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
390390 lib/std/Io.zig
391391 lib/std/Io/Reader.zig
392392 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
402393 lib/std/Progress.zig
403394 lib/std/Random.zig
404395 lib/std/Target.zig
......@@ -550,6 +541,14 @@ set(ZIG_STAGE2_SOURCES
550541 src/clang_options.zig
551542 src/clang_options_data.zig
552543 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
553552 src/codegen/c.zig
554553 src/codegen/c/Type.zig
555554 src/codegen/llvm.zig
doc/langref/build.zig+4-2
......@@ -4,8 +4,10 @@ pub fn build(b: *std.Build) void {
44 const optimize = b.standardOptimizeOption(.{});
55 const exe = b.addExecutable(.{
66 .name = "example",
7 .root_source_file = b.path("example.zig"),
8 .optimize = optimize,
7 .root_module = b.createModule(.{
8 .root_source_file = b.path("example.zig"),
9 .optimize = optimize,
10 }),
911 });
1012 b.default_step.dependOn(&exe.step);
1113}
doc/langref/build_c.zig+8-4
......@@ -4,15 +4,19 @@ pub fn build(b: *std.Build) void {
44 const lib = b.addLibrary(.{
55 .linkage = .dynamic,
66 .name = "mathtest",
7 .root_source_file = b.path("mathtest.zig"),
7 .root_module = b.createModule(.{
8 .root_source_file = b.path("mathtest.zig"),
9 }),
810 .version = .{ .major = 1, .minor = 0, .patch = 0 },
911 });
1012 const exe = b.addExecutable(.{
1113 .name = "test",
14 .root_module = b.createModule(.{
15 .link_libc = true,
16 }),
1217 });
13 exe.addCSourceFile(.{ .file = b.path("test.c"), .flags = &.{"-std=c99"} });
14 exe.linkLibrary(lib);
15 exe.linkSystemLibrary("c");
18 exe.root_module.addCSourceFile(.{ .file = b.path("test.c"), .flags = &.{"-std=c99"} });
19 exe.root_module.linkLibrary(lib);
1620
1721 b.default_step.dependOn(&exe.step);
1822
doc/langref/build_object.zig+8-4
......@@ -3,15 +3,19 @@ const std = @import("std");
33pub fn build(b: *std.Build) void {
44 const obj = b.addObject(.{
55 .name = "base64",
6 .root_source_file = b.path("base64.zig"),
6 .root_module = b.createModule(.{
7 .root_source_file = b.path("base64.zig"),
8 }),
79 });
810
911 const exe = b.addExecutable(.{
1012 .name = "test",
13 .root_module = b.createModule(.{
14 .link_libc = true,
15 }),
1116 });
12 exe.addCSourceFile(.{ .file = b.path("test.c"), .flags = &.{"-std=c99"} });
13 exe.addObject(obj);
14 exe.linkSystemLibrary("c");
17 exe.root_module.addCSourceFile(.{ .file = b.path("test.c"), .flags = &.{"-std=c99"} });
18 exe.root_module.addObject(obj);
1519 b.installArtifact(exe);
1620}
1721
lib/compiler/build_runner.zig+7-3
......@@ -696,8 +696,11 @@ fn runStepNames(
696696 .failures, .none => true,
697697 else => false,
698698 };
699 if (failure_count == 0 and failures_only) {
700 return run.cleanExit();
699 if (failure_count == 0) {
700 std.Progress.setStatus(.success);
701 if (failures_only) return run.cleanExit();
702 } else {
703 std.Progress.setStatus(.failure);
701704 }
702705
703706 const ttyconf = run.ttyconf;
......@@ -708,7 +711,7 @@ fn runStepNames(
708711
709712 const total_count = success_count + failure_count + pending_count + skipped_count;
710713 ttyconf.setColor(w, .cyan) catch {};
711 w.writeAll("Build Summary:") catch {};
714 w.writeAll("\nBuild Summary:") catch {};
712715 ttyconf.setColor(w, .reset) catch {};
713716 w.print(" {d}/{d} steps succeeded", .{ success_count, total_count }) catch {};
714717 if (skipped_count > 0) w.print("; {d} skipped", .{skipped_count}) catch {};
......@@ -1149,6 +1152,7 @@ fn workerMakeOneStep(
11491152 } else |err| switch (err) {
11501153 error.MakeFailed => {
11511154 @atomicStore(Step.State, &s.state, .failure, .seq_cst);
1155 std.Progress.setStatus(.failure_working);
11521156 break :handle_result;
11531157 },
11541158 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;
1313var stdin_buffer: [1024]u8 = undefined;
1414var stdout_buffer: [1024]u8 = undefined;
1515
16var input_buffer: [1024]u8 = undefined;
17var output_buffer: [1024]u8 = undefined;
18
1619pub fn main() !void {
1720 var arena_instance = std.heap.ArenaAllocator.init(std.heap.page_allocator);
1821 defer arena_instance.deinit();
......@@ -145,13 +148,16 @@ fn cmdObjCopy(gpa: Allocator, arena: Allocator, args: []const []const u8) !void
145148 const input = opt_input orelse fatal("expected input parameter", .{});
146149 const output = opt_output orelse fatal("expected output parameter", .{});
147150
148 var in_file = fs.cwd().openFile(input, .{}) catch |err|
149 fatal("unable to open '{s}': {s}", .{ input, @errorName(err) });
150 defer in_file.close();
151 const input_file = fs.cwd().openFile(input, .{}) catch |err| fatal("failed to open {s}: {t}", .{ input, err });
152 defer input_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) {
153 error.InvalidElfMagic => fatal("not an ELF file: '{s}'", .{input}),
154 else => fatal("unable to read '{s}': {s}", .{ input, @errorName(err) }),
156 var in: File.Reader = .initSize(input_file, &input_buffer, stat.size);
157
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}),
155161 };
156162
157163 const in_ofmt = .elf;
......@@ -168,16 +174,12 @@ fn cmdObjCopy(gpa: Allocator, arena: Allocator, args: []const []const u8) !void
168174 }
169175 };
170176
171 const mode = mode: {
172 if (out_fmt != .elf or only_keep_debug)
173 break :mode fs.File.default_mode;
174 if (in_file.stat()) |stat|
175 break :mode stat.mode
176 else |_|
177 break :mode fs.File.default_mode;
178 };
179 var out_file = try fs.cwd().createFile(output, .{ .mode = mode });
180 defer out_file.close();
177 const mode = if (out_fmt != .elf or only_keep_debug) fs.File.default_mode else stat.mode;
178
179 var output_file = try fs.cwd().createFile(output, .{ .mode = mode });
180 defer output_file.close();
181
182 var out = output_file.writer(&output_buffer);
181183
182184 switch (out_fmt) {
183185 .hex, .raw => {
......@@ -192,7 +194,7 @@ fn cmdObjCopy(gpa: Allocator, arena: Allocator, args: []const []const u8) !void
192194 if (set_section_flags != null)
193195 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, .{
196198 .ofmt = out_fmt,
197199 .only_section = only_section,
198200 .pad_to = pad_to,
......@@ -208,22 +210,13 @@ fn cmdObjCopy(gpa: Allocator, arena: Allocator, args: []const []const u8) !void
208210 if (pad_to) |_|
209211 fatal("zig objcopy: ELF to ELF copying does not support --pad-to", .{});
210212
211 try stripElf(arena, in_file, out_file, elf_hdr, .{
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();
213 fatal("unimplemented", .{});
223214 },
224215 else => fatal("unsupported output object format: {s}", .{@tagName(out_fmt)}),
225216 }
226217
218 try out.end();
219
227220 if (listen) {
228221 var stdin_reader = fs.File.stdin().reader(&stdin_buffer);
229222 var stdout_writer = fs.File.stdout().writer(&stdout_buffer);
......@@ -304,12 +297,12 @@ const SetSectionFlags = struct {
304297
305298fn emitElf(
306299 arena: Allocator,
307 in_file: File,
308 out_file: File,
300 in: *File.Reader,
301 out: *File.Writer,
309302 elf_hdr: elf.Header,
310303 options: EmitRawElfOptions,
311304) !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);
313306 defer binary_elf_output.deinit();
314307
315308 if (options.ofmt == .elf) {
......@@ -328,8 +321,8 @@ fn emitElf(
328321 continue;
329322 }
330323
331 try writeBinaryElfSection(in_file, out_file, section);
332 try padFile(out_file, options.pad_to);
324 try writeBinaryElfSection(in, out, section);
325 try padFile(out, options.pad_to);
333326 return;
334327 }
335328 },
......@@ -342,10 +335,10 @@ fn emitElf(
342335 switch (options.ofmt) {
343336 .raw => {
344337 for (binary_elf_output.sections.items) |section| {
345 try out_file.seekTo(section.binaryOffset);
346 try writeBinaryElfSection(in_file, out_file, section);
338 try out.seekTo(section.binaryOffset);
339 try writeBinaryElfSection(in, out, section);
347340 }
348 try padFile(out_file, options.pad_to);
341 try padFile(out, options.pad_to);
349342 },
350343 .hex => {
351344 if (binary_elf_output.segments.items.len == 0) return;
......@@ -353,15 +346,15 @@ fn emitElf(
353346 return error.InvalidHexfileAddressRange;
354347 }
355348
356 var hex_writer = HexWriter{ .out_file = out_file };
349 var hex_writer = HexWriter{ .out = out };
357350 for (binary_elf_output.segments.items) |segment| {
358 try hex_writer.writeSegment(segment, in_file);
351 try hex_writer.writeSegment(segment, in);
359352 }
360353 if (options.pad_to) |_| {
361354 // Padding to a size in hex files isn't applicable
362355 return error.InvalidArgument;
363356 }
364 try hex_writer.writeEOF();
357 try hex_writer.writeEof();
365358 },
366359 else => unreachable,
367360 }
......@@ -399,7 +392,7 @@ const BinaryElfOutput = struct {
399392 self.segments.deinit(self.allocator);
400393 }
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 {
403396 var self: Self = .{
404397 .segments = .{},
405398 .sections = .{},
......@@ -412,7 +405,7 @@ const BinaryElfOutput = struct {
412405 self.shstrtab = blk: {
413406 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
417410 var section_counter: usize = 0;
418411 while (section_counter < elf_hdr.shstrndx) : (section_counter += 1) {
......@@ -421,18 +414,13 @@ const BinaryElfOutput = struct {
421414
422415 const shstrtab_shdr = (try section_headers.next()).?;
423416
424 const buffer = try allocator.alloc(u8, @intCast(shstrtab_shdr.sh_size));
425 errdefer allocator.free(buffer);
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;
417 try in.seekTo(shstrtab_shdr.sh_offset);
418 break :blk try in.interface.readAlloc(allocator, shstrtab_shdr.sh_size);
431419 };
432420
433421 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);
436424 while (try section_headers.next()) |section| {
437425 if (sectionValidForOutput(section)) {
438426 const newSection = try allocator.create(BinaryElfSection);
......@@ -451,7 +439,7 @@ const BinaryElfOutput = struct {
451439 }
452440 }
453441
454 var program_headers = elf_hdr.program_header_iterator(&elf_file);
442 var program_headers = elf_hdr.iterateProgramHeaders(in);
455443 while (try program_headers.next()) |phdr| {
456444 if (phdr.p_type == elf.PT_LOAD) {
457445 const newSegment = try allocator.create(BinaryElfSegment);
......@@ -539,19 +527,17 @@ const BinaryElfOutput = struct {
539527 }
540528};
541529
542fn writeBinaryElfSection(elf_file: File, out_file: File, section: *BinaryElfSection) !void {
543 try out_file.writeFileAll(elf_file, .{
544 .in_offset = section.elfOffset,
545 .in_len = section.fileSize,
546 });
530fn writeBinaryElfSection(in: *File.Reader, out: *File.Writer, section: *BinaryElfSection) !void {
531 try in.seekTo(section.elfOffset);
532 _ = try out.interface.sendFileAll(in, .limited(section.fileSize));
547533}
548534
549535const HexWriter = struct {
550536 prev_addr: ?u32 = null,
551 out_file: File,
537 out: *File.Writer,
552538
553539 /// Max data bytes per line of output
554 const MAX_PAYLOAD_LEN: u8 = 16;
540 const max_payload_len: u8 = 16;
555541
556542 fn addressParts(address: u16) [2]u8 {
557543 const msb: u8 = @truncate(address >> 8);
......@@ -627,13 +613,13 @@ const HexWriter = struct {
627613 return (sum ^ 0xFF) +% 1;
628614 }
629615
630 fn write(self: Record, file: File) File.WriteError!void {
616 fn write(self: Record, out: *File.Writer) !void {
631617 const linesep = "\r\n";
632618 // 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;
634620 var outbuf: [BUFSIZE]u8 = undefined;
635621 const payload_bytes = self.getPayloadBytes();
636 assert(payload_bytes.len <= MAX_PAYLOAD_LEN);
622 assert(payload_bytes.len <= max_payload_len);
637623
638624 const line = try std.fmt.bufPrint(&outbuf, ":{0X:0>2}{1X:0>4}{2X:0>2}{3X}{4X:0>2}" ++ linesep, .{
639625 @as(u8, @intCast(payload_bytes.len)),
......@@ -642,38 +628,37 @@ const HexWriter = struct {
642628 payload_bytes,
643629 self.checksum(),
644630 });
645 try file.writeAll(line);
631 try out.interface.writeAll(line);
646632 }
647633 };
648634
649 pub fn writeSegment(self: *HexWriter, segment: *const BinaryElfSegment, elf_file: File) !void {
650 var buf: [MAX_PAYLOAD_LEN]u8 = undefined;
635 pub fn writeSegment(self: *HexWriter, segment: *const BinaryElfSegment, in: *File.Reader) !void {
636 var buf: [max_payload_len]u8 = undefined;
651637 var bytes_read: usize = 0;
652638 while (bytes_read < segment.fileSize) {
653639 const row_address: u32 = @intCast(segment.physicalAddress + bytes_read);
654640
655641 const remaining = segment.fileSize - bytes_read;
656 const to_read: usize = @intCast(@min(remaining, MAX_PAYLOAD_LEN));
657 const did_read = try elf_file.preadAll(buf[0..to_read], segment.elfOffset + bytes_read);
658 if (did_read < to_read) return error.UnexpectedEOF;
642 const dest = buf[0..@min(remaining, max_payload_len)];
643 try in.seekTo(segment.elfOffset + bytes_read);
644 try in.interface.readSliceAll(dest);
645 try self.writeDataRow(row_address, dest);
659646
660 try self.writeDataRow(row_address, buf[0..did_read]);
661
662 bytes_read += did_read;
647 bytes_read += dest.len;
663648 }
664649 }
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 {
667652 const record = Record.Data(address, data);
668653 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);
670655 }
671 try record.write(self.out_file);
656 try record.write(self.out);
672657 self.prev_addr = @intCast(record.address + data.len);
673658 }
674659
675 fn writeEOF(self: HexWriter) File.WriteError!void {
676 try Record.EOF().write(self.out_file);
660 fn writeEof(self: HexWriter) !void {
661 try Record.EOF().write(self.out);
677662 }
678663};
679664
......@@ -686,9 +671,9 @@ fn containsValidAddressRange(segments: []*BinaryElfSegment) bool {
686671 return true;
687672}
688673
689fn padFile(f: File, opt_size: ?u64) !void {
674fn padFile(out: *File.Writer, opt_size: ?u64) !void {
690675 const size = opt_size orelse return;
691 try f.setEndPos(size);
676 try out.file.setEndPos(size);
692677}
693678
694679test "HexWriter.Record.Address has correct payload and checksum" {
......@@ -732,836 +717,6 @@ test "containsValidAddressRange" {
732717 try std.testing.expect(containsValidAddressRange(&buf));
733718}
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
1565720const SectionFlags = packed struct {
1566721 alloc: bool = false,
1567722 contents: bool = false,
lib/compiler/std-docs.zig+25-20
......@@ -60,7 +60,9 @@ pub fn main() !void {
6060 const should_open_browser = force_open_browser orelse (listen_port == 0);
6161
6262 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 });
6466 const port = http_server.listen_address.in.getPort();
6567 const url_with_newline = try std.fmt.allocPrint(arena, "http://127.0.0.1:{d}/\n", .{port});
6668 std.fs.File.stdout().writeAll(url_with_newline) catch {};
......@@ -189,7 +191,11 @@ fn serveSourcesTar(request: *std.http.Server.Request, context: *Context) !void {
189191 var walker = try std_dir.walk(gpa);
190192 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 };
193199 archiver.prefix = "std";
194200
195201 while (try walker.next()) |entry| {
......@@ -204,7 +210,13 @@ fn serveSourcesTar(request: *std.http.Server.Request, context: *Context) !void {
204210 }
205211 var file = try entry.dir.openFile(entry.basename, .{});
206212 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);
208220 }
209221
210222 {
......@@ -217,6 +229,7 @@ fn serveSourcesTar(request: *std.http.Server.Request, context: *Context) !void {
217229
218230 // intentionally omitting the pointless trailer
219231 //try archiver.finish();
232 try response_writer.new_interface.flush();
220233 try response.end();
221234}
222235
......@@ -307,21 +320,17 @@ fn buildWasmBinary(
307320 try sendMessage(child.stdin.?, .update);
308321 try sendMessage(child.stdin.?, .exit);
309322
310 const Header = std.zig.Server.Message.Header;
311323 var result: ?Cache.Path = null;
312324 var result_error_bundle = std.zig.ErrorBundle.empty;
313325
314 const stdout = poller.fifo(.stdout);
326 const stdout = poller.reader(.stdout);
315327
316328 poll: while (true) {
317 while (stdout.readableLength() < @sizeOf(Header)) {
318 if (!(try poller.poll())) break :poll;
319 }
320 const header = stdout.reader().readStruct(Header) catch unreachable;
321 while (stdout.readableLength() < header.bytes_len) {
322 if (!(try poller.poll())) break :poll;
323 }
324 const body = stdout.readableSliceOfLen(header.bytes_len);
329 const Header = std.zig.Server.Message.Header;
330 while (stdout.buffered().len < @sizeOf(Header)) if (!try poller.poll()) break :poll;
331 const header = stdout.takeStruct(Header, .little) catch unreachable;
332 while (stdout.buffered().len < header.bytes_len) if (!try poller.poll()) break :poll;
333 const body = stdout.take(header.bytes_len) catch unreachable;
325334
326335 switch (header.tag) {
327336 .zig_version => {
......@@ -361,15 +370,11 @@ fn buildWasmBinary(
361370 },
362371 else => {}, // ignore other messages
363372 }
364
365 stdout.discard(body.len);
366373 }
367374
368 const stderr = poller.fifo(.stderr);
369 if (stderr.readableLength() > 0) {
370 const owned_stderr = try stderr.toOwnedSlice();
371 defer gpa.free(owned_stderr);
372 std.debug.print("{s}", .{owned_stderr});
375 const stderr = poller.reader(.stderr);
376 if (stderr.bufferedLen() > 0) {
377 std.debug.print("{s}", .{stderr.buffered()});
373378 }
374379
375380 // Send EOF to stdin.
lib/compiler/test_runner.zig+19-20
......@@ -16,6 +16,7 @@ var stdin_buffer: [4096]u8 = undefined;
1616var stdout_buffer: [4096]u8 = undefined;
1717
1818const crippled = switch (builtin.zig_backend) {
19 .stage2_aarch64,
1920 .stage2_powerpc,
2021 .stage2_riscv64,
2122 => true,
......@@ -287,13 +288,14 @@ pub fn log(
287288/// work-in-progress backends can handle it.
288289pub fn mainSimple() anyerror!void {
289290 @disableInstrumentation();
290 // is the backend capable of printing to stderr?
291 const enable_print = switch (builtin.zig_backend) {
291 // is the backend capable of calling `std.fs.File.writeAll`?
292 const enable_write = switch (builtin.zig_backend) {
293 .stage2_aarch64, .stage2_riscv64 => true,
292294 else => false,
293295 };
294 // is the backend capable of using std.fmt.format to print a summary at the end?
295 const print_summary = switch (builtin.zig_backend) {
296 .stage2_riscv64 => true,
296 // is the backend capable of calling `std.Io.Writer.print`?
297 const enable_print = switch (builtin.zig_backend) {
298 .stage2_aarch64, .stage2_riscv64 => true,
297299 else => false,
298300 };
299301
......@@ -302,34 +304,31 @@ pub fn mainSimple() anyerror!void {
302304 var failed: u64 = 0;
303305
304306 // we don't want to bring in File and Writer if the backend doesn't support it
305 const stderr = if (comptime enable_print) std.fs.File.stderr() else {};
307 const stdout = if (enable_write) std.fs.File.stdout() else {};
306308
307309 for (builtin.test_functions) |test_fn| {
310 if (enable_write) {
311 stdout.writeAll(test_fn.name) catch {};
312 stdout.writeAll("... ") catch {};
313 }
308314 if (test_fn.func()) |_| {
309 if (enable_print) {
310 stderr.writeAll(test_fn.name) catch {};
311 stderr.writeAll("... ") catch {};
312 stderr.writeAll("PASS\n") catch {};
313 }
315 if (enable_write) stdout.writeAll("PASS\n") catch {};
314316 } else |err| {
315 if (enable_print) {
316 stderr.writeAll(test_fn.name) catch {};
317 stderr.writeAll("... ") catch {};
318 }
319317 if (err != error.SkipZigTest) {
320 if (enable_print) stderr.writeAll("FAIL\n") catch {};
318 if (enable_write) stdout.writeAll("FAIL\n") catch {};
321319 failed += 1;
322 if (!enable_print) return err;
320 if (!enable_write) return err;
323321 continue;
324322 }
325 if (enable_print) stderr.writeAll("SKIP\n") catch {};
323 if (enable_write) stdout.writeAll("SKIP\n") catch {};
326324 skipped += 1;
327325 continue;
328326 }
329327 passed += 1;
330328 }
331 if (enable_print and print_summary) {
332 stderr.deprecatedWriter().print("{} passed, {} skipped, {} failed\n", .{ passed, skipped, failed }) catch {};
329 if (enable_print) {
330 var stdout_writer = stdout.writer(&.{});
331 stdout_writer.interface.print("{} passed, {} skipped, {} failed\n", .{ passed, skipped, failed }) catch {};
333332 }
334333 if (failed != 0) std.process.exit(1);
335334}
lib/compiler_rt.zig+2-2
......@@ -249,12 +249,12 @@ comptime {
249249 _ = @import("compiler_rt/hexagon.zig");
250250
251251 if (@import("builtin").object_format != .c) {
252 _ = @import("compiler_rt/atomics.zig");
252 if (builtin.zig_backend != .stage2_aarch64) _ = @import("compiler_rt/atomics.zig");
253253 _ = @import("compiler_rt/stack_probe.zig");
254254
255255 // macOS has these functions inside libSystem.
256256 if (builtin.cpu.arch.isAARCH64() and !builtin.os.tag.isDarwin()) {
257 _ = @import("compiler_rt/aarch64_outline_atomics.zig");
257 if (builtin.zig_backend != .stage2_aarch64) _ = @import("compiler_rt/aarch64_outline_atomics.zig");
258258 }
259259
260260 _ = @import("compiler_rt/memcpy.zig");
lib/compiler_rt/addo.zig+1-3
......@@ -1,6 +1,4 @@
11const std = @import("std");
2const builtin = @import("builtin");
3const is_test = builtin.is_test;
42const common = @import("./common.zig");
53pub const panic = @import("common.zig").panic;
64
......@@ -16,7 +14,7 @@ comptime {
1614// - addoXi4_generic as default
1715
1816inline fn addoXi4_generic(comptime ST: type, a: ST, b: ST, overflow: *c_int) ST {
19 @setRuntimeSafety(builtin.is_test);
17 @setRuntimeSafety(common.test_safety);
2018 overflow.* = 0;
2119 const sum: ST = a +% b;
2220 // Hackers Delight: section Overflow Detection, subsection Signed Add/Subtract
lib/compiler_rt/addoti4_test.zig+3
......@@ -1,4 +1,5 @@
11const addv = @import("addo.zig");
2const builtin = @import("builtin");
23const std = @import("std");
34const testing = std.testing;
45const math = std.math;
......@@ -23,6 +24,8 @@ fn simple_addoti4(a: i128, b: i128, overflow: *c_int) i128 {
2324}
2425
2526test "addoti4" {
27 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
28
2629 const min: i128 = math.minInt(i128);
2730 const max: i128 = math.maxInt(i128);
2831 var i: i128 = 1;
lib/compiler_rt/clear_cache.zig+4-10
......@@ -97,8 +97,7 @@ fn clear_cache(start: usize, end: usize) callconv(.c) void {
9797 .nbytes = end - start,
9898 .whichcache = 3, // ICACHE | DCACHE
9999 };
100 asm volatile (
101 \\ syscall
100 asm volatile ("syscall"
102101 :
103102 : [_] "{$2}" (165), // nr = SYS_sysarch
104103 [_] "{$4}" (0), // op = MIPS_CACHEFLUSH
......@@ -116,11 +115,8 @@ fn clear_cache(start: usize, end: usize) callconv(.c) void {
116115 } else if (arm64 and !apple) {
117116 // Get Cache Type Info.
118117 // TODO memoize this?
119 var ctr_el0: u64 = 0;
120 asm volatile (
121 \\mrs %[x], ctr_el0
122 \\
123 : [x] "=r" (ctr_el0),
118 const ctr_el0 = asm volatile ("mrs %[ctr_el0], ctr_el0"
119 : [ctr_el0] "=r" (-> u64),
124120 );
125121 // The DC and IC instructions must use 64-bit registers so we don't use
126122 // uintptr_t in case this runs in an IPL32 environment.
......@@ -187,9 +183,7 @@ fn clear_cache(start: usize, end: usize) callconv(.c) void {
187183 exportIt();
188184 } else if (os == .linux and loongarch) {
189185 // See: https://github.com/llvm/llvm-project/blob/cf54cae26b65fc3201eff7200ffb9b0c9e8f9a13/compiler-rt/lib/builtins/clear_cache.c#L94-L95
190 asm volatile (
191 \\ ibar 0
192 );
186 asm volatile ("ibar 0");
193187 exportIt();
194188 }
195189
lib/compiler_rt/cmp.zig-1
......@@ -1,6 +1,5 @@
11const std = @import("std");
22const builtin = @import("builtin");
3const is_test = builtin.is_test;
43const common = @import("common.zig");
54
65pub const panic = common.panic;
lib/compiler_rt/common.zig+6-1
......@@ -102,9 +102,14 @@ pub const gnu_f16_abi = switch (builtin.cpu.arch) {
102102
103103pub const want_sparc_abi = builtin.cpu.arch.isSPARC();
104104
105pub const test_safety = switch (builtin.zig_backend) {
106 .stage2_aarch64 => false,
107 else => builtin.is_test,
108};
109
105110// Avoid dragging in the runtime safety mechanisms into this .o file, unless
106111// we're trying to test compiler-rt.
107pub const panic = if (builtin.is_test) std.debug.FullPanic(std.debug.defaultPanic) else std.debug.no_panic;
112pub const panic = if (test_safety) std.debug.FullPanic(std.debug.defaultPanic) else std.debug.no_panic;
108113
109114/// This seems to mostly correspond to `clang::TargetInfo::HasFloat16`.
110115pub fn F16T(comptime OtherType: type) type {
lib/compiler_rt/comparedf2_test.zig-1
......@@ -4,7 +4,6 @@
44
55const std = @import("std");
66const builtin = @import("builtin");
7const is_test = builtin.is_test;
87
98const __eqdf2 = @import("./cmpdf2.zig").__eqdf2;
109const __ledf2 = @import("./cmpdf2.zig").__ledf2;
lib/compiler_rt/comparesf2_test.zig-1
......@@ -4,7 +4,6 @@
44
55const std = @import("std");
66const builtin = @import("builtin");
7const is_test = builtin.is_test;
87
98const __eqsf2 = @import("./cmpsf2.zig").__eqsf2;
109const __lesf2 = @import("./cmpsf2.zig").__lesf2;
lib/compiler_rt/count0bits.zig-1
......@@ -1,6 +1,5 @@
11const std = @import("std");
22const builtin = @import("builtin");
3const is_test = builtin.is_test;
43const common = @import("common.zig");
54
65pub const panic = common.panic;
lib/compiler_rt/divdf3.zig-1
......@@ -5,7 +5,6 @@
55const std = @import("std");
66const builtin = @import("builtin");
77const arch = builtin.cpu.arch;
8const is_test = builtin.is_test;
98const common = @import("common.zig");
109
1110const normalize = common.normalize;
lib/compiler_rt/divmodei4.zig+2-2
......@@ -34,7 +34,7 @@ fn divmod(q: ?[]u32, r: ?[]u32, u: []u32, v: []u32) !void {
3434}
3535
3636pub fn __divei4(q_p: [*]u8, u_p: [*]u8, v_p: [*]u8, bits: usize) callconv(.c) void {
37 @setRuntimeSafety(builtin.is_test);
37 @setRuntimeSafety(common.test_safety);
3838 const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits));
3939 const q: []u32 = @ptrCast(@alignCast(q_p[0..byte_size]));
4040 const u: []u32 = @ptrCast(@alignCast(u_p[0..byte_size]));
......@@ -43,7 +43,7 @@ pub fn __divei4(q_p: [*]u8, u_p: [*]u8, v_p: [*]u8, bits: usize) callconv(.c) vo
4343}
4444
4545pub fn __modei4(r_p: [*]u8, u_p: [*]u8, v_p: [*]u8, bits: usize) callconv(.c) void {
46 @setRuntimeSafety(builtin.is_test);
46 @setRuntimeSafety(common.test_safety);
4747 const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits));
4848 const r: []u32 = @ptrCast(@alignCast(r_p[0..byte_size]));
4949 const u: []u32 = @ptrCast(@alignCast(u_p[0..byte_size]));
lib/compiler_rt/fixint_test.zig-1
......@@ -1,4 +1,3 @@
1const is_test = @import("builtin").is_test;
21const std = @import("std");
32const math = std.math;
43const testing = std.testing;
lib/compiler_rt/int.zig-1
......@@ -6,7 +6,6 @@ const testing = std.testing;
66const maxInt = std.math.maxInt;
77const minInt = std.math.minInt;
88const arch = builtin.cpu.arch;
9const is_test = builtin.is_test;
109const common = @import("common.zig");
1110const udivmod = @import("udivmod.zig").udivmod;
1211const __divti3 = @import("divti3.zig").__divti3;
lib/compiler_rt/memcpy.zig+3-1
......@@ -11,7 +11,7 @@ comptime {
1111 .visibility = common.visibility,
1212 };
1313
14 if (builtin.mode == .ReleaseSmall)
14 if (builtin.mode == .ReleaseSmall or builtin.zig_backend == .stage2_aarch64)
1515 @export(&memcpySmall, export_options)
1616 else
1717 @export(&memcpyFast, export_options);
......@@ -195,6 +195,8 @@ inline fn copyRange4(
195195}
196196
197197test "memcpy" {
198 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
199
198200 const S = struct {
199201 fn testFunc(comptime copy_func: anytype) !void {
200202 const max_len = 1024;
lib/compiler_rt/memmove.zig+9-7
......@@ -14,7 +14,7 @@ comptime {
1414 .visibility = common.visibility,
1515 };
1616
17 if (builtin.mode == .ReleaseSmall)
17 if (builtin.mode == .ReleaseSmall or builtin.zig_backend == .stage2_aarch64)
1818 @export(&memmoveSmall, export_options)
1919 else
2020 @export(&memmoveFast, export_options);
......@@ -39,7 +39,7 @@ fn memmoveSmall(opt_dest: ?[*]u8, opt_src: ?[*]const u8, len: usize) callconv(.c
3939}
4040
4141fn memmoveFast(dest: ?[*]u8, src: ?[*]u8, len: usize) callconv(.c) ?[*]u8 {
42 @setRuntimeSafety(builtin.is_test);
42 @setRuntimeSafety(common.test_safety);
4343 const small_limit = @max(2 * @sizeOf(Element), @sizeOf(Element));
4444
4545 if (copySmallLength(small_limit, dest.?, src.?, len)) return dest;
......@@ -79,7 +79,7 @@ inline fn copyLessThan16(
7979 src: [*]const u8,
8080 len: usize,
8181) void {
82 @setRuntimeSafety(builtin.is_test);
82 @setRuntimeSafety(common.test_safety);
8383 if (len < 4) {
8484 if (len == 0) return;
8585 const b = len / 2;
......@@ -100,7 +100,7 @@ inline fn copy16ToSmallLimit(
100100 src: [*]const u8,
101101 len: usize,
102102) bool {
103 @setRuntimeSafety(builtin.is_test);
103 @setRuntimeSafety(common.test_safety);
104104 inline for (2..(std.math.log2(small_limit) + 1) / 2 + 1) |p| {
105105 const limit = 1 << (2 * p);
106106 if (len < limit) {
......@@ -119,7 +119,7 @@ inline fn copyRange4(
119119 src: [*]const u8,
120120 len: usize,
121121) void {
122 @setRuntimeSafety(builtin.is_test);
122 @setRuntimeSafety(common.test_safety);
123123 comptime assert(std.math.isPowerOfTwo(copy_len));
124124 assert(len >= copy_len);
125125 assert(len < 4 * copy_len);
......@@ -147,7 +147,7 @@ inline fn copyForwards(
147147 src: [*]const u8,
148148 len: usize,
149149) void {
150 @setRuntimeSafety(builtin.is_test);
150 @setRuntimeSafety(common.test_safety);
151151 assert(len >= 2 * @sizeOf(Element));
152152
153153 const head = src[0..@sizeOf(Element)].*;
......@@ -181,7 +181,7 @@ inline fn copyBlocks(
181181 src: anytype,
182182 max_bytes: usize,
183183) void {
184 @setRuntimeSafety(builtin.is_test);
184 @setRuntimeSafety(common.test_safety);
185185
186186 const T = @typeInfo(@TypeOf(dest)).pointer.child;
187187 comptime assert(T == @typeInfo(@TypeOf(src)).pointer.child);
......@@ -217,6 +217,8 @@ inline fn copyBackwards(
217217}
218218
219219test memmoveFast {
220 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
221
220222 const max_len = 1024;
221223 var buffer: [max_len + @alignOf(Element) - 1]u8 = undefined;
222224 for (&buffer, 0..) |*b, i| {
lib/compiler_rt/mulf3.zig+2-2
......@@ -6,7 +6,7 @@ const common = @import("./common.zig");
66/// Ported from:
77/// https://github.com/llvm/llvm-project/blob/2ffb1b0413efa9a24eb3c49e710e36f92e2cb50b/compiler-rt/lib/builtins/fp_mul_impl.inc
88pub inline fn mulf3(comptime T: type, a: T, b: T) T {
9 @setRuntimeSafety(builtin.is_test);
9 @setRuntimeSafety(common.test_safety);
1010 const typeWidth = @typeInfo(T).float.bits;
1111 const significandBits = math.floatMantissaBits(T);
1212 const fractionalBits = math.floatFractionalBits(T);
......@@ -163,7 +163,7 @@ pub inline fn mulf3(comptime T: type, a: T, b: T) T {
163163///
164164/// This is analogous to an shr version of `@shlWithOverflow`
165165fn wideShrWithTruncation(comptime Z: type, hi: *Z, lo: *Z, count: u32) bool {
166 @setRuntimeSafety(builtin.is_test);
166 @setRuntimeSafety(common.test_safety);
167167 const typeWidth = @typeInfo(Z).int.bits;
168168 var inexact = false;
169169 if (count < typeWidth) {
lib/compiler_rt/rem_pio2_large.zig+1-1
......@@ -251,7 +251,7 @@ const PIo2 = [_]f64{
251251/// compiler will convert from decimal to binary accurately enough
252252/// to produce the hexadecimal values shown.
253253///
254pub fn rem_pio2_large(x: []f64, y: []f64, e0: i32, nx: i32, prec: usize) i32 {
254pub fn rem_pio2_large(x: []const f64, y: []f64, e0: i32, nx: i32, prec: usize) i32 {
255255 var jz: i32 = undefined;
256256 var jx: i32 = undefined;
257257 var jv: i32 = undefined;
lib/compiler_rt/stack_probe.zig-1
......@@ -4,7 +4,6 @@ const common = @import("common.zig");
44const os_tag = builtin.os.tag;
55const arch = builtin.cpu.arch;
66const abi = builtin.abi;
7const is_test = builtin.is_test;
87
98pub const panic = common.panic;
109
lib/compiler_rt/suboti4_test.zig+3
......@@ -1,4 +1,5 @@
11const subo = @import("subo.zig");
2const builtin = @import("builtin");
23const std = @import("std");
34const testing = std.testing;
45const math = std.math;
......@@ -27,6 +28,8 @@ pub fn simple_suboti4(a: i128, b: i128, overflow: *c_int) i128 {
2728}
2829
2930test "suboti3" {
31 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
32
3033 const min: i128 = math.minInt(i128);
3134 const max: i128 = math.maxInt(i128);
3235 var i: i128 = 1;
lib/compiler_rt/udivmod.zig+5-5
......@@ -1,8 +1,8 @@
11const std = @import("std");
22const builtin = @import("builtin");
3const is_test = builtin.is_test;
43const Log2Int = std.math.Log2Int;
5const HalveInt = @import("common.zig").HalveInt;
4const common = @import("common.zig");
5const HalveInt = common.HalveInt;
66
77const lo = switch (builtin.cpu.arch.endian()) {
88 .big => 1,
......@@ -14,7 +14,7 @@ const hi = 1 - lo;
1414// Returns U / v_ and sets r = U % v_.
1515fn divwide_generic(comptime T: type, _u1: T, _u0: T, v_: T, r: *T) T {
1616 const HalfT = HalveInt(T, false).HalfT;
17 @setRuntimeSafety(is_test);
17 @setRuntimeSafety(common.test_safety);
1818 var v = v_;
1919
2020 const b = @as(T, 1) << (@bitSizeOf(T) / 2);
......@@ -70,7 +70,7 @@ fn divwide_generic(comptime T: type, _u1: T, _u0: T, v_: T, r: *T) T {
7070}
7171
7272fn divwide(comptime T: type, _u1: T, _u0: T, v: T, r: *T) T {
73 @setRuntimeSafety(is_test);
73 @setRuntimeSafety(common.test_safety);
7474 if (T == u64 and builtin.target.cpu.arch == .x86_64 and builtin.target.os.tag != .windows) {
7575 var rem: T = undefined;
7676 const quo = asm (
......@@ -90,7 +90,7 @@ fn divwide(comptime T: type, _u1: T, _u0: T, v: T, r: *T) T {
9090
9191// Returns a_ / b_ and sets maybe_rem = a_ % b.
9292pub fn udivmod(comptime T: type, a_: T, b_: T, maybe_rem: ?*T) T {
93 @setRuntimeSafety(is_test);
93 @setRuntimeSafety(common.test_safety);
9494 const HalfT = HalveInt(T, false).HalfT;
9595 const SignedT = std.meta.Int(.signed, @bitSizeOf(T));
9696
lib/compiler_rt/udivmodei4.zig+3-2
......@@ -113,7 +113,7 @@ pub fn divmod(q: ?[]u32, r: ?[]u32, u: []const u32, v: []const u32) !void {
113113}
114114
115115pub fn __udivei4(q_p: [*]u8, u_p: [*]const u8, v_p: [*]const u8, bits: usize) callconv(.c) void {
116 @setRuntimeSafety(builtin.is_test);
116 @setRuntimeSafety(common.test_safety);
117117 const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits));
118118 const q: []u32 = @ptrCast(@alignCast(q_p[0..byte_size]));
119119 const u: []const u32 = @ptrCast(@alignCast(u_p[0..byte_size]));
......@@ -122,7 +122,7 @@ pub fn __udivei4(q_p: [*]u8, u_p: [*]const u8, v_p: [*]const u8, bits: usize) ca
122122}
123123
124124pub fn __umodei4(r_p: [*]u8, u_p: [*]const u8, v_p: [*]const u8, bits: usize) callconv(.c) void {
125 @setRuntimeSafety(builtin.is_test);
125 @setRuntimeSafety(common.test_safety);
126126 const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits));
127127 const r: []u32 = @ptrCast(@alignCast(r_p[0..byte_size]));
128128 const u: []const u32 = @ptrCast(@alignCast(u_p[0..byte_size]));
......@@ -131,6 +131,7 @@ pub fn __umodei4(r_p: [*]u8, u_p: [*]const u8, v_p: [*]const u8, bits: usize) ca
131131}
132132
133133test "__udivei4/__umodei4" {
134 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
134135 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
135136 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
136137
lib/docs/wasm/main.zig+3-3
......@@ -772,10 +772,10 @@ export fn decl_type_html(decl_index: Decl.Index) String {
772772const Oom = error{OutOfMemory};
773773
774774fn unpackInner(tar_bytes: []u8) !void {
775 var fbs = std.io.fixedBufferStream(tar_bytes);
775 var reader: std.Io.Reader = .fixed(tar_bytes);
776776 var file_name_buffer: [1024]u8 = undefined;
777777 var link_name_buffer: [1024]u8 = undefined;
778 var it = std.tar.iterator(fbs.reader(), .{
778 var it: std.tar.Iterator = .init(&reader, .{
779779 .file_name_buffer = &file_name_buffer,
780780 .link_name_buffer = &link_name_buffer,
781781 });
......@@ -796,7 +796,7 @@ fn unpackInner(tar_bytes: []u8) !void {
796796 {
797797 gop.value_ptr.* = file;
798798 }
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)];
800800 assert(file == try Walk.add_file(file_name, file_bytes));
801801 }
802802 } else {
lib/init/build.zig-1
......@@ -1,4 +1,3 @@
1//! Use `zig init --strip` next time to generate a project without comments.
21const std = @import("std");
32
43// Although this function looks imperative, it does not perform the build
lib/std/Build.zig+151-76
......@@ -408,104 +408,179 @@ fn createChildOnly(
408408 return child;
409409}
410410
411fn userInputOptionsFromArgs(allocator: Allocator, args: anytype) UserInputOptionsMap {
412 var user_input_options = UserInputOptionsMap.init(allocator);
411fn userInputOptionsFromArgs(arena: Allocator, args: anytype) UserInputOptionsMap {
412 var map = UserInputOptionsMap.init(arena);
413413 inline for (@typeInfo(@TypeOf(args)).@"struct".fields) |field| {
414 const v = @field(args, field.name);
415 const T = @TypeOf(v);
416 switch (T) {
417 Target.Query => {
418 user_input_options.put(field.name, .{
419 .name = field.name,
420 .value = .{ .scalar = v.zigTriple(allocator) catch @panic("OOM") },
421 .used = false,
422 }) catch @panic("OOM");
423 user_input_options.put("cpu", .{
424 .name = "cpu",
425 .value = .{ .scalar = v.serializeCpuAlloc(allocator) catch @panic("OOM") },
426 .used = false,
427 }) catch @panic("OOM");
428 },
429 ResolvedTarget => {
430 user_input_options.put(field.name, .{
431 .name = field.name,
432 .value = .{ .scalar = v.query.zigTriple(allocator) catch @panic("OOM") },
433 .used = false,
434 }) catch @panic("OOM");
435 user_input_options.put("cpu", .{
436 .name = "cpu",
437 .value = .{ .scalar = v.query.serializeCpuAlloc(allocator) catch @panic("OOM") },
438 .used = false,
439 }) catch @panic("OOM");
440 },
441 LazyPath => {
442 user_input_options.put(field.name, .{
414 if (field.type == @Type(.null)) continue;
415 addUserInputOptionFromArg(arena, &map, field, field.type, @field(args, field.name));
416 }
417 return map;
418}
419
420fn addUserInputOptionFromArg(
421 arena: Allocator,
422 map: *UserInputOptionsMap,
423 field: std.builtin.Type.StructField,
424 comptime T: type,
425 /// If null, the value won't be added, but `T` will still be type-checked.
426 maybe_value: ?T,
427) void {
428 switch (T) {
429 Target.Query => return if (maybe_value) |v| {
430 map.put(field.name, .{
431 .name = field.name,
432 .value = .{ .scalar = v.zigTriple(arena) catch @panic("OOM") },
433 .used = false,
434 }) catch @panic("OOM");
435 map.put("cpu", .{
436 .name = "cpu",
437 .value = .{ .scalar = v.serializeCpuAlloc(arena) catch @panic("OOM") },
438 .used = false,
439 }) catch @panic("OOM");
440 },
441 ResolvedTarget => return if (maybe_value) |v| {
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, .{
443495 .name = field.name,
444 .value = .{ .lazy_path = v.dupeInner(allocator) },
496 .value = .{ .scalar = if (v) "true" else "false" },
445497 .used = false,
446498 }) catch @panic("OOM");
447499 },
448 []const LazyPath => {
449 var list = ArrayList(LazyPath).initCapacity(allocator, v.len) catch @panic("OOM");
450 for (v) |lp| list.appendAssumeCapacity(lp.dupeInner(allocator));
451 user_input_options.put(field.name, .{
500 .@"enum", .enum_literal => return if (maybe_value) |v| {
501 map.put(field.name, .{
452502 .name = field.name,
453 .value = .{ .lazy_path_list = list },
503 .value = .{ .scalar = @tagName(v) },
454504 .used = false,
455505 }) catch @panic("OOM");
456506 },
457 []const u8 => {
458 user_input_options.put(field.name, .{
507 .comptime_int, .int => return if (maybe_value) |v| {
508 map.put(field.name, .{
459509 .name = field.name,
460 .value = .{ .scalar = v },
510 .value = .{ .scalar = std.fmt.allocPrint(arena, "{d}", .{v}) catch @panic("OOM") },
461511 .used = false,
462512 }) catch @panic("OOM");
463513 },
464 []const []const u8 => {
465 var list = ArrayList([]const u8).initCapacity(allocator, v.len) catch @panic("OOM");
466 list.appendSliceAssumeCapacity(v);
467
468 user_input_options.put(field.name, .{
514 .comptime_float, .float => return if (maybe_value) |v| {
515 map.put(field.name, .{
469516 .name = field.name,
470 .value = .{ .list = list },
517 .value = .{ .scalar = std.fmt.allocPrint(arena, "{x}", .{v}) catch @panic("OOM") },
471518 .used = false,
472519 }) catch @panic("OOM");
473520 },
474 else => switch (@typeInfo(T)) {
475 .bool => {
476 user_input_options.put(field.name, .{
477 .name = field.name,
478 .value = .{ .scalar = if (v) "true" else "false" },
479 .used = false,
480 }) catch @panic("OOM");
481 },
482 .@"enum", .enum_literal => {
483 user_input_options.put(field.name, .{
484 .name = field.name,
485 .value = .{ .scalar = @tagName(v) },
486 .used = false,
487 }) catch @panic("OOM");
521 .pointer => |ptr_info| switch (ptr_info.size) {
522 .one => switch (@typeInfo(ptr_info.child)) {
523 .array => |array_info| {
524 comptime var slice_info = ptr_info;
525 slice_info.size = .slice;
526 slice_info.is_const = true;
527 slice_info.child = array_info.child;
528 slice_info.sentinel_ptr = null;
529 addUserInputOptionFromArg(
530 arena,
531 map,
532 field,
533 @Type(.{ .pointer = slice_info }),
534 maybe_value orelse null,
535 );
536 return;
537 },
538 else => {},
488539 },
489 .comptime_int, .int => {
490 user_input_options.put(field.name, .{
491 .name = field.name,
492 .value = .{ .scalar = std.fmt.allocPrint(allocator, "{d}", .{v}) catch @panic("OOM") },
493 .used = false,
494 }) catch @panic("OOM");
540 .slice => switch (@typeInfo(ptr_info.child)) {
541 .@"enum" => return if (maybe_value) |v| {
542 var list = ArrayList([]const u8).initCapacity(arena, v.len) catch @panic("OOM");
543 for (v) |tag| list.appendAssumeCapacity(@tagName(tag));
544 map.put(field.name, .{
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 },
495563 },
496 .comptime_float, .float => {
497 user_input_options.put(field.name, .{
498 .name = field.name,
499 .value = .{ .scalar = std.fmt.allocPrint(allocator, "{e}", .{v}) catch @panic("OOM") },
500 .used = false,
501 }) catch @panic("OOM");
564 else => {},
565 },
566 .null => unreachable,
567 .optional => |info| switch (@typeInfo(info.child)) {
568 .optional => {},
569 else => {
570 addUserInputOptionFromArg(
571 arena,
572 map,
573 field,
574 info.child,
575 maybe_value orelse null,
576 );
577 return;
502578 },
503 else => @compileError("option '" ++ field.name ++ "' has unsupported type: " ++ @typeName(T)),
504579 },
505 }
580 else => {},
581 },
506582 }
507
508 return user_input_options;
583 @compileError("option '" ++ field.name ++ "' has unsupported type: " ++ @typeName(field.type));
509584}
510585
511586const OrderedUserValue = union(enum) {
lib/std/Build/Fuzz/WebServer.zig+17-22
......@@ -273,21 +273,17 @@ fn buildWasmBinary(
273273 try sendMessage(child.stdin.?, .update);
274274 try sendMessage(child.stdin.?, .exit);
275275
276 const Header = std.zig.Server.Message.Header;
277276 var result: ?Path = null;
278277 var result_error_bundle = std.zig.ErrorBundle.empty;
279278
280 const stdout = poller.fifo(.stdout);
279 const stdout = poller.reader(.stdout);
281280
282281 poll: while (true) {
283 while (stdout.readableLength() < @sizeOf(Header)) {
284 if (!(try poller.poll())) break :poll;
285 }
286 const header = stdout.reader().readStruct(Header) catch unreachable;
287 while (stdout.readableLength() < header.bytes_len) {
288 if (!(try poller.poll())) break :poll;
289 }
290 const body = stdout.readableSliceOfLen(header.bytes_len);
282 const Header = std.zig.Server.Message.Header;
283 while (stdout.buffered().len < @sizeOf(Header)) if (!try poller.poll()) break :poll;
284 const header = stdout.takeStruct(Header, .little) catch unreachable;
285 while (stdout.buffered().len < header.bytes_len) if (!try poller.poll()) break :poll;
286 const body = stdout.take(header.bytes_len) catch unreachable;
291287
292288 switch (header.tag) {
293289 .zig_version => {
......@@ -325,15 +321,11 @@ fn buildWasmBinary(
325321 },
326322 else => {}, // ignore other messages
327323 }
328
329 stdout.discard(body.len);
330324 }
331325
332 const stderr = poller.fifo(.stderr);
333 if (stderr.readableLength() > 0) {
334 const owned_stderr = try stderr.toOwnedSlice();
335 defer gpa.free(owned_stderr);
336 std.debug.print("{s}", .{owned_stderr});
326 const stderr_contents = try poller.toOwnedSlice(.stderr);
327 if (stderr_contents.len > 0) {
328 std.debug.print("{s}", .{stderr_contents});
337329 }
338330
339331 // Send EOF to stdin.
......@@ -522,7 +514,9 @@ fn serveSourcesTar(ws: *WebServer, request: *std.http.Server.Request) !void {
522514
523515 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
527521 for (deduped_paths) |joined_path| {
528522 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 {
530524 continue;
531525 };
532526 defer file.close();
533
527 const stat = try file.stat();
528 var file_reader: std.fs.File.Reader = .initSize(file, &read_buffer, stat.size);
534529 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);
536531 }
537532
538 // intentionally omitting the pointless trailer
539 //try archiver.finish();
533 // intentionally not calling `archiver.finishPedantically`
534 try adapter.new_interface.flush();
540535 try response.end();
541536}
542537
lib/std/Build/Step.zig+25-34
......@@ -286,7 +286,7 @@ pub fn cast(step: *Step, comptime T: type) ?*T {
286286}
287287
288288/// 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 {
290290 const debug_info = std.debug.getSelfDebugInfo() catch |err| {
291291 w.print("Unable to dump stack trace: Unable to open debug info: {s}\n", .{
292292 @errorName(err),
......@@ -359,7 +359,7 @@ pub fn addError(step: *Step, comptime fmt: []const u8, args: anytype) error{OutO
359359
360360pub const ZigProcess = struct {
361361 child: std.process.Child,
362 poller: std.io.Poller(StreamEnum),
362 poller: std.Io.Poller(StreamEnum),
363363 progress_ipc_fd: if (std.Progress.have_ipc) ?std.posix.fd_t else void,
364364
365365 pub const StreamEnum = enum { stdout, stderr };
......@@ -428,7 +428,7 @@ pub fn evalZigProcess(
428428 const zp = try gpa.create(ZigProcess);
429429 zp.* = .{
430430 .child = child,
431 .poller = std.io.poll(gpa, ZigProcess.StreamEnum, .{
431 .poller = std.Io.poll(gpa, ZigProcess.StreamEnum, .{
432432 .stdout = child.stdout.?,
433433 .stderr = child.stderr.?,
434434 }),
......@@ -508,20 +508,16 @@ fn zigProcessUpdate(s: *Step, zp: *ZigProcess, watch: bool) !?Path {
508508 try sendMessage(zp.child.stdin.?, .update);
509509 if (!watch) try sendMessage(zp.child.stdin.?, .exit);
510510
511 const Header = std.zig.Server.Message.Header;
512511 var result: ?Path = null;
513512
514 const stdout = zp.poller.fifo(.stdout);
513 const stdout = zp.poller.reader(.stdout);
515514
516515 poll: while (true) {
517 while (stdout.readableLength() < @sizeOf(Header)) {
518 if (!(try zp.poller.poll())) break :poll;
519 }
520 const header = stdout.reader().readStruct(Header) catch unreachable;
521 while (stdout.readableLength() < header.bytes_len) {
522 if (!(try zp.poller.poll())) break :poll;
523 }
524 const body = stdout.readableSliceOfLen(header.bytes_len);
516 const Header = std.zig.Server.Message.Header;
517 while (stdout.buffered().len < @sizeOf(Header)) if (!try zp.poller.poll()) break :poll;
518 const header = stdout.takeStruct(Header, .little) catch unreachable;
519 while (stdout.buffered().len < header.bytes_len) if (!try zp.poller.poll()) break :poll;
520 const body = stdout.take(header.bytes_len) catch unreachable;
525521
526522 switch (header.tag) {
527523 .zig_version => {
......@@ -547,11 +543,8 @@ fn zigProcessUpdate(s: *Step, zp: *ZigProcess, watch: bool) !?Path {
547543 .string_bytes = try arena.dupe(u8, string_bytes),
548544 .extra = extra_array,
549545 };
550 if (watch) {
551 // This message indicates the end of the update.
552 stdout.discard(body.len);
553 break;
554 }
546 // This message indicates the end of the update.
547 if (watch) break :poll;
555548 },
556549 .emit_digest => {
557550 const EmitDigest = std.zig.Server.Message.EmitDigest;
......@@ -611,15 +604,13 @@ fn zigProcessUpdate(s: *Step, zp: *ZigProcess, watch: bool) !?Path {
611604 },
612605 else => {}, // ignore other messages
613606 }
614
615 stdout.discard(body.len);
616607 }
617608
618609 s.result_duration_ns = timer.read();
619610
620 const stderr = zp.poller.fifo(.stderr);
621 if (stderr.readableLength() > 0) {
622 try s.result_error_msgs.append(arena, try stderr.toOwnedSlice());
611 const stderr_contents = try zp.poller.toOwnedSlice(.stderr);
612 if (stderr_contents.len > 0) {
613 try s.result_error_msgs.append(arena, try arena.dupe(u8, stderr_contents));
623614 }
624615
625616 return result;
......@@ -736,7 +727,7 @@ pub fn allocPrintCmd2(
736727 argv: []const []const u8,
737728) Allocator.Error![]u8 {
738729 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 {
740731 for (string) |c| {
741732 if (switch (c) {
742733 else => true,
......@@ -770,9 +761,9 @@ pub fn allocPrintCmd2(
770761 }
771762 };
772763
773 var buf: std.ArrayListUnmanaged(u8) = .empty;
774 const writer = buf.writer(arena);
775 if (opt_cwd) |cwd| try writer.print("cd {s} && ", .{cwd});
764 var aw: std.Io.Writer.Allocating = .init(arena);
765 const writer = &aw.writer;
766 if (opt_cwd) |cwd| writer.print("cd {s} && ", .{cwd}) catch return error.OutOfMemory;
776767 if (opt_env) |env| {
777768 const process_env_map = std.process.getEnvMap(arena) catch std.process.EnvMap.init(arena);
778769 var it = env.iterator();
......@@ -782,17 +773,17 @@ pub fn allocPrintCmd2(
782773 if (process_env_map.get(key)) |process_value| {
783774 if (std.mem.eql(u8, value, process_value)) continue;
784775 }
785 try writer.print("{s}=", .{key});
786 try shell.escape(writer, value, false);
787 try writer.writeByte(' ');
776 writer.print("{s}=", .{key}) catch return error.OutOfMemory;
777 shell.escape(writer, value, false) catch return error.OutOfMemory;
778 writer.writeByte(' ') catch return error.OutOfMemory;
788779 }
789780 }
790 try shell.escape(writer, argv[0], true);
781 shell.escape(writer, argv[0], true) catch return error.OutOfMemory;
791782 for (argv[1..]) |arg| {
792 try writer.writeByte(' ');
793 try shell.escape(writer, arg, false);
783 writer.writeByte(' ') catch return error.OutOfMemory;
784 shell.escape(writer, arg, false) catch return error.OutOfMemory;
794785 }
795 return buf.toOwnedSlice(arena);
786 return aw.toOwnedSlice();
796787}
797788
798789/// 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 {
681681 return compile.isDll();
682682}
683683
684/// Deprecated; use `compile.root_module.link_libc = true` instead.
685/// To be removed after 0.15.0 is tagged.
684686pub fn linkLibC(compile: *Compile) void {
685687 compile.root_module.link_libc = true;
686688}
687689
690/// Deprecated; use `compile.root_module.link_libcpp = true` instead.
691/// To be removed after 0.15.0 is tagged.
688692pub fn linkLibCpp(compile: *Compile) void {
689693 compile.root_module.link_libcpp = true;
690694}
......@@ -802,10 +806,14 @@ fn runPkgConfig(compile: *Compile, lib_name: []const u8) !PkgConfigResult {
802806 };
803807}
804808
809/// Deprecated; use `compile.root_module.linkSystemLibrary(name, .{})` instead.
810/// To be removed after 0.15.0 is tagged.
805811pub fn linkSystemLibrary(compile: *Compile, name: []const u8) void {
806812 return compile.root_module.linkSystemLibrary(name, .{});
807813}
808814
815/// Deprecated; use `compile.root_module.linkSystemLibrary(name, options)` instead.
816/// To be removed after 0.15.0 is tagged.
809817pub fn linkSystemLibrary2(
810818 compile: *Compile,
811819 name: []const u8,
......@@ -814,22 +822,26 @@ pub fn linkSystemLibrary2(
814822 return compile.root_module.linkSystemLibrary(name, options);
815823}
816824
825/// Deprecated; use `c.root_module.linkFramework(name, .{})` instead.
826/// To be removed after 0.15.0 is tagged.
817827pub fn linkFramework(c: *Compile, name: []const u8) void {
818828 c.root_module.linkFramework(name, .{});
819829}
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.
822833pub fn addCSourceFiles(compile: *Compile, options: Module.AddCSourceFilesOptions) void {
823834 compile.root_module.addCSourceFiles(options);
824835}
825836
837/// Deprecated; use `compile.root_module.addCSourceFile(source)` instead.
838/// To be removed after 0.15.0 is tagged.
826839pub fn addCSourceFile(compile: *Compile, source: Module.CSourceFile) void {
827840 compile.root_module.addCSourceFile(source);
828841}
829842
830/// Resource files must have the extension `.rc`.
831/// Can be called regardless of target. The .rc file will be ignored
832/// if the target object format does not support embedded resources.
843/// Deprecated; use `compile.root_module.addWin32ResourceFile(source)` instead.
844/// To be removed after 0.15.0 is tagged.
833845pub fn addWin32ResourceFile(compile: *Compile, source: Module.RcSourceFile) void {
834846 compile.root_module.addWin32ResourceFile(source);
835847}
......@@ -915,54 +927,80 @@ pub fn getEmittedLlvmBc(compile: *Compile) LazyPath {
915927 return compile.getEmittedFileGeneric(&compile.generated_llvm_bc);
916928}
917929
930/// Deprecated; use `compile.root_module.addAssemblyFile(source)` instead.
931/// To be removed after 0.15.0 is tagged.
918932pub fn addAssemblyFile(compile: *Compile, source: LazyPath) void {
919933 compile.root_module.addAssemblyFile(source);
920934}
921935
936/// Deprecated; use `compile.root_module.addObjectFile(source)` instead.
937/// To be removed after 0.15.0 is tagged.
922938pub fn addObjectFile(compile: *Compile, source: LazyPath) void {
923939 compile.root_module.addObjectFile(source);
924940}
925941
942/// Deprecated; use `compile.root_module.addObject(object)` instead.
943/// To be removed after 0.15.0 is tagged.
926944pub fn addObject(compile: *Compile, object: *Compile) void {
927945 compile.root_module.addObject(object);
928946}
929947
948/// Deprecated; use `compile.root_module.linkLibrary(library)` instead.
949/// To be removed after 0.15.0 is tagged.
930950pub fn linkLibrary(compile: *Compile, library: *Compile) void {
931951 compile.root_module.linkLibrary(library);
932952}
933953
954/// Deprecated; use `compile.root_module.addAfterIncludePath(lazy_path)` instead.
955/// To be removed after 0.15.0 is tagged.
934956pub fn addAfterIncludePath(compile: *Compile, lazy_path: LazyPath) void {
935957 compile.root_module.addAfterIncludePath(lazy_path);
936958}
937959
960/// Deprecated; use `compile.root_module.addSystemIncludePath(lazy_path)` instead.
961/// To be removed after 0.15.0 is tagged.
938962pub fn addSystemIncludePath(compile: *Compile, lazy_path: LazyPath) void {
939963 compile.root_module.addSystemIncludePath(lazy_path);
940964}
941965
966/// Deprecated; use `compile.root_module.addIncludePath(lazy_path)` instead.
967/// To be removed after 0.15.0 is tagged.
942968pub fn addIncludePath(compile: *Compile, lazy_path: LazyPath) void {
943969 compile.root_module.addIncludePath(lazy_path);
944970}
945971
972/// Deprecated; use `compile.root_module.addConfigHeader(config_header)` instead.
973/// To be removed after 0.15.0 is tagged.
946974pub fn addConfigHeader(compile: *Compile, config_header: *Step.ConfigHeader) void {
947975 compile.root_module.addConfigHeader(config_header);
948976}
949977
978/// Deprecated; use `compile.root_module.addEmbedPath(lazy_path)` instead.
979/// To be removed after 0.15.0 is tagged.
950980pub fn addEmbedPath(compile: *Compile, lazy_path: LazyPath) void {
951981 compile.root_module.addEmbedPath(lazy_path);
952982}
953983
984/// Deprecated; use `compile.root_module.addLibraryPath(directory_path)` instead.
985/// To be removed after 0.15.0 is tagged.
954986pub fn addLibraryPath(compile: *Compile, directory_path: LazyPath) void {
955987 compile.root_module.addLibraryPath(directory_path);
956988}
957989
990/// Deprecated; use `compile.root_module.addRPath(directory_path)` instead.
991/// To be removed after 0.15.0 is tagged.
958992pub fn addRPath(compile: *Compile, directory_path: LazyPath) void {
959993 compile.root_module.addRPath(directory_path);
960994}
961995
996/// Deprecated; use `compile.root_module.addSystemFrameworkPath(directory_path)` instead.
997/// To be removed after 0.15.0 is tagged.
962998pub fn addSystemFrameworkPath(compile: *Compile, directory_path: LazyPath) void {
963999 compile.root_module.addSystemFrameworkPath(directory_path);
9641000}
9651001
1002/// Deprecated; use `compile.root_module.addFrameworkPath(directory_path)` instead.
1003/// To be removed after 0.15.0 is tagged.
9661004pub fn addFrameworkPath(compile: *Compile, directory_path: LazyPath) void {
9671005 compile.root_module.addFrameworkPath(directory_path);
9681006}
lib/std/Build/Step/Run.zig+58-39
......@@ -73,9 +73,12 @@ skip_foreign_checks: bool,
7373/// external executor (such as qemu) but not fail if the executor is unavailable.
7474failing_to_execute_foreign_is_an_error: bool,
7575
76/// Deprecated in favor of `stdio_limit`.
77max_stdio_size: usize,
78
7679/// If stderr or stdout exceeds this amount, the child process is killed and
7780/// the step fails.
78max_stdio_size: usize,
81stdio_limit: std.Io.Limit,
7982
8083captured_stdout: ?*Output,
8184captured_stderr: ?*Output,
......@@ -169,7 +172,7 @@ pub const Output = struct {
169172pub fn create(owner: *std.Build, name: []const u8) *Run {
170173 const run = owner.allocator.create(Run) catch @panic("OOM");
171174 run.* = .{
172 .step = Step.init(.{
175 .step = .init(.{
173176 .id = base_id,
174177 .name = name,
175178 .owner = owner,
......@@ -186,6 +189,7 @@ pub fn create(owner: *std.Build, name: []const u8) *Run {
186189 .skip_foreign_checks = false,
187190 .failing_to_execute_foreign_is_an_error = true,
188191 .max_stdio_size = 10 * 1024 * 1024,
192 .stdio_limit = .unlimited,
189193 .captured_stdout = null,
190194 .captured_stderr = null,
191195 .dep_output_file = null,
......@@ -1011,7 +1015,7 @@ fn populateGeneratedPaths(
10111015 }
10121016}
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 {
10151019 if (term) |t| switch (t) {
10161020 .Exited => |code| try w.print("exited with code {d}", .{code}),
10171021 .Signal => |sig| try w.print("terminated with signal {d}", .{sig}),
......@@ -1500,7 +1504,7 @@ fn evalZigTest(
15001504 const gpa = run.step.owner.allocator;
15011505 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 }, .{
15041508 .stdout = child.stdout.?,
15051509 .stderr = child.stderr.?,
15061510 });
......@@ -1524,11 +1528,6 @@ fn evalZigTest(
15241528 break :failed false;
15251529 };
15261530
1527 const Header = std.zig.Server.Message.Header;
1528
1529 const stdout = poller.fifo(.stdout);
1530 const stderr = poller.fifo(.stderr);
1531
15321531 var fail_count: u32 = 0;
15331532 var skip_count: u32 = 0;
15341533 var leak_count: u32 = 0;
......@@ -1541,16 +1540,14 @@ fn evalZigTest(
15411540 var sub_prog_node: ?std.Progress.Node = null;
15421541 defer if (sub_prog_node) |n| n.end();
15431542
1543 const stdout = poller.reader(.stdout);
1544 const stderr = poller.reader(.stderr);
15441545 const any_write_failed = first_write_failed or poll: while (true) {
1545 while (stdout.readableLength() < @sizeOf(Header)) {
1546 if (!(try poller.poll())) break :poll false;
1547 }
1548 const header = stdout.reader().readStruct(Header) catch unreachable;
1549 while (stdout.readableLength() < header.bytes_len) {
1550 if (!(try poller.poll())) break :poll false;
1551 }
1552 const body = stdout.readableSliceOfLen(header.bytes_len);
1553
1546 const Header = std.zig.Server.Message.Header;
1547 while (stdout.buffered().len < @sizeOf(Header)) if (!try poller.poll()) break :poll false;
1548 const header = stdout.takeStruct(Header, .little) catch unreachable;
1549 while (stdout.buffered().len < header.bytes_len) if (!try poller.poll()) break :poll false;
1550 const body = stdout.take(header.bytes_len) catch unreachable;
15541551 switch (header.tag) {
15551552 .zig_version => {
15561553 if (!std.mem.eql(u8, builtin.zig_version_string, body)) {
......@@ -1607,9 +1604,9 @@ fn evalZigTest(
16071604
16081605 if (tr_hdr.flags.fail or tr_hdr.flags.leak or tr_hdr.flags.log_err_count > 0) {
16091606 const name = std.mem.sliceTo(md.string_bytes[md.names[tr_hdr.index]..], 0);
1610 const orig_msg = stderr.readableSlice(0);
1611 defer stderr.discard(orig_msg.len);
1612 const msg = std.mem.trim(u8, orig_msg, "\n");
1607 const stderr_contents = stderr.buffered();
1608 stderr.toss(stderr_contents.len);
1609 const msg = std.mem.trim(u8, stderr_contents, "\n");
16131610 const label = if (tr_hdr.flags.fail)
16141611 "failed"
16151612 else if (tr_hdr.flags.leak)
......@@ -1660,8 +1657,6 @@ fn evalZigTest(
16601657 },
16611658 else => {}, // ignore other messages
16621659 }
1663
1664 stdout.discard(body.len);
16651660 };
16661661
16671662 if (any_write_failed) {
......@@ -1670,9 +1665,9 @@ fn evalZigTest(
16701665 while (try poller.poll()) {}
16711666 }
16721667
1673 if (stderr.readableLength() > 0) {
1674 const msg = std.mem.trim(u8, try stderr.toOwnedSlice(), "\n");
1675 if (msg.len > 0) run.step.result_stderr = msg;
1668 const stderr_contents = std.mem.trim(u8, stderr.buffered(), "\n");
1669 if (stderr_contents.len > 0) {
1670 run.step.result_stderr = try arena.dupe(u8, stderr_contents);
16761671 }
16771672
16781673 // Send EOF to stdin.
......@@ -1769,13 +1764,22 @@ fn evalGeneric(run: *Run, child: *std.process.Child) !StdIoResult {
17691764 child.stdin = null;
17701765 },
17711766 .lazy_path => |lazy_path| {
1772 const path = lazy_path.getPath2(b, &run.step);
1773 const file = b.build_root.handle.openFile(path, .{}) catch |err| {
1767 const path = lazy_path.getPath3(b, &run.step);
1768 const file = path.root_dir.handle.openFile(path.subPathOrDot(), .{}) catch |err| {
17741769 return run.step.fail("unable to open stdin file: {s}", .{@errorName(err)});
17751770 };
17761771 defer file.close();
1777 child.stdin.?.writeFileAll(file, .{}) catch |err| {
1778 return run.step.fail("unable to write file to stdin: {s}", .{@errorName(err)});
1772 // TODO https://github.com/ziglang/zig/issues/23955
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 }),
17791783 };
17801784 child.stdin.?.close();
17811785 child.stdin = null;
......@@ -1786,28 +1790,43 @@ fn evalGeneric(run: *Run, child: *std.process.Child) !StdIoResult {
17861790 var stdout_bytes: ?[]const u8 = null;
17871791 var stderr_bytes: ?[]const u8 = null;
17881792
1793 run.stdio_limit = run.stdio_limit.min(.limited(run.max_stdio_size));
17891794 if (child.stdout) |stdout| {
17901795 if (child.stderr) |stderr| {
1791 var poller = std.io.poll(arena, enum { stdout, stderr }, .{
1796 var poller = std.Io.poll(arena, enum { stdout, stderr }, .{
17921797 .stdout = stdout,
17931798 .stderr = stderr,
17941799 });
17951800 defer poller.deinit();
17961801
17971802 while (try poller.poll()) {
1798 if (poller.fifo(.stdout).count > run.max_stdio_size)
1799 return error.StdoutStreamTooLong;
1800 if (poller.fifo(.stderr).count > run.max_stdio_size)
1801 return error.StderrStreamTooLong;
1803 if (run.stdio_limit.toInt()) |limit| {
1804 if (poller.reader(.stderr).buffered().len > limit)
1805 return error.StdoutStreamTooLong;
1806 if (poller.reader(.stderr).buffered().len > limit)
1807 return error.StderrStreamTooLong;
1808 }
18021809 }
18031810
1804 stdout_bytes = try poller.fifo(.stdout).toOwnedSlice();
1805 stderr_bytes = try poller.fifo(.stderr).toOwnedSlice();
1811 stdout_bytes = try poller.toOwnedSlice(.stdout);
1812 stderr_bytes = try poller.toOwnedSlice(.stderr);
18061813 } 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 };
18081821 }
18091822 } 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 };
18111830 }
18121831
18131832 if (stderr_bytes) |bytes| if (bytes.len > 0) {
lib/std/Io.zig+264-215
......@@ -1,16 +1,11 @@
1const std = @import("std.zig");
21const builtin = @import("builtin");
3const root = @import("root");
4const c = std.c;
52const is_windows = builtin.os.tag == .windows;
3
4const std = @import("std.zig");
65const windows = std.os.windows;
76const posix = std.posix;
87const math = std.math;
98const assert = std.debug.assert;
10const fs = std.fs;
11const mem = std.mem;
12const meta = std.meta;
13const File = std.fs.File;
149const Allocator = std.mem.Allocator;
1510const Alignment = std.mem.Alignment;
1611
......@@ -314,11 +309,11 @@ pub fn GenericReader(
314309 }
315310
316311 /// 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 {
318313 return .{
319314 .derp_reader = self.*,
320315 .new_interface = .{
321 .buffer = &.{},
316 .buffer = buffer,
322317 .vtable = &.{ .stream = Adapter.stream },
323318 .seek = 0,
324319 .end = 0,
......@@ -334,10 +329,12 @@ pub fn GenericReader(
334329 fn stream(r: *Reader, w: *Writer, limit: Limit) Reader.StreamError!usize {
335330 const a: *@This() = @alignCast(@fieldParentPtr("new_interface", r));
336331 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| {
338333 a.err = err;
339334 return error.ReadFailed;
340335 };
336 w.advance(n);
337 return n;
341338 }
342339 };
343340 };
......@@ -419,9 +416,14 @@ pub fn GenericWriter(
419416 new_interface: Writer,
420417 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 {
423420 _ = splat;
424421 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 });
425427 return a.derp_writer.write(data[0]) catch |err| {
426428 a.err = err;
427429 return error.WriteFailed;
......@@ -435,54 +437,46 @@ pub fn GenericWriter(
435437pub const AnyReader = @import("Io/DeprecatedReader.zig");
436438/// Deprecated in favor of `Writer`.
437439pub const AnyWriter = @import("Io/DeprecatedWriter.zig");
438
440/// Deprecated in favor of `File.Reader` and `File.Writer`.
439441pub const SeekableStream = @import("Io/seekable_stream.zig").SeekableStream;
440
442/// Deprecated in favor of `Writer`.
441443pub const BufferedWriter = @import("Io/buffered_writer.zig").BufferedWriter;
444/// Deprecated in favor of `Writer`.
442445pub const bufferedWriter = @import("Io/buffered_writer.zig").bufferedWriter;
443
446/// Deprecated in favor of `Reader`.
444447pub const BufferedReader = @import("Io/buffered_reader.zig").BufferedReader;
448/// Deprecated in favor of `Reader`.
445449pub const bufferedReader = @import("Io/buffered_reader.zig").bufferedReader;
450/// Deprecated in favor of `Reader`.
446451pub const bufferedReaderSize = @import("Io/buffered_reader.zig").bufferedReaderSize;
447
452/// Deprecated in favor of `Reader`.
448453pub const FixedBufferStream = @import("Io/fixed_buffer_stream.zig").FixedBufferStream;
454/// Deprecated in favor of `Reader`.
449455pub const fixedBufferStream = @import("Io/fixed_buffer_stream.zig").fixedBufferStream;
450
451pub const CWriter = @import("Io/c_writer.zig").CWriter;
452pub const cWriter = @import("Io/c_writer.zig").cWriter;
453
456/// Deprecated in favor of `Reader.Limited`.
454457pub const LimitedReader = @import("Io/limited_reader.zig").LimitedReader;
458/// Deprecated in favor of `Reader.Limited`.
455459pub const limitedReader = @import("Io/limited_reader.zig").limitedReader;
456
460/// Deprecated with no replacement; inefficient pattern
457461pub const CountingWriter = @import("Io/counting_writer.zig").CountingWriter;
462/// Deprecated with no replacement; inefficient pattern
458463pub const countingWriter = @import("Io/counting_writer.zig").countingWriter;
464/// Deprecated with no replacement; inefficient pattern
459465pub const CountingReader = @import("Io/counting_reader.zig").CountingReader;
466/// Deprecated with no replacement; inefficient pattern
460467pub 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
465469pub const BitReader = @import("Io/bit_reader.zig").BitReader;
466470pub const bitReader = @import("Io/bit_reader.zig").bitReader;
467471
468472pub const BitWriter = @import("Io/bit_writer.zig").BitWriter;
469473pub 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
481475pub const tty = @import("Io/tty.zig");
482476
483/// A Writer that doesn't write to anything.
477/// Deprecated in favor of `Writer.Discarding`.
484478pub const null_writer: NullWriter = .{ .context = {} };
485
479/// Deprecated in favor of `Writer.Discarding`.
486480pub const NullWriter = GenericWriter(void, error{}, dummyWrite);
487481fn dummyWrite(context: void, data: []const u8) error{}!usize {
488482 _ = context;
......@@ -494,54 +488,51 @@ test null_writer {
494488}
495489
496490pub fn poll(
497 allocator: Allocator,
491 gpa: Allocator,
498492 comptime StreamEnum: type,
499493 files: PollFiles(StreamEnum),
500494) Poller(StreamEnum) {
501495 const enum_fields = @typeInfo(StreamEnum).@"enum".fields;
502 var result: Poller(StreamEnum) = undefined;
503
504 if (is_windows) result.windows = .{
505 .first_read_done = false,
506 .overlapped = [1]windows.OVERLAPPED{
507 mem.zeroes(windows.OVERLAPPED),
508 } ** enum_fields.len,
509 .small_bufs = undefined,
510 .active = .{
511 .count = 0,
512 .handles_buf = undefined,
513 .stream_map = undefined,
514 },
496 var result: Poller(StreamEnum) = .{
497 .gpa = gpa,
498 .readers = @splat(.failing),
499 .poll_fds = undefined,
500 .windows = if (is_windows) .{
501 .first_read_done = false,
502 .overlapped = [1]windows.OVERLAPPED{
503 std.mem.zeroes(windows.OVERLAPPED),
504 } ** enum_fields.len,
505 .small_bufs = undefined,
506 .active = .{
507 .count = 0,
508 .handles_buf = undefined,
509 .stream_map = undefined,
510 },
511 } else {},
515512 };
516513
517 inline for (0..enum_fields.len) |i| {
518 result.fifos[i] = .{
519 .allocator = allocator,
520 .buf = &.{},
521 .head = 0,
522 .count = 0,
523 };
514 inline for (enum_fields, 0..) |field, i| {
524515 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;
526517 } else {
527518 result.poll_fds[i] = .{
528 .fd = @field(files, enum_fields[i].name).handle,
519 .fd = @field(files, field.name).handle,
529520 .events = posix.POLL.IN,
530521 .revents = undefined,
531522 };
532523 }
533524 }
525
534526 return result;
535527}
536528
537pub const PollFifo = std.fifo.LinearFifo(u8, .Dynamic);
538
539529pub fn Poller(comptime StreamEnum: type) type {
540530 return struct {
541531 const enum_fields = @typeInfo(StreamEnum).@"enum".fields;
542532 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,
545536 poll_fds: [enum_fields.len]PollFd,
546537 windows: if (is_windows) struct {
547538 first_read_done: bool,
......@@ -553,7 +544,7 @@ pub fn Poller(comptime StreamEnum: type) type {
553544 stream_map: [enum_fields.len]StreamEnum,
554545
555546 pub fn removeAt(self: *@This(), index: u32) void {
556 std.debug.assert(index < self.count);
547 assert(index < self.count);
557548 for (index + 1..self.count) |i| {
558549 self.handles_buf[i - 1] = self.handles_buf[i];
559550 self.stream_map[i - 1] = self.stream_map[i];
......@@ -566,13 +557,14 @@ pub fn Poller(comptime StreamEnum: type) type {
566557 const Self = @This();
567558
568559 pub fn deinit(self: *Self) void {
560 const gpa = self.gpa;
569561 if (is_windows) {
570562 // cancel any pending IO to prevent clobbering OVERLAPPED value
571563 for (self.windows.active.handles_buf[0..self.windows.active.count]) |h| {
572564 _ = windows.kernel32.CancelIo(h);
573565 }
574566 }
575 inline for (&self.fifos) |*q| q.deinit();
567 inline for (&self.readers) |*r| gpa.free(r.buffer);
576568 self.* = undefined;
577569 }
578570
......@@ -592,21 +584,40 @@ pub fn Poller(comptime StreamEnum: type) type {
592584 }
593585 }
594586
595 pub inline fn fifo(self: *Self, comptime which: StreamEnum) *PollFifo {
596 return &self.fifos[@intFromEnum(which)];
587 pub fn reader(self: *Self, which: StreamEnum) *Reader {
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;
597606 }
598607
599608 fn pollWindows(self: *Self, nanoseconds: ?u64) !bool {
600609 const bump_amt = 512;
610 const gpa = self.gpa;
601611
602612 if (!self.windows.first_read_done) {
603613 var already_read_data = false;
604614 for (0..enum_fields.len) |i| {
605615 const handle = self.windows.active.handles_buf[i];
606616 switch (try windowsAsyncReadToFifoAndQueueSmallRead(
617 gpa,
607618 handle,
608619 &self.windows.overlapped[i],
609 &self.fifos[i],
620 &self.readers[i],
610621 &self.windows.small_bufs[i],
611622 bump_amt,
612623 )) {
......@@ -653,7 +664,7 @@ pub fn Poller(comptime StreamEnum: type) type {
653664 const handle = self.windows.active.handles_buf[active_idx];
654665
655666 const overlapped = &self.windows.overlapped[stream_idx];
656 const stream_fifo = &self.fifos[stream_idx];
667 const stream_reader = &self.readers[stream_idx];
657668 const small_buf = &self.windows.small_bufs[stream_idx];
658669
659670 const num_bytes_read = switch (try windowsGetReadResult(handle, overlapped, false)) {
......@@ -664,12 +675,16 @@ pub fn Poller(comptime StreamEnum: type) type {
664675 },
665676 .aborted => unreachable,
666677 };
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
669683 switch (try windowsAsyncReadToFifoAndQueueSmallRead(
684 gpa,
670685 handle,
671686 overlapped,
672 stream_fifo,
687 stream_reader,
673688 small_buf,
674689 bump_amt,
675690 )) {
......@@ -684,6 +699,7 @@ pub fn Poller(comptime StreamEnum: type) type {
684699 }
685700
686701 fn pollPosix(self: *Self, nanoseconds: ?u64) !bool {
702 const gpa = self.gpa;
687703 // We ask for ensureUnusedCapacity with this much extra space. This
688704 // has more of an effect on small reads because once the reads
689705 // start to get larger the amount of space an ArrayList will
......@@ -703,18 +719,18 @@ pub fn Poller(comptime StreamEnum: type) type {
703719 }
704720
705721 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| {
707723 // Try reading whatever is available before checking the error
708724 // conditions.
709725 // It's still possible to read after a POLL.HUP is received,
710726 // always check if there's some data waiting to be read first.
711727 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);
713729 const amt = posix.read(poll_fd.fd, buf) catch |err| switch (err) {
714730 error.BrokenPipe => 0, // Handle the same as EOF.
715731 else => |e| return e,
716732 };
717 q.update(amt);
733 advanceBufferEnd(r, amt);
718734 if (amt == 0) {
719735 // Remove the fd when the EOF condition is met.
720736 poll_fd.fd = -1;
......@@ -730,146 +746,181 @@ pub fn Poller(comptime StreamEnum: type) type {
730746 }
731747 return keep_polling;
732748 }
733 };
734}
735749
736/// The `ReadFile` docuementation states that `lpNumberOfBytesRead` does not have a meaningful
737/// result when using overlapped I/O, but also that it cannot be `null` on Windows 7. For
738/// compatibility, we point it to this dummy variables, which we never otherwise access.
739/// See: https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-readfile
740var win_dummy_bytes_read: u32 = undefined;
741
742/// Read as much data as possible from `handle` with `overlapped`, and write it to the FIFO. Before
743/// returning, queue a read into `small_buf` so that `WaitForMultipleObjects` returns when more data
744/// is available. `handle` must have no pending asynchronous operation.
745fn windowsAsyncReadToFifoAndQueueSmallRead(
746 handle: windows.HANDLE,
747 overlapped: *windows.OVERLAPPED,
748 fifo: *PollFifo,
749 small_buf: *[128]u8,
750 bump_amt: usize,
751) !enum { empty, populated, closed_populated, closed } {
752 var read_any_data = false;
753 while (true) {
754 const fifo_read_pending = while (true) {
755 const buf = try fifo.writableWithSize(bump_amt);
756 const buf_len = math.cast(u32, buf.len) orelse math.maxInt(u32);
757
758 if (0 == windows.kernel32.ReadFile(
759 handle,
760 buf.ptr,
761 buf_len,
762 &win_dummy_bytes_read,
763 overlapped,
764 )) switch (windows.GetLastError()) {
765 .IO_PENDING => break true,
766 .BROKEN_PIPE => return if (read_any_data) .closed_populated else .closed,
767 else => |err| return windows.unexpectedError(err),
768 };
750 /// Returns a slice into the unused capacity of `buffer` with at least
751 /// `min_len` bytes, extending `buffer` by resizing it with `gpa` as necessary.
752 ///
753 /// After calling this function, typically the caller will follow up with a
754 /// call to `advanceBufferEnd` to report the actual number of bytes buffered.
755 fn writableSliceGreedyAlloc(r: *Reader, allocator: Allocator, min_len: usize) Allocator.Error![]u8 {
756 {
757 const unused = r.buffer[r.end..];
758 if (unused.len >= min_len) return unused;
759 }
760 if (r.seek > 0) r.rebase(r.buffer.len) catch unreachable;
761 {
762 var list: std.ArrayListUnmanaged(u8) = .{
763 .items = r.buffer[0..r.end],
764 .capacity = r.buffer.len,
765 };
766 defer r.buffer = list.allocatedSlice();
767 try list.ensureUnusedCapacity(allocator, min_len);
768 }
769 const unused = r.buffer[r.end..];
770 assert(unused.len >= min_len);
771 return unused;
772 }
773
774 /// After writing directly into the unused capacity of `buffer`, this function
775 /// updates `end` so that users of `Reader` can receive the data.
776 fn advanceBufferEnd(r: *Reader, n: usize) void {
777 assert(n <= r.buffer.len - r.end);
778 r.end += n;
779 }
780
781 /// The `ReadFile` docuementation states that `lpNumberOfBytesRead` does not have a meaningful
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)) {
771 .success => |n| n,
772 .closed => return if (read_any_data) .closed_populated else .closed,
773 .aborted => unreachable,
774 };
804 if (0 == windows.kernel32.ReadFile(
805 handle,
806 buf.ptr,
807 buf_len,
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;
777 fifo.update(num_bytes_read);
816 const num_bytes_read = switch (try windowsGetReadResult(handle, overlapped, false)) {
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) {
780 // We filled the buffer, so there's probably more data available.
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 };
822 read_any_data = true;
823 advanceBufferEnd(r, num_bytes_read);
788824
789 if (fifo_read_pending) cancel_read: {
790 // Cancel the pending read into the FIFO.
791 _ = windows.kernel32.CancelIo(handle);
825 if (num_bytes_read == buf_len) {
826 // We filled the buffer, so there's probably more data available.
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.
794 switch (windows.kernel32.WaitForSingleObject(handle, windows.INFINITE)) {
795 windows.WAIT_OBJECT_0 => {},
796 windows.WAIT_FAILED => return windows.unexpectedError(windows.GetLastError()),
797 else => unreachable,
798 }
835 if (fifo_read_pending) cancel_read: {
836 // Cancel the pending read into the FIFO.
837 _ = windows.kernel32.CancelIo(handle);
799838
800 // If it completed before we canceled, make sure to tell the FIFO!
801 const num_bytes_read = switch (try windowsGetReadResult(handle, overlapped, true)) {
802 .success => |n| n,
803 .closed => return if (read_any_data) .closed_populated else .closed,
804 .aborted => break :cancel_read,
805 };
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 };
839 // We have to wait for the handle to be signalled, i.e. for the cancellation to complete.
840 switch (windows.kernel32.WaitForSingleObject(handle, windows.INFINITE)) {
841 windows.WAIT_OBJECT_0 => {},
842 windows.WAIT_FAILED => return windows.unexpectedError(windows.GetLastError()),
843 else => unreachable,
844 }
825845
826 // We got data back this time. Write it to the FIFO and run the main loop again.
827 const num_bytes_read = switch (try windowsGetReadResult(handle, overlapped, false)) {
828 .success => |n| n,
829 .closed => return if (read_any_data) .closed_populated else .closed,
830 .aborted => unreachable,
831 };
832 try fifo.write(small_buf[0..num_bytes_read]);
833 read_any_data = true;
834 }
835}
846 // If it completed before we canceled, make sure to tell the FIFO!
847 const num_bytes_read = switch (try windowsGetReadResult(handle, overlapped, true)) {
848 .success => |n| n,
849 .closed => return if (read_any_data) .closed_populated else .closed,
850 .aborted => break :cancel_read,
851 };
852 read_any_data = true;
853 advanceBufferEnd(r, num_bytes_read);
854 }
836855
837/// Simple wrapper around `GetOverlappedResult` to determine the result of a `ReadFile` operation.
838/// If `!allow_aborted`, then `aborted` is never returned (`OPERATION_ABORTED` is considered unexpected).
839///
840/// The `ReadFile` documentation states that the number of bytes read by an overlapped `ReadFile` must be determined using `GetOverlappedResult`, even if the
841/// operation immediately returns data:
842/// "Use NULL for [lpNumberOfBytesRead] if this is an asynchronous operation to avoid potentially
843/// erroneous results."
844/// "If `hFile` was opened with `FILE_FLAG_OVERLAPPED`, the following conditions are in effect: [...]
845/// The lpNumberOfBytesRead parameter should be set to NULL. Use the GetOverlappedResult function to
846/// get the actual number of bytes read."
847/// See: https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-readfile
848fn windowsGetReadResult(
849 handle: windows.HANDLE,
850 overlapped: *windows.OVERLAPPED,
851 allow_aborted: bool,
852) !union(enum) {
853 success: u32,
854 closed,
855 aborted,
856} {
857 var num_bytes_read: u32 = undefined;
858 if (0 == windows.kernel32.GetOverlappedResult(
859 handle,
860 overlapped,
861 &num_bytes_read,
862 0,
863 )) switch (windows.GetLastError()) {
864 .BROKEN_PIPE => return .closed,
865 .OPERATION_ABORTED => |err| if (allow_aborted) {
866 return .aborted;
867 } else {
868 return windows.unexpectedError(err);
869 },
870 else => |err| return windows.unexpectedError(err),
856 // Try to queue the 1-byte read.
857 if (0 == windows.kernel32.ReadFile(
858 handle,
859 small_buf,
860 small_buf.len,
861 &win_dummy_bytes_read,
862 overlapped,
863 )) switch (windows.GetLastError()) {
864 .IO_PENDING => {
865 // 1-byte read pending as intended
866 return if (read_any_data) .populated else .empty;
867 },
868 .BROKEN_PIPE => return if (read_any_data) .closed_populated else .closed,
869 else => |err| return windows.unexpectedError(err),
870 };
871
872 // We got data back this time. Write it to the FIFO and run the main loop again.
873 const num_bytes_read = switch (try windowsGetReadResult(handle, overlapped, false)) {
874 .success => |n| n,
875 .closed => return if (read_any_data) .closed_populated else .closed,
876 .aborted => unreachable,
877 };
878 const buf = small_buf[0..num_bytes_read];
879 const dest = try writableSliceGreedyAlloc(r, gpa, buf.len);
880 @memcpy(dest[0..buf.len], buf);
881 advanceBufferEnd(r, buf.len);
882 read_any_data = true;
883 }
884 }
885
886 /// Simple wrapper around `GetOverlappedResult` to determine the result of a `ReadFile` operation.
887 /// If `!allow_aborted`, then `aborted` is never returned (`OPERATION_ABORTED` is considered unexpected).
888 ///
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 }
871923 };
872 return .{ .success = num_bytes_read };
873924}
874925
875926/// Given an enum, returns a struct with fields of that enum, each field
......@@ -880,10 +931,10 @@ pub fn PollFiles(comptime StreamEnum: type) type {
880931 for (&struct_fields, enum_fields) |*struct_field, enum_field| {
881932 struct_field.* = .{
882933 .name = enum_field.name,
883 .type = fs.File,
934 .type = std.fs.File,
884935 .default_value_ptr = null,
885936 .is_comptime = false,
886 .alignment = @alignOf(fs.File),
937 .alignment = @alignOf(std.fs.File),
887938 };
888939 }
889940 return @Type(.{ .@"struct" = .{
......@@ -898,16 +949,14 @@ test {
898949 _ = Reader;
899950 _ = Reader.Limited;
900951 _ = Writer;
901 _ = @import("Io/bit_reader.zig");
902 _ = @import("Io/bit_writer.zig");
903 _ = @import("Io/buffered_atomic_file.zig");
904 _ = @import("Io/buffered_reader.zig");
905 _ = @import("Io/buffered_writer.zig");
906 _ = @import("Io/c_writer.zig");
907 _ = @import("Io/counting_writer.zig");
908 _ = @import("Io/counting_reader.zig");
909 _ = @import("Io/fixed_buffer_stream.zig");
910 _ = @import("Io/seekable_stream.zig");
911 _ = @import("Io/stream_source.zig");
952 _ = BitReader;
953 _ = BitWriter;
954 _ = BufferedReader;
955 _ = BufferedWriter;
956 _ = CountingWriter;
957 _ = CountingReader;
958 _ = FixedBufferStream;
959 _ = SeekableStream;
960 _ = tty;
912961 _ = @import("Io/test.zig");
913962}
lib/std/Io/DeprecatedReader.zig+5-3
......@@ -373,11 +373,11 @@ pub fn discard(self: Self) anyerror!u64 {
373373}
374374
375375/// 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 {
377377 return .{
378378 .derp_reader = self.*,
379379 .new_interface = .{
380 .buffer = &.{},
380 .buffer = buffer,
381381 .vtable = &.{ .stream = Adapter.stream },
382382 .seek = 0,
383383 .end = 0,
......@@ -393,10 +393,12 @@ pub const Adapter = struct {
393393 fn stream(r: *std.io.Reader, w: *std.io.Writer, limit: std.io.Limit) std.io.Reader.StreamError!usize {
394394 const a: *@This() = @alignCast(@fieldParentPtr("new_interface", r));
395395 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| {
397397 a.err = err;
398398 return error.ReadFailed;
399399 };
400 w.advance(n);
401 return n;
400402 }
401403};
402404
lib/std/Io/DeprecatedWriter.zig+6-1
......@@ -100,7 +100,12 @@ pub const Adapter = struct {
100100
101101 fn drain(w: *std.io.Writer, data: []const []const u8, splat: usize) std.io.Writer.Error!usize {
102102 _ = 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 });
104109 return a.derp_writer.write(data[0]) catch |err| {
105110 a.err = err;
106111 return error.WriteFailed;
lib/std/Io/Reader.zig+70-70
......@@ -67,6 +67,18 @@ pub const VTable = struct {
6767 ///
6868 /// This function is only called when `buffer` is empty.
6969 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,
7082};
7183
7284pub const StreamError = error{
......@@ -97,6 +109,10 @@ pub const ShortError = error{
97109 ReadFailed,
98110};
99111
112pub const RebaseError = error{
113 EndOfStream,
114};
115
100116pub const failing: Reader = .{
101117 .vtable = &.{
102118 .stream = failingStream,
......@@ -122,6 +138,7 @@ pub fn fixed(buffer: []const u8) Reader {
122138 .vtable = &.{
123139 .stream = endingStream,
124140 .discard = endingDiscard,
141 .rebase = endingRebase,
125142 },
126143 // This cast is safe because all potential writes to it will instead
127144 // return `error.EndOfStream`.
......@@ -179,6 +196,38 @@ pub fn streamExact(r: *Reader, w: *Writer, n: usize) StreamError!void {
179196 while (remaining != 0) remaining -= try r.stream(w, .limited(remaining));
180197}
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
182231/// "Pump" data from the reader to the writer, handling `error.EndOfStream` as
183232/// a success case.
184233///
......@@ -234,7 +283,7 @@ pub fn allocRemaining(r: *Reader, gpa: Allocator, limit: Limit) LimitedAllocErro
234283/// such case, the next byte that would be read will be the first one to exceed
235284/// `limit`, and all preceeding bytes have been appended to `list`.
236285///
237/// Asserts `buffer` has nonzero capacity.
286/// If `limit` is not `Limit.unlimited`, asserts `buffer` has nonzero capacity.
238287///
239288/// See also:
240289/// * `allocRemaining`
......@@ -245,7 +294,7 @@ pub fn appendRemaining(
245294 list: *std.ArrayListAlignedUnmanaged(u8, alignment),
246295 limit: Limit,
247296) 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.
249298 const buffer_contents = r.buffer[r.seek..r.end];
250299 const copy_len = limit.minInt(buffer_contents.len);
251300 try list.appendSlice(gpa, r.buffer[0..copy_len]);
......@@ -748,11 +797,8 @@ pub fn peekDelimiterInclusive(r: *Reader, delimiter: u8) DelimiterError![]u8 {
748797 @branchHint(.likely);
749798 return buffer[seek .. end + 1];
750799 }
751 if (r.vtable.stream == &endingStream) {
752 // Protect the `@constCast` of `fixed`.
753 return error.EndOfStream;
754 }
755 r.rebase();
800 // TODO take a parameter for max search length rather than relying on buffer capacity
801 try rebase(r, r.buffer.len);
756802 while (r.buffer.len - r.end != 0) {
757803 const end_cap = r.buffer[r.end..];
758804 var writer: Writer = .fixed(end_cap);
......@@ -1018,11 +1064,7 @@ fn fillUnbuffered(r: *Reader, n: usize) Error!void {
10181064 };
10191065 if (r.seek + n <= r.end) return;
10201066 };
1021 if (r.vtable.stream == &endingStream) {
1022 // Protect the `@constCast` of `fixed`.
1023 return error.EndOfStream;
1024 }
1025 rebaseCapacity(r, n);
1067 try rebase(r, n);
10261068 var writer: Writer = .{
10271069 .buffer = r.buffer,
10281070 .vtable = &.{ .drain = Writer.fixedDrain },
......@@ -1042,7 +1084,7 @@ fn fillUnbuffered(r: *Reader, n: usize) Error!void {
10421084///
10431085/// Asserts buffer capacity is at least 1.
10441086pub fn fillMore(r: *Reader) Error!void {
1045 rebaseCapacity(r, 1);
1087 try rebase(r, 1);
10461088 var writer: Writer = .{
10471089 .buffer = r.buffer,
10481090 .end = r.end,
......@@ -1219,7 +1261,7 @@ pub fn takeLeb128(r: *Reader, comptime Result: type) TakeLeb128Error!Result {
12191261
12201262pub fn expandTotalCapacity(r: *Reader, allocator: Allocator, n: usize) Allocator.Error!void {
12211263 if (n <= r.buffer.len) return;
1222 if (r.seek > 0) rebase(r);
1264 if (r.seek > 0) rebase(r, r.buffer.len);
12231265 var list: ArrayList(u8) = .{
12241266 .items = r.buffer[0..r.end],
12251267 .capacity = r.buffer.len,
......@@ -1235,37 +1277,6 @@ pub fn fillAlloc(r: *Reader, allocator: Allocator, n: usize) FillAllocError!void
12351277 return fill(r, n);
12361278}
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
12691280fn takeMultipleOf7Leb128(r: *Reader, comptime Result: type) TakeLeb128Error!Result {
12701281 const result_info = @typeInfo(Result).int;
12711282 comptime assert(result_info.bits % 7 == 0);
......@@ -1296,37 +1307,20 @@ fn takeMultipleOf7Leb128(r: *Reader, comptime Result: type) TakeLeb128Error!Resu
12961307 }
12971308}
12981309
1299/// Left-aligns data such that `r.seek` becomes zero.
1300///
1301/// If `r.seek` is not already zero then `buffer` is mutated, making it illegal
1302/// to call this function with a const-casted `buffer`, such as in the case of
1303/// `fixed`. This issue can be avoided:
1304/// * in implementations, by attempting a read before a rebase, in which
1305/// case the read will return `error.EndOfStream`, preventing the rebase.
1306/// * in usage, by copying into a mutable buffer before initializing `fixed`.
1307pub fn rebase(r: *Reader) void {
1308 if (r.seek == 0) return;
1310/// Ensures `capacity` more data can be buffered without rebasing.
1311pub fn rebase(r: *Reader, capacity: usize) RebaseError!void {
1312 if (r.end + capacity <= r.buffer.len) return;
1313 return r.vtable.rebase(r, capacity);
1314}
1315
1316pub fn defaultRebase(r: *Reader, capacity: usize) RebaseError!void {
1317 if (r.end <= r.buffer.len - capacity) return;
13091318 const data = r.buffer[r.seek..r.end];
13101319 @memmove(r.buffer[0..data.len], data);
13111320 r.seek = 0;
13121321 r.end = data.len;
13131322}
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
13301324/// Advances the stream and decreases the size of the storage buffer by `n`,
13311325/// returning the range of bytes no longer accessible by `r`.
13321326///
......@@ -1682,6 +1676,12 @@ fn endingDiscard(r: *Reader, limit: Limit) Error!usize {
16821676 return error.EndOfStream;
16831677}
16841678
1679fn endingRebase(r: *Reader, capacity: usize) RebaseError!void {
1680 _ = r;
1681 _ = capacity;
1682 return error.EndOfStream;
1683}
1684
16851685fn failingStream(r: *Reader, w: *Writer, limit: Limit) StreamError!usize {
16861686 _ = r;
16871687 _ = w;
lib/std/Io/Writer.zig+85-28
......@@ -256,10 +256,10 @@ test "fixed buffer flush" {
256256 try testing.expectEqual(10, buffer[0]);
257257}
258258
259/// Calls `VTable.drain` but hides the last `preserve_length` bytes from the
259/// Calls `VTable.drain` but hides the last `preserve_len` bytes from the
260260/// implementation, keeping them buffered.
261pub fn drainPreserve(w: *Writer, preserve_length: usize) Error!void {
262 const temp_end = w.end -| preserve_length;
261pub fn drainPreserve(w: *Writer, preserve_len: usize) Error!void {
262 const temp_end = w.end -| preserve_len;
263263 const preserved = w.buffer[temp_end..w.end];
264264 w.end = temp_end;
265265 defer w.end += preserved.len;
......@@ -310,24 +310,38 @@ pub fn writableSliceGreedy(w: *Writer, minimum_length: usize) Error![]u8 {
310310}
311311
312312/// Asserts the provided buffer has total capacity enough for `minimum_length`
313/// and `preserve_length` combined.
313/// and `preserve_len` combined.
314314///
315315/// Does not `advance` the buffer end position.
316316///
317/// When draining the buffer, ensures that at least `preserve_length` bytes
317/// When draining the buffer, ensures that at least `preserve_len` bytes
318318/// remain buffered.
319319///
320/// If `preserve_length` is zero, this is equivalent to `writableSliceGreedy`.
321pub fn writableSliceGreedyPreserve(w: *Writer, preserve_length: usize, minimum_length: usize) Error![]u8 {
322 assert(w.buffer.len >= preserve_length + minimum_length);
320/// If `preserve_len` is zero, this is equivalent to `writableSliceGreedy`.
321pub fn writableSliceGreedyPreserve(w: *Writer, preserve_len: usize, minimum_length: usize) Error![]u8 {
322 assert(w.buffer.len >= preserve_len + minimum_length);
323323 while (w.buffer.len - w.end < minimum_length) {
324 try drainPreserve(w, preserve_length);
324 try drainPreserve(w, preserve_len);
325325 } else {
326326 @branchHint(.likely);
327327 return w.buffer[w.end..];
328328 }
329329}
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
331345pub const WritableVectorIterator = struct {
332346 first: []u8,
333347 middle: []const []u8 = &.{},
......@@ -523,16 +537,16 @@ pub fn write(w: *Writer, bytes: []const u8) Error!usize {
523537 return w.vtable.drain(w, &.{bytes}, 1);
524538}
525539
526/// Asserts `buffer` capacity exceeds `preserve_length`.
527pub fn writePreserve(w: *Writer, preserve_length: usize, bytes: []const u8) Error!usize {
528 assert(preserve_length <= w.buffer.len);
540/// Asserts `buffer` capacity exceeds `preserve_len`.
541pub fn writePreserve(w: *Writer, preserve_len: usize, bytes: []const u8) Error!usize {
542 assert(preserve_len <= w.buffer.len);
529543 if (w.end + bytes.len <= w.buffer.len) {
530544 @branchHint(.likely);
531545 @memcpy(w.buffer[w.end..][0..bytes.len], bytes);
532546 w.end += bytes.len;
533547 return bytes.len;
534548 }
535 const temp_end = w.end -| preserve_length;
549 const temp_end = w.end -| preserve_len;
536550 const preserved = w.buffer[temp_end..w.end];
537551 w.end = temp_end;
538552 defer w.end += preserved.len;
......@@ -552,13 +566,13 @@ pub fn writeAll(w: *Writer, bytes: []const u8) Error!void {
552566/// Calls `drain` as many times as necessary such that all of `bytes` are
553567/// transferred.
554568///
555/// When draining the buffer, ensures that at least `preserve_length` bytes
569/// When draining the buffer, ensures that at least `preserve_len` bytes
556570/// remain buffered.
557571///
558/// Asserts `buffer` capacity exceeds `preserve_length`.
559pub fn writeAllPreserve(w: *Writer, preserve_length: usize, bytes: []const u8) Error!void {
572/// Asserts `buffer` capacity exceeds `preserve_len`.
573pub fn writeAllPreserve(w: *Writer, preserve_len: usize, bytes: []const u8) Error!void {
560574 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..]);
562576}
563577
564578/// Renders fmt string with args, calling `writer` with slices of bytes.
......@@ -761,11 +775,11 @@ pub fn writeByte(w: *Writer, byte: u8) Error!void {
761775 }
762776}
763777
764/// When draining the buffer, ensures that at least `preserve_length` bytes
778/// When draining the buffer, ensures that at least `preserve_len` bytes
765779/// 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 {
767781 while (w.buffer.len - w.end == 0) {
768 try drainPreserve(w, preserve_length);
782 try drainPreserve(w, preserve_len);
769783 } else {
770784 @branchHint(.likely);
771785 w.buffer[w.end] = byte;
......@@ -788,10 +802,42 @@ test splatByteAll {
788802 try testing.expectEqualStrings("7" ** 45, aw.writer.buffered());
789803}
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
791831/// Writes the same byte many times, allowing short writes.
792832///
793833/// Does maximum of one underlying `VTable.drain`.
794834pub 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 }
795841 return writeSplat(w, &.{&.{byte}}, n);
796842}
797843
......@@ -801,9 +847,10 @@ pub fn splatBytesAll(w: *Writer, bytes: []const u8, splat: usize) Error!void {
801847 var remaining_bytes: usize = bytes.len * splat;
802848 remaining_bytes -= try w.splatBytes(bytes, splat);
803849 while (remaining_bytes > 0) {
804 const leftover = remaining_bytes % bytes.len;
805 const buffers: [2][]const u8 = .{ bytes[bytes.len - leftover ..], bytes };
806 remaining_bytes -= try w.writeSplat(&buffers, splat);
850 const leftover_splat = remaining_bytes / bytes.len;
851 const leftover_bytes = remaining_bytes % bytes.len;
852 const buffers: [2][]const u8 = .{ bytes[bytes.len - leftover_bytes ..], bytes };
853 remaining_bytes -= try w.writeSplat(&buffers, leftover_splat);
807854 }
808855}
809856
......@@ -1564,17 +1611,23 @@ pub fn printFloatHexOptions(w: *Writer, value: anytype, options: std.fmt.Number)
15641611}
15651612
15661613pub fn printFloatHex(w: *Writer, value: anytype, case: std.fmt.Case, opt_precision: ?usize) Error!void {
1567 if (std.math.signbit(value)) try w.writeByte('-');
1568 if (std.math.isNan(value)) return w.writeAll(switch (case) {
1614 const v = switch (@TypeOf(value)) {
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) {
15691622 .lower => "nan",
15701623 .upper => "NAN",
15711624 });
1572 if (std.math.isInf(value)) return w.writeAll(switch (case) {
1625 if (std.math.isInf(v)) return w.writeAll(switch (case) {
15731626 .lower => "inf",
15741627 .upper => "INF",
15751628 });
15761629
1577 const T = @TypeOf(value);
1630 const T = @TypeOf(v);
15781631 const TU = std.meta.Int(.unsigned, @bitSizeOf(T));
15791632
15801633 const mantissa_bits = std.math.floatMantissaBits(T);
......@@ -1584,7 +1637,7 @@ pub fn printFloatHex(w: *Writer, value: anytype, case: std.fmt.Case, opt_precisi
15841637 const exponent_mask = (1 << exponent_bits) - 1;
15851638 const exponent_bias = (1 << (exponent_bits - 1)) - 1;
15861639
1587 const as_bits: TU = @bitCast(value);
1640 const as_bits: TU = @bitCast(v);
15881641 var mantissa = as_bits & mantissa_mask;
15891642 var exponent: i32 = @as(u16, @truncate((as_bits >> mantissa_bits) & exponent_mask));
15901643
......@@ -2239,6 +2292,10 @@ pub const Discarding = struct {
22392292
22402293 pub fn sendFile(w: *Writer, file_reader: *File.Reader, limit: Limit) FileError!usize {
22412294 if (File.Handle == void) return error.Unimplemented;
2295 switch (builtin.zig_backend) {
2296 else => {},
2297 .stage2_aarch64 => return error.Unimplemented,
2298 }
22422299 const d: *Discarding = @alignCast(@fieldParentPtr("writer", w));
22432300 d.count += w.end;
22442301 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,
2525/// Accessed atomically.
2626done: bool,
2727need_clear: bool,
28status: Status,
2829
2930refresh_rate_ns: u64,
3031initial_delay_ns: u64,
......@@ -47,6 +48,22 @@ node_freelist: Freelist,
4748/// value may at times temporarily exceed the node count.
4849node_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
5067const Freelist = packed struct(u32) {
5168 head: Node.OptionalIndex,
5269 /// Whenever `node_freelist` is added to, this generation is incremented
......@@ -383,6 +400,7 @@ var global_progress: Progress = .{
383400 .draw_buffer = undefined,
384401 .done = false,
385402 .need_clear = false,
403 .status = .working,
386404
387405 .node_parents = &node_parents_buffer,
388406 .node_storage = &node_storage_buffer,
......@@ -408,6 +426,9 @@ pub const have_ipc = switch (builtin.os.tag) {
408426const noop_impl = builtin.single_threaded or switch (builtin.os.tag) {
409427 .wasi, .freestanding => true,
410428 else => false,
429} or switch (builtin.zig_backend) {
430 .stage2_aarch64 => true,
431 else => false,
411432};
412433
413434/// Initializes a global Progress instance.
......@@ -495,6 +516,11 @@ pub fn start(options: Options) Node {
495516 return root_node;
496517}
497518
519pub fn setStatus(new_status: Status) void {
520 if (noop_impl) return;
521 @atomicStore(Status, &global_progress.status, new_status, .monotonic);
522}
523
498524/// Returns whether a resize is needed to learn the terminal size.
499525fn wait(timeout_ns: u64) bool {
500526 const resize_flag = if (global_progress.redraw_event.timedWait(timeout_ns)) |_|
......@@ -675,6 +701,14 @@ const save = "\x1b7";
675701const restore = "\x1b8";
676702const 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
678712const TreeSymbol = enum {
679713 /// ├─
680714 tee,
......@@ -754,10 +788,10 @@ fn appendTreeSymbol(symbol: TreeSymbol, buf: []u8, start_i: usize) usize {
754788}
755789
756790fn clearWrittenWithEscapeCodes() anyerror!void {
757 if (!global_progress.need_clear) return;
791 if (noop_impl or !global_progress.need_clear) return;
758792
759793 global_progress.need_clear = false;
760 try write(clear);
794 try write(clear ++ progress_remove);
761795}
762796
763797/// U+25BA or â–º
......@@ -1200,6 +1234,43 @@ fn computeRedraw(serialized_buffer: *Serialized.Buffer) struct { []u8, usize } {
12001234 i, const nl_n = computeNode(buf, i, 0, serialized, children, root_node_index);
12011235
12021236 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
12031274 if (nl_n > 0) {
12041275 buf[i] = '\r';
12051276 i += 1;
lib/std/builtin.zig+5-2
......@@ -772,7 +772,7 @@ pub const Endian = enum {
772772
773773/// This data structure is used by the Zig language code generation and
774774/// therefore must be kept in sync with the compiler implementation.
775pub const Signedness = enum {
775pub const Signedness = enum(u1) {
776776 signed,
777777 unsigned,
778778};
......@@ -894,7 +894,10 @@ pub const VaList = switch (builtin.cpu.arch) {
894894 .aarch64, .aarch64_be => switch (builtin.os.tag) {
895895 .windows => *u8,
896896 .ios, .macos, .tvos, .watchos, .visionos => *u8,
897 else => @compileError("disabled due to miscompilations"), // VaListAarch64,
897 else => switch (builtin.zig_backend) {
898 .stage2_aarch64 => VaListAarch64,
899 else => @compileError("disabled due to miscompilations"),
900 },
898901 },
899902 .arm, .armeb, .thumb, .thumbeb => switch (builtin.os.tag) {
900903 .ios, .macos, .tvos, .watchos, .visionos => *u8,
lib/std/c.zig+3-3
......@@ -7147,7 +7147,7 @@ pub const dirent = switch (native_os) {
71477147 off: off_t,
71487148 reclen: c_ushort,
71497149 type: u8,
7150 name: [256:0]u8,
7150 name: [255:0]u8,
71517151 },
71527152 else => void,
71537153};
......@@ -10497,9 +10497,9 @@ pub const sysconf = switch (native_os) {
1049710497
1049810498pub const sf_hdtr = switch (native_os) {
1049910499 .freebsd, .macos, .ios, .tvos, .watchos, .visionos => extern struct {
10500 headers: [*]const iovec_const,
10500 headers: ?[*]const iovec_const,
1050110501 hdr_cnt: c_int,
10502 trailers: [*]const iovec_const,
10502 trailers: ?[*]const iovec_const,
1050310503 trl_cnt: c_int,
1050410504 },
1050510505 else => void,
lib/std/compress.zig+2-58
......@@ -1,75 +1,19 @@
11//! Compression algorithms.
22
3const std = @import("std.zig");
4
53pub const flate = @import("compress/flate.zig");
64pub const gzip = @import("compress/gzip.zig");
75pub const zlib = @import("compress/zlib.zig");
86pub const lzma = @import("compress/lzma.zig");
97pub const lzma2 = @import("compress/lzma2.zig");
108pub const xz = @import("compress/xz.zig");
11pub const zstd = @import("compress/zstandard.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}
9pub const zstd = @import("compress/zstd.zig");
6610
6711test {
12 _ = flate;
6813 _ = lzma;
6914 _ = lzma2;
7015 _ = xz;
7116 _ = zstd;
72 _ = flate;
7317 _ = gzip;
7418 _ = zlib;
7519}
lib/std/compress/xz.zig+35-14
......@@ -12,17 +12,11 @@ pub const Check = enum(u4) {
1212};
1313
1414fn readStreamFlags(reader: anytype, check: *Check) !void {
15 var bit_reader = std.io.bitReader(.little, reader);
16
17 const reserved1 = try bit_reader.readBitsNoEof(u8, 8);
18 if (reserved1 != 0)
19 return error.CorruptInput;
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;
15 const reserved1 = try reader.readByte();
16 if (reserved1 != 0) return error.CorruptInput;
17 const byte = try reader.readByte();
18 if ((byte >> 4) != 0) return error.CorruptInput;
19 check.* = @enumFromInt(@as(u4, @truncate(byte)));
2620}
2721
2822pub fn decompress(allocator: Allocator, reader: anytype) !Decompress(@TypeOf(reader)) {
......@@ -47,7 +41,7 @@ pub fn Decompress(comptime ReaderType: type) type {
4741
4842 var check: Check = undefined;
4943 const hash_a = blk: {
50 var hasher = std.compress.hashedReader(source, Crc32.init());
44 var hasher = hashedReader(source, Crc32.init());
5145 try readStreamFlags(hasher.reader(), &check);
5246 break :blk hasher.hasher.final();
5347 };
......@@ -80,7 +74,7 @@ pub fn Decompress(comptime ReaderType: type) type {
8074 return r;
8175
8276 const index_size = blk: {
83 var hasher = std.compress.hashedReader(self.in_reader, Crc32.init());
77 var hasher = hashedReader(self.in_reader, Crc32.init());
8478 hasher.hasher.update(&[1]u8{0x00});
8579
8680 var counter = std.io.countingReader(hasher.reader());
......@@ -115,7 +109,7 @@ pub fn Decompress(comptime ReaderType: type) type {
115109 const hash_a = try self.in_reader.readInt(u32, .little);
116110
117111 const hash_b = blk: {
118 var hasher = std.compress.hashedReader(self.in_reader, Crc32.init());
112 var hasher = hashedReader(self.in_reader, Crc32.init());
119113 const hashed_reader = hasher.reader();
120114
121115 const backward_size = (@as(u64, try hashed_reader.readInt(u32, .little)) + 1) * 4;
......@@ -140,6 +134,33 @@ pub fn Decompress(comptime ReaderType: type) type {
140134 };
141135}
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
143164test {
144165 _ = @import("xz/test.zig");
145166}
lib/std/compress/xz/block.zig+1-1
......@@ -91,7 +91,7 @@ pub fn Decoder(comptime ReaderType: type) type {
9191
9292 // Block Header
9393 {
94 var header_hasher = std.compress.hashedReader(block_reader, Crc32.init());
94 var header_hasher = xz.hashedReader(block_reader, Crc32.init());
9595 const header_reader = header_hasher.reader();
9696
9797 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 {
5454 };
5555 }
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 {
5858 var d = Md5.init(options);
59 d.update(b);
59 d.update(data);
6060 d.final(out);
6161 }
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
6371 pub fn update(d: *Self, b: []const u8) void {
6472 var off: usize = 0;
6573
lib/std/elf.zig+103-172
......@@ -482,6 +482,7 @@ pub const Header = struct {
482482 is_64: bool,
483483 endian: std.builtin.Endian,
484484 os_abi: OSABI,
485 /// The meaning of this value depends on `os_abi`.
485486 abi_version: u8,
486487 type: ET,
487488 machine: EM,
......@@ -494,205 +495,135 @@ pub const Header = struct {
494495 shnum: u16,
495496 shstrndx: u16,
496497
497 pub fn program_header_iterator(self: Header, parse_source: anytype) ProgramHeaderIterator(@TypeOf(parse_source)) {
498 return ProgramHeaderIterator(@TypeOf(parse_source)){
499 .elf_header = self,
500 .parse_source = parse_source,
498 pub fn iterateProgramHeaders(h: Header, file_reader: *std.fs.File.Reader) ProgramHeaderIterator {
499 return .{
500 .elf_header = h,
501 .file_reader = file_reader,
501502 };
502503 }
503504
504 pub fn section_header_iterator(self: Header, parse_source: anytype) SectionHeaderIterator(@TypeOf(parse_source)) {
505 return SectionHeaderIterator(@TypeOf(parse_source)){
506 .elf_header = self,
507 .parse_source = parse_source,
505 pub fn iterateSectionHeaders(h: Header, file_reader: *std.fs.File.Reader) SectionHeaderIterator {
506 return .{
507 .elf_header = h,
508 .file_reader = file_reader,
508509 };
509510 }
510511
511 pub fn read(parse_source: anytype) !Header {
512 var hdr_buf: [@sizeOf(Elf64_Ehdr)]u8 align(@alignOf(Elf64_Ehdr)) = undefined;
513 try parse_source.seekableStream().seekTo(0);
514 try parse_source.deprecatedReader().readNoEof(&hdr_buf);
515 return Header.parse(&hdr_buf);
516 }
512 pub const ReadError = std.Io.Reader.Error || error{
513 InvalidElfMagic,
514 InvalidElfVersion,
515 InvalidElfClass,
516 InvalidElfEndian,
517 };
517518
518 pub fn parse(hdr_buf: *align(@alignOf(Elf64_Ehdr)) const [@sizeOf(Elf64_Ehdr)]u8) !Header {
519 const hdr32 = @as(*const Elf32_Ehdr, @ptrCast(hdr_buf));
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;
519 pub fn read(r: *std.Io.Reader) ReadError!Header {
520 const buf = try r.peek(@sizeOf(Elf64_Ehdr));
523521
524 const is_64 = switch (hdr32.e_ident[EI_CLASS]) {
525 ELFCLASS32 => false,
526 ELFCLASS64 => true,
527 else => return error.InvalidElfClass,
528 };
522 if (!mem.eql(u8, buf[0..4], MAGIC)) return error.InvalidElfMagic;
523 if (buf[EI_VERSION] != 1) return error.InvalidElfVersion;
529524
530 const endian: std.builtin.Endian = switch (hdr32.e_ident[EI_DATA]) {
525 const endian: std.builtin.Endian = switch (buf[EI_DATA]) {
531526 ELFDATA2LSB => .little,
532527 ELFDATA2MSB => .big,
533528 else => return error.InvalidElfEndian,
534529 };
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 {
537539 // Converting integers to exhaustive enums using `@enumFromInt` could cause a panic.
538540 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`.
542 const abi_version = hdr32.e_ident[EI_ABIVERSION];
564pub const ProgramHeaderIterator = struct {
565 elf_header: Header,
566 file_reader: *std.fs.File.Reader,
567 index: usize = 0,
543568
544 const @"type" = if (need_bswap) blk: {
545 comptime assert(!@typeInfo(ET).@"enum".is_exhaustive);
546 const value = @intFromEnum(hdr32.e_type);
547 break :blk @as(ET, @enumFromInt(@byteSwap(value)));
548 } else hdr32.e_type;
569 pub fn next(it: *ProgramHeaderIterator) !?Elf64_Phdr {
570 if (it.index >= it.elf_header.phnum) return null;
571 defer it.index += 1;
549572
550 const machine = if (need_bswap) blk: {
551 comptime assert(!@typeInfo(EM).@"enum".is_exhaustive);
552 const value = @intFromEnum(hdr32.e_machine);
553 break :blk @as(EM, @enumFromInt(@byteSwap(value)));
554 } else hdr32.e_machine;
573 if (it.elf_header.is_64) {
574 const offset = it.elf_header.phoff + @sizeOf(Elf64_Phdr) * it.index;
575 try it.file_reader.seekTo(offset);
576 const phdr = try it.file_reader.interface.takeStruct(Elf64_Phdr, it.elf_header.endian);
577 return phdr;
578 }
555579
556 return @as(Header, .{
557 .is_64 = is_64,
558 .endian = endian,
559 .os_abi = os_abi,
560 .abi_version = abi_version,
561 .type = @"type",
562 .machine = machine,
563 .entry = int(is_64, need_bswap, hdr32.e_entry, hdr64.e_entry),
564 .phoff = int(is_64, need_bswap, hdr32.e_phoff, hdr64.e_phoff),
565 .shoff = int(is_64, need_bswap, hdr32.e_shoff, hdr64.e_shoff),
566 .phentsize = int(is_64, need_bswap, hdr32.e_phentsize, hdr64.e_phentsize),
567 .phnum = int(is_64, need_bswap, hdr32.e_phnum, hdr64.e_phnum),
568 .shentsize = int(is_64, need_bswap, hdr32.e_shentsize, hdr64.e_shentsize),
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 });
580 const offset = it.elf_header.phoff + @sizeOf(Elf32_Phdr) * it.index;
581 try it.file_reader.seekTo(offset);
582 const phdr = try it.file_reader.interface.takeStruct(Elf32_Phdr, it.elf_header.endian);
583 return .{
584 .p_type = phdr.p_type,
585 .p_offset = phdr.p_offset,
586 .p_vaddr = phdr.p_vaddr,
587 .p_paddr = phdr.p_paddr,
588 .p_filesz = phdr.p_filesz,
589 .p_memsz = phdr.p_memsz,
590 .p_flags = phdr.p_flags,
591 .p_align = phdr.p_align,
592 };
572593 }
573594};
574595
575pub fn ProgramHeaderIterator(comptime ParseSource: anytype) type {
576 return struct {
577 elf_header: Header,
578 parse_source: ParseSource,
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}
596pub const SectionHeaderIterator = struct {
597 elf_header: Header,
598 file_reader: *std.fs.File.Reader,
599 index: usize = 0,
624600
625pub fn SectionHeaderIterator(comptime ParseSource: anytype) type {
626 return struct {
627 elf_header: Header,
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}
601 pub fn next(it: *SectionHeaderIterator) !?Elf64_Shdr {
602 if (it.index >= it.elf_header.shnum) return null;
603 defer it.index += 1;
676604
677fn int(is_64: bool, need_bswap: bool, int_32: anytype, int_64: anytype) @TypeOf(int_64) {
678 if (is_64) {
679 if (need_bswap) {
680 return @byteSwap(int_64);
681 } else {
682 return int_64;
605 if (it.elf_header.is_64) {
606 try it.file_reader.seekTo(it.elf_header.shoff + @sizeOf(Elf64_Shdr) * it.index);
607 const shdr = try it.file_reader.interface.takeStruct(Elf64_Shdr, it.elf_header.endian);
608 return shdr;
683609 }
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 {
690 if (need_bswap) {
691 return @byteSwap(int_32);
692 } else {
693 return int_32;
611 try it.file_reader.seekTo(it.elf_header.shoff + @sizeOf(Elf32_Shdr) * it.index);
612 const shdr = try it.file_reader.interface.takeStruct(Elf32_Shdr, it.elf_header.endian);
613 return .{
614 .sh_name = shdr.sh_name,
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 };
694625 }
695}
626};
696627
697628pub const ELFCLASSNONE = 0;
698629pub const ELFCLASS32 = 1;
......@@ -2070,7 +2001,7 @@ pub const R_AARCH64 = enum(u32) {
20702001 TLSLE_LDST64_TPREL_LO12 = 558,
20712002 /// Likewise; no check.
20722003 TLSLE_LDST64_TPREL_LO12_NC = 559,
2073 /// PC-rel. load immediate 20:2.
2004 /// PC-rel. load immediate 20:2.
20742005 TLSDESC_LD_PREL19 = 560,
20752006 /// PC-rel. ADR immediate 20:0.
20762007 TLSDESC_ADR_PREL21 = 561,
lib/std/fs/AtomicFile.zig+52-46
......@@ -1,6 +1,13 @@
1file: File,
2// TODO either replace this with rand_buf or use []u16 on Windows
3tmp_path_buf: [tmp_path_len:0]u8,
1const AtomicFile = @This();
2const std = @import("../std.zig");
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,
411dest_basename: []const u8,
512file_open: bool,
613file_exists: bool,
......@@ -9,35 +16,24 @@ dir: Dir,
916
1017pub const InitError = File.OpenError;
1118
12pub const random_bytes_len = 12;
13const tmp_path_len = fs.base64_encoder.calcSize(random_bytes_len);
14
1519/// Note that the `Dir.atomicFile` API may be more handy than this lower-level function.
1620pub fn init(
1721 dest_basename: []const u8,
1822 mode: File.Mode,
1923 dir: Dir,
2024 close_dir_on_deinit: bool,
25 write_buffer: []u8,
2126) InitError!AtomicFile {
22 var rand_buf: [random_bytes_len]u8 = undefined;
23 var tmp_path_buf: [tmp_path_len:0]u8 = undefined;
24
2527 while (true) {
26 std.crypto.random.bytes(rand_buf[0..]);
27 const tmp_path = fs.base64_encoder.encode(&tmp_path_buf, &rand_buf);
28 tmp_path_buf[tmp_path.len] = 0;
29
30 const file = dir.createFile(
31 tmp_path,
32 .{ .mode = mode, .exclusive = true },
33 ) catch |err| switch (err) {
28 const random_integer = std.crypto.random.int(u64);
29 const tmp_sub_path = std.fmt.hex(random_integer);
30 const file = dir.createFile(&tmp_sub_path, .{ .mode = mode, .exclusive = true }) catch |err| switch (err) {
3431 error.PathAlreadyExists => continue,
3532 else => |e| return e,
3633 };
37
38 return AtomicFile{
39 .file = file,
40 .tmp_path_buf = tmp_path_buf,
34 return .{
35 .file_writer = file.writer(write_buffer),
36 .random_integer = random_integer,
4137 .dest_basename = dest_basename,
4238 .file_open = true,
4339 .file_exists = true,
......@@ -48,41 +44,51 @@ pub fn init(
4844}
4945
5046/// Always call deinit, even after a successful finish().
51pub fn deinit(self: *AtomicFile) void {
52 if (self.file_open) {
53 self.file.close();
54 self.file_open = false;
47pub fn deinit(af: *AtomicFile) void {
48 if (af.file_open) {
49 af.file_writer.file.close();
50 af.file_open = false;
5551 }
56 if (self.file_exists) {
57 self.dir.deleteFile(&self.tmp_path_buf) catch {};
58 self.file_exists = false;
52 if (af.file_exists) {
53 const tmp_sub_path = std.fmt.hex(af.random_integer);
54 af.dir.deleteFile(&tmp_sub_path) catch {};
55 af.file_exists = false;
5956 }
60 if (self.close_dir_on_deinit) {
61 self.dir.close();
57 if (af.close_dir_on_deinit) {
58 af.dir.close();
6259 }
63 self.* = undefined;
60 af.* = undefined;
6461}
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
6873/// On Windows, this function introduces a period of time where some file
6974/// system operations on the destination file will result in
7075/// `error.AccessDenied`, including rename operations (such as the one used in
7176/// this function).
72pub fn finish(self: *AtomicFile) FinishError!void {
73 assert(self.file_exists);
74 if (self.file_open) {
75 self.file.close();
76 self.file_open = false;
77pub fn renameIntoPlace(af: *AtomicFile) RenameIntoPlaceError!void {
78 assert(af.file_exists);
79 if (af.file_open) {
80 af.file_writer.file.close();
81 af.file_open = false;
7782 }
78 try posix.renameat(self.dir.fd, self.tmp_path_buf[0..], self.dir.fd, self.dest_basename);
79 self.file_exists = false;
83 const tmp_sub_path = std.fmt.hex(af.random_integer);
84 try posix.renameat(af.dir.fd, &tmp_sub_path, af.dir.fd, af.dest_basename);
85 af.file_exists = false;
8086}
8187
82const AtomicFile = @This();
83const std = @import("../std.zig");
84const File = std.fs.File;
85const Dir = std.fs.Dir;
86const fs = std.fs;
87const assert = std.debug.assert;
88const posix = std.posix;
88pub const FinishError = FlushError || RenameIntoPlaceError;
89
90/// Combination of `flush` followed by `renameIntoPlace`.
91pub fn finish(af: *AtomicFile) FinishError!void {
92 try af.flush();
93 try af.renameIntoPlace();
94}
lib/std/fs/Dir.zig+71-109
......@@ -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
118fd: Handle,
219
320pub const Handle = posix.fd_t;
......@@ -1862,9 +1879,10 @@ pub fn symLinkW(
18621879
18631880/// Same as `symLink`, except tries to create the symbolic link until it
18641881/// 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/).
1866/// On WASI, both paths should be encoded as valid UTF-8.
1867/// On other platforms, both paths are an opaque sequence of bytes with no particular encoding.
1882///
1883/// * On Windows, both paths should be encoded as [WTF-8](https://simonsapin.github.io/wtf-8/).
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.
18681886pub fn atomicSymLink(
18691887 dir: Dir,
18701888 target_path: []const u8,
......@@ -1880,9 +1898,8 @@ pub fn atomicSymLink(
18801898
18811899 const dirname = path.dirname(sym_link_path) orelse ".";
18821900
1883 var rand_buf: [AtomicFile.random_bytes_len]u8 = undefined;
1884
1885 const temp_path_len = dirname.len + 1 + base64_encoder.calcSize(rand_buf.len);
1901 const rand_len = @sizeOf(u64) * 2;
1902 const temp_path_len = dirname.len + 1 + rand_len;
18861903 var temp_path_buf: [fs.max_path_bytes]u8 = undefined;
18871904
18881905 if (temp_path_len > temp_path_buf.len) return error.NameTooLong;
......@@ -1892,8 +1909,8 @@ pub fn atomicSymLink(
18921909 const temp_path = temp_path_buf[0..temp_path_len];
18931910
18941911 while (true) {
1895 crypto.random.bytes(rand_buf[0..]);
1896 _ = base64_encoder.encode(temp_path[dirname.len + 1 ..], rand_buf[0..]);
1912 const random_integer = std.crypto.random.int(u64);
1913 temp_path[dirname.len + 1 ..][0..rand_len].* = std.fmt.hex(random_integer);
18971914
18981915 if (dir.symLink(target_path, temp_path, flags)) {
18991916 return dir.rename(temp_path, sym_link_path);
......@@ -2552,25 +2569,42 @@ pub fn updateFile(
25522569 try dest_dir.makePath(dirname);
25532570 }
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 });
25562577 defer atomic_file.deinit();
25572578
2558 try atomic_file.file.writeFileAll(src_file, .{ .in_len = src_stat.size });
2559 try atomic_file.file.updateTimes(src_stat.atime, src_stat.mtime);
2579 var src_reader: File.Reader = .initSize(src_file, &.{}, src_stat.size);
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);
25602587 try atomic_file.finish();
2561 return PrevStatus.stale;
2588 return .stale;
25622589}
25632590
25642591pub 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.
2568/// On Linux, until https://patchwork.kernel.org/patch/9636735/ is merged and readily available,
2569/// there is a possibility of power loss or application termination leaving temporary files present
2570/// in the same directory as dest_path.
2571/// On Windows, both paths should be encoded as [WTF-8](https://simonsapin.github.io/wtf-8/).
2572/// On WASI, both paths should be encoded as valid UTF-8.
2573/// On other platforms, both paths are an opaque sequence of bytes with no particular encoding.
2595/// Atomically creates a new file at `dest_path` within `dest_dir` with the
2596/// same contents as `source_path` within `source_dir`, overwriting any already
2597/// existing file.
2598///
2599/// On Linux, until https://patchwork.kernel.org/patch/9636735/ is merged and
2600/// readily available, there is a possibility of power loss or application
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.
25742608pub fn copyFile(
25752609 source_dir: Dir,
25762610 source_path: []const u8,
......@@ -2578,79 +2612,34 @@ pub fn copyFile(
25782612 dest_path: []const u8,
25792613 options: CopyFileOptions,
25802614) CopyFileError!void {
2581 var in_file = try source_dir.openFile(source_path, .{});
2582 defer in_file.close();
2615 var file_reader: File.Reader = .init(try source_dir.openFile(source_path, .{}), &.{});
2616 defer file_reader.file.close();
25832617
2584 var size: ?u64 = null;
25852618 const mode = options.override_mode orelse blk: {
2586 const st = try in_file.stat();
2587 size = st.size;
2619 const st = try file_reader.file.stat();
2620 file_reader.size = st.size;
25882621 break :blk st.mode;
25892622 };
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 });
25922629 defer atomic_file.deinit();
25932630
2594 try copy_file(in_file.handle, atomic_file.file.handle, size);
2595 try atomic_file.finish();
2596}
2597
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 }
2631 _ = atomic_file.file_writer.interface.sendFileAll(&file_reader, .unlimited) catch |err| switch (err) {
2632 error.ReadFailed => return file_reader.err.?,
2633 error.WriteFailed => return atomic_file.file_writer.err.?,
2634 };
26352635
2636 // Sendfile is a zero-copy mechanism iff the OS supports it, otherwise the
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 }
2636 try atomic_file.finish();
26492637}
26502638
26512639pub const AtomicFileOptions = struct {
26522640 mode: File.Mode = File.default_mode,
26532641 make_path: bool = false,
2642 write_buffer: []u8,
26542643};
26552644
26562645/// 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)
26682657 else
26692658 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);
26722661 } else {
2673 return AtomicFile.init(dest_path, options.mode, self, false);
2662 return .init(dest_path, options.mode, self, false, options.write_buffer);
26742663 }
26752664}
26762665
......@@ -2768,30 +2757,3 @@ pub fn setPermissions(self: Dir, permissions: Permissions) SetPermissionsError!v
27682757 const file: File = .{ .handle = self.fd };
27692758 try file.setPermissions(permissions);
27702759}
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
10891089 return total_bytes_copied;
10901090}
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
11991092/// Deprecated in favor of `Reader`.
12001093pub const DeprecatedReader = io.GenericReader(File, ReadError, read);
12011094
......@@ -1242,7 +1135,7 @@ pub const Reader = struct {
12421135 err: ?ReadError = null,
12431136 mode: Reader.Mode = .positional,
12441137 /// 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`.
12461139 pos: u64 = 0,
12471140 size: ?u64 = null,
12481141 size_err: ?GetEndPosError = null,
......@@ -1335,14 +1228,12 @@ pub const Reader = struct {
13351228 pub fn seekBy(r: *Reader, offset: i64) Reader.SeekError!void {
13361229 switch (r.mode) {
13371230 .positional, .positional_reading => {
1338 // TODO: make += operator allow any integer types
1339 r.pos = @intCast(@as(i64, @intCast(r.pos)) + offset);
1231 setPosAdjustingBuffer(r, @intCast(@as(i64, @intCast(r.pos)) + offset));
13401232 },
13411233 .streaming, .streaming_reading => {
13421234 const seek_err = r.seek_err orelse e: {
13431235 if (posix.lseek_CUR(r.file.handle, offset)) |_| {
1344 // TODO: make += operator allow any integer types
1345 r.pos = @intCast(@as(i64, @intCast(r.pos)) + offset);
1236 setPosAdjustingBuffer(r, @intCast(@as(i64, @intCast(r.pos)) + offset));
13461237 return;
13471238 } else |err| {
13481239 r.seek_err = err;
......@@ -1358,6 +1249,8 @@ pub const Reader = struct {
13581249 r.pos += n;
13591250 remaining -= n;
13601251 }
1252 r.interface.seek = 0;
1253 r.interface.end = 0;
13611254 },
13621255 .failure => return r.seek_err.?,
13631256 }
......@@ -1366,7 +1259,7 @@ pub const Reader = struct {
13661259 pub fn seekTo(r: *Reader, offset: u64) Reader.SeekError!void {
13671260 switch (r.mode) {
13681261 .positional, .positional_reading => {
1369 r.pos = offset;
1262 setPosAdjustingBuffer(r, offset);
13701263 },
13711264 .streaming, .streaming_reading => {
13721265 if (offset >= r.pos) return Reader.seekBy(r, @intCast(offset - r.pos));
......@@ -1375,12 +1268,28 @@ pub const Reader = struct {
13751268 r.seek_err = err;
13761269 return err;
13771270 };
1378 r.pos = offset;
1271 setPosAdjustingBuffer(r, offset);
13791272 },
13801273 .failure => return r.seek_err.?,
13811274 }
13821275 }
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
13841293 /// Number of slices to store on the stack, when trying to send as many byte
13851294 /// vectors through the underlying read calls as possible.
13861295 const max_buffers_len = 16;
......@@ -1526,7 +1435,7 @@ pub const Reader = struct {
15261435 }
15271436 return 0;
15281437 };
1529 const n = @min(size - pos, std.math.maxInt(i64), @intFromEnum(limit));
1438 const n = @min(size - pos, maxInt(i64), @intFromEnum(limit));
15301439 file.seekBy(n) catch |err| {
15311440 r.seek_err = err;
15321441 return 0;
......@@ -1645,7 +1554,10 @@ pub const Writer = struct {
16451554 return .{
16461555 .vtable = &.{
16471556 .drain = drain,
1648 .sendFile = sendFile,
1557 .sendFile = switch (builtin.zig_backend) {
1558 else => sendFile,
1559 .stage2_aarch64 => std.io.Writer.unimplementedSendFile,
1560 },
16491561 },
16501562 .buffer = buffer,
16511563 };
......@@ -1715,7 +1627,6 @@ pub const Writer = struct {
17151627 const pattern = data[data.len - 1];
17161628 if (pattern.len == 0 or splat == 0) return 0;
17171629 const n = windows.WriteFile(handle, pattern, null) catch |err| {
1718 std.debug.print("windows write file failed3: {t}\n", .{err});
17191630 w.err = err;
17201631 return error.WriteFailed;
17211632 };
......@@ -1817,18 +1728,141 @@ pub const Writer = struct {
18171728 file_reader: *Reader,
18181729 limit: std.io.Limit,
18191730 ) 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;
18201736 const w: *Writer = @alignCast(@fieldParentPtr("interface", io_w));
18211737 const out_fd = w.file.handle;
18221738 const in_fd = file_reader.file.handle;
1823 // TODO try using copy_file_range on FreeBSD
1824 // TODO try using sendfile on macOS
1825 // TODO try using sendfile on FreeBSD
1739
1740 if (file_reader.size) |size| {
1741 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
18261860 if (native_os == .linux and w.mode == .streaming) sf: {
18271861 // Try using sendfile on Linux.
18281862 if (w.sendfile_err != null) break :sf;
18291863 // Linux sendfile does not support headers.
1830 const buffered = limit.slice(file_reader.interface.buffer);
1831 if (io_w.end != 0 or buffered.len != 0) return drain(io_w, &.{buffered}, 1);
1864 if (writer_buffered.len != 0 or reader_buffered.len != 0)
1865 return sendFileBuffered(io_w, file_reader, reader_buffered);
18321866 const max_count = 0x7ffff000; // Avoid EINVAL.
18331867 var off: std.os.linux.off_t = undefined;
18341868 const off_ptr: ?*std.os.linux.off_t, const count: usize = switch (file_reader.mode) {
......@@ -1875,6 +1909,7 @@ pub const Writer = struct {
18751909 w.pos += n;
18761910 return n;
18771911 }
1912
18781913 const copy_file_range = switch (native_os) {
18791914 .freebsd => std.os.freebsd.copy_file_range,
18801915 .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 {
18821917 };
18831918 if (@TypeOf(copy_file_range) != void) cfr: {
18841919 if (w.copy_file_range_err != null) break :cfr;
1885 const buffered = limit.slice(file_reader.interface.buffer);
1886 if (io_w.end != 0 or buffered.len != 0) return drain(io_w, &.{buffered}, 1);
1920 if (writer_buffered.len != 0 or reader_buffered.len != 0)
1921 return sendFileBuffered(io_w, file_reader, reader_buffered);
18871922 var off_in: i64 = undefined;
18881923 var off_out: i64 = undefined;
18891924 const off_in_ptr: ?*i64 = switch (file_reader.mode) {
......@@ -1922,6 +1957,9 @@ pub const Writer = struct {
19221957 if (file_reader.pos != 0) break :fcf;
19231958 if (w.pos != 0) break :fcf;
19241959 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);
19251963 const rc = std.c.fcopyfile(in_fd, out_fd, null, .{ .DATA = true });
19261964 switch (posix.errno(rc)) {
19271965 .SUCCESS => {},
......@@ -1942,15 +1980,24 @@ pub const Writer = struct {
19421980 return 0;
19431981 },
19441982 }
1945 const n = if (file_reader.size) |size| size else @panic("TODO figure out how much copied");
1946 file_reader.pos = n;
1947 w.pos = n;
1948 return n;
1983 file_reader.pos = size;
1984 w.pos = size;
1985 return size;
19491986 }
19501987
19511988 return error.Unimplemented;
19521989 }
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
19542001 pub fn seekTo(w: *Writer, offset: u64) SeekError!void {
19552002 switch (w.mode) {
19562003 .positional, .positional_reading => {
......@@ -1979,7 +2026,19 @@ pub const Writer = struct {
19792026 /// along with other write failures.
19802027 pub fn end(w: *Writer) EndError!void {
19812028 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 }
19832042 }
19842043};
19852044
lib/std/fs/test.zig+57-29
......@@ -1499,32 +1499,18 @@ test "sendfile" {
14991499 const header2 = "second header\n";
15001500 const trailer1 = "trailer1\n";
15011501 const trailer2 = "second trailer\n";
1502 var hdtr = [_]posix.iovec_const{
1503 .{
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 };
1502 var headers: [2][]const u8 = .{ header1, header2 };
1503 var trailers: [2][]const u8 = .{ trailer1, trailer2 };
15201504
15211505 var written_buf: [100]u8 = undefined;
1522 try dest_file.writeFileAll(src_file, .{
1523 .in_offset = 1,
1524 .in_len = 10,
1525 .headers_and_trailers = &hdtr,
1526 .header_count = 2,
1527 });
1506 var file_reader = src_file.reader(&.{});
1507 var fallback_buffer: [50]u8 = undefined;
1508 var file_writer = dest_file.writer(&fallback_buffer);
1509 try file_writer.interface.writeVecAll(&headers);
1510 try file_reader.seekTo(1);
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();
15281514 const amt = try dest_file.preadAll(&written_buf, 0);
15291515 try testing.expectEqualStrings("header1\nsecond header\nine1\nsecontrailer1\nsecond trailer\n", written_buf[0..amt]);
15301516}
......@@ -1595,9 +1581,10 @@ test "AtomicFile" {
15951581 ;
15961582
15971583 {
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 });
15991586 defer af.deinit();
1600 try af.file.writeAll(test_content);
1587 try af.file_writer.interface.writeAll(test_content);
16011588 try af.finish();
16021589 }
16031590 const content = try ctx.dir.readFileAlloc(allocator, test_out_file, 9999);
......@@ -2073,7 +2060,7 @@ test "invalid UTF-8/WTF-8 paths" {
20732060}
20742061
20752062test "read file non vectored" {
2076 var tmp_dir = std.testing.tmpDir(.{});
2063 var tmp_dir = testing.tmpDir(.{});
20772064 defer tmp_dir.cleanup();
20782065
20792066 const contents = "hello, world!\n";
......@@ -2098,6 +2085,47 @@ test "read file non vectored" {
20982085 else => |e| return e,
20992086 };
21002087 }
2101 try std.testing.expectEqualStrings(contents, w.buffered());
2102 try std.testing.expectEqual(contents.len, i);
2088 try testing.expectEqualStrings(contents, w.buffered());
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);
21032131}
lib/std/http/Server.zig+1-2
......@@ -129,11 +129,10 @@ pub const Request = struct {
129129 pub const Compression = union(enum) {
130130 pub const DeflateDecompressor = std.compress.zlib.Decompressor(std.io.AnyReader);
131131 pub const GzipDecompressor = std.compress.gzip.Decompressor(std.io.AnyReader);
132 pub const ZstdDecompressor = std.compress.zstd.Decompressor(std.io.AnyReader);
133132
134133 deflate: DeflateDecompressor,
135134 gzip: GzipDecompressor,
136 zstd: ZstdDecompressor,
135 zstd: std.compress.zstd.Decompress,
137136 none: void,
138137 };
139138
lib/std/json.zig-1
......@@ -69,7 +69,6 @@ pub const ArrayHashMap = @import("json/hashmap.zig").ArrayHashMap;
6969pub const Scanner = @import("json/Scanner.zig");
7070pub const validate = Scanner.validate;
7171pub const Error = Scanner.Error;
72pub const reader = Scanner.reader;
7372pub const default_buffer_size = Scanner.default_buffer_size;
7473pub const Token = Scanner.Token;
7574pub const TokenType = Scanner.TokenType;
lib/std/math.zig+55-38
......@@ -45,6 +45,7 @@ pub const rad_per_deg = 0.017453292519943295769236907684886127134428718885417254
4545/// 180.0/pi
4646pub const deg_per_rad = 57.295779513082320876798154814105170332405472466564321549160243861;
4747
48pub const Sign = enum(u1) { positive, negative };
4849pub const FloatRepr = float.FloatRepr;
4950pub const floatExponentBits = float.floatExponentBits;
5051pub const floatMantissaBits = float.floatMantissaBits;
......@@ -594,27 +595,30 @@ pub fn shlExact(comptime T: type, a: T, shift_amt: Log2Int(T)) !T {
594595/// Shifts left. Overflowed bits are truncated.
595596/// A negative shift amount results in a right shift.
596597pub fn shl(comptime T: type, a: T, shift_amt: anytype) T {
598 const is_shl = shift_amt >= 0;
597599 const abs_shift_amt = @abs(shift_amt);
598
599 const casted_shift_amt = blk: {
600 if (@typeInfo(T) == .vector) {
601 const C = @typeInfo(T).vector.child;
602 const len = @typeInfo(T).vector.len;
603 if (abs_shift_amt >= @typeInfo(C).int.bits) return @splat(0);
604 break :blk @as(@Vector(len, Log2Int(C)), @splat(@as(Log2Int(C), @intCast(abs_shift_amt))));
605 } else {
606 if (abs_shift_amt >= @typeInfo(T).int.bits) return 0;
607 break :blk @as(Log2Int(T), @intCast(abs_shift_amt));
608 }
600 const casted_shift_amt = casted_shift_amt: switch (@typeInfo(T)) {
601 .int => |info| {
602 if (abs_shift_amt < info.bits) break :casted_shift_amt @as(
603 Log2Int(T),
604 @intCast(abs_shift_amt),
605 );
606 if (info.signedness == .unsigned or is_shl) return 0;
607 return a >> (info.bits - 1);
608 },
609 .vector => |info| {
610 const Child = info.child;
611 const child_info = @typeInfo(Child).int;
612 if (abs_shift_amt < child_info.bits) break :casted_shift_amt @as(
613 @Vector(info.len, Log2Int(Child)),
614 @splat(@as(Log2Int(Child), @intCast(abs_shift_amt))),
615 );
616 if (child_info.signedness == .unsigned or is_shl) return @splat(0);
617 return a >> @splat(child_info.bits - 1);
618 },
619 else => comptime unreachable,
609620 };
610
611 if (@TypeOf(shift_amt) == comptime_int or @typeInfo(@TypeOf(shift_amt)).int.signedness == .signed) {
612 if (shift_amt < 0) {
613 return a >> casted_shift_amt;
614 }
615 }
616
617 return a << casted_shift_amt;
621 return if (is_shl) a << casted_shift_amt else a >> casted_shift_amt;
618622}
619623
620624test shl {
......@@ -629,32 +633,40 @@ test shl {
629633 try testing.expect(shl(@Vector(1, u32), @Vector(1, u32){42}, @as(usize, 1))[0] == @as(u32, 42) << 1);
630634 try testing.expect(shl(@Vector(1, u32), @Vector(1, u32){42}, @as(isize, -1))[0] == @as(u32, 42) >> 1);
631635 try testing.expect(shl(@Vector(1, u32), @Vector(1, u32){42}, 33)[0] == 0);
636
637 try testing.expect(shl(i8, -1, -100) == -1);
638 try testing.expect(shl(i8, -1, 100) == 0);
639 try testing.expect(@reduce(.And, shl(@Vector(2, i8), .{ -1, 1 }, -100) == @Vector(2, i8){ -1, 0 }));
640 try testing.expect(@reduce(.And, shl(@Vector(2, i8), .{ -1, 1 }, 100) == @Vector(2, i8){ 0, 0 }));
632641}
633642
634643/// Shifts right. Overflowed bits are truncated.
635644/// A negative shift amount results in a left shift.
636645pub fn shr(comptime T: type, a: T, shift_amt: anytype) T {
646 const is_shl = shift_amt < 0;
637647 const abs_shift_amt = @abs(shift_amt);
638
639 const casted_shift_amt = blk: {
640 if (@typeInfo(T) == .vector) {
641 const C = @typeInfo(T).vector.child;
642 const len = @typeInfo(T).vector.len;
643 if (abs_shift_amt >= @typeInfo(C).int.bits) return @splat(0);
644 break :blk @as(@Vector(len, Log2Int(C)), @splat(@as(Log2Int(C), @intCast(abs_shift_amt))));
645 } else {
646 if (abs_shift_amt >= @typeInfo(T).int.bits) return 0;
647 break :blk @as(Log2Int(T), @intCast(abs_shift_amt));
648 }
648 const casted_shift_amt = casted_shift_amt: switch (@typeInfo(T)) {
649 .int => |info| {
650 if (abs_shift_amt < info.bits) break :casted_shift_amt @as(
651 Log2Int(T),
652 @intCast(abs_shift_amt),
653 );
654 if (info.signedness == .unsigned or is_shl) return 0;
655 return a >> (info.bits - 1);
656 },
657 .vector => |info| {
658 const Child = info.child;
659 const child_info = @typeInfo(Child).int;
660 if (abs_shift_amt < child_info.bits) break :casted_shift_amt @as(
661 @Vector(info.len, Log2Int(Child)),
662 @splat(@as(Log2Int(Child), @intCast(abs_shift_amt))),
663 );
664 if (child_info.signedness == .unsigned or is_shl) return @splat(0);
665 return a >> @splat(child_info.bits - 1);
666 },
667 else => comptime unreachable,
649668 };
650
651 if (@TypeOf(shift_amt) == comptime_int or @typeInfo(@TypeOf(shift_amt)).int.signedness == .signed) {
652 if (shift_amt < 0) {
653 return a << casted_shift_amt;
654 }
655 }
656
657 return a >> casted_shift_amt;
669 return if (is_shl) a << casted_shift_amt else a >> casted_shift_amt;
658670}
659671
660672test shr {
......@@ -669,6 +681,11 @@ test shr {
669681 try testing.expect(shr(@Vector(1, u32), @Vector(1, u32){42}, @as(usize, 1))[0] == @as(u32, 42) >> 1);
670682 try testing.expect(shr(@Vector(1, u32), @Vector(1, u32){42}, @as(isize, -1))[0] == @as(u32, 42) << 1);
671683 try testing.expect(shr(@Vector(1, u32), @Vector(1, u32){42}, 33)[0] == 0);
684
685 try testing.expect(shr(i8, -1, -100) == 0);
686 try testing.expect(shr(i8, -1, 100) == -1);
687 try testing.expect(@reduce(.And, shr(@Vector(2, i8), .{ -1, 1 }, -100) == @Vector(2, i8){ 0, 0 }));
688 try testing.expect(@reduce(.And, shr(@Vector(2, i8), .{ -1, 1 }, 100) == @Vector(2, i8){ -1, 0 }));
672689}
673690
674691/// Rotates right. Only unsigned values can be rotated. Negative shift
lib/std/math/big/int_test.zig-1
......@@ -2774,7 +2774,6 @@ test "bitNotWrap more than two limbs" {
27742774 // This test requires int sizes greater than 128 bits.
27752775 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
27762776 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
2777 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
27782777 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
27792778 // LLVM: unexpected runtime library name: __umodei4
27802779 if (builtin.zig_backend == .stage2_llvm and comptime builtin.target.cpu.arch.isWasm()) return error.SkipZigTest; // TODO
lib/std/math/float.zig+2-4
......@@ -4,8 +4,6 @@ const assert = std.debug.assert;
44const expect = std.testing.expect;
55const expectEqual = std.testing.expectEqual;
66
7pub const Sign = enum(u1) { positive, negative };
8
97pub fn FloatRepr(comptime Float: type) type {
108 const fractional_bits = floatFractionalBits(Float);
119 const exponent_bits = floatExponentBits(Float);
......@@ -14,7 +12,7 @@ pub fn FloatRepr(comptime Float: type) type {
1412
1513 mantissa: StoredMantissa,
1614 exponent: BiasedExponent,
17 sign: Sign,
15 sign: std.math.Sign,
1816
1917 pub const StoredMantissa = @Type(.{ .int = .{
2018 .signedness = .unsigned,
......@@ -69,7 +67,7 @@ pub fn FloatRepr(comptime Float: type) type {
6967
7068 /// This currently truncates denormal values, which needs to be fixed before this can be used to
7169 /// produce a rounded value.
72 pub fn reconstruct(normalized: Normalized, sign: Sign) Float {
70 pub fn reconstruct(normalized: Normalized, sign: std.math.Sign) Float {
7371 if (normalized.exponent > BiasedExponent.max_normal.unbias()) return @bitCast(Repr{
7472 .mantissa = 0,
7573 .exponent = .infinite,
lib/std/math/log10.zig-1
......@@ -132,7 +132,6 @@ inline fn less_than_5(x: u32) u32 {
132132test log10_int {
133133 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
134134 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
135 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
136135 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
137136 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
138137 if (builtin.zig_backend == .stage2_llvm and comptime builtin.target.cpu.arch.isWasm()) return error.SkipZigTest; // TODO
lib/std/mem.zig+4-3
......@@ -676,6 +676,7 @@ test lessThan {
676676
677677const eqlBytes_allowed = switch (builtin.zig_backend) {
678678 // These backends don't support vectors yet.
679 .stage2_aarch64,
679680 .stage2_powerpc,
680681 .stage2_riscv64,
681682 => false,
......@@ -4482,7 +4483,7 @@ pub fn doNotOptimizeAway(val: anytype) void {
44824483 );
44834484 asm volatile (""
44844485 :
4485 : [val2] "r" (val2),
4486 : [_] "r" (val2),
44864487 );
44874488 } else doNotOptimizeAway(&val);
44884489 },
......@@ -4490,7 +4491,7 @@ pub fn doNotOptimizeAway(val: anytype) void {
44904491 if ((t.float.bits == 32 or t.float.bits == 64) and builtin.zig_backend != .stage2_c) {
44914492 asm volatile (""
44924493 :
4493 : [val] "rm" (val),
4494 : [_] "rm" (val),
44944495 );
44954496 } else doNotOptimizeAway(&val);
44964497 },
......@@ -4500,7 +4501,7 @@ pub fn doNotOptimizeAway(val: anytype) void {
45004501 } else {
45014502 asm volatile (""
45024503 :
4503 : [val] "m" (val),
4504 : [_] "m" (val),
45044505 : .{ .memory = true });
45054506 }
45064507 },
lib/std/os/linux.zig-1
......@@ -503,7 +503,6 @@ pub var elf_aux_maybe: ?[*]std.elf.Auxv = null;
503503/// Whether an external or internal getauxval implementation is used.
504504const extern_getauxval = switch (builtin.zig_backend) {
505505 // Calling extern functions is not yet supported with these backends
506 .stage2_aarch64,
507506 .stage2_arm,
508507 .stage2_powerpc,
509508 .stage2_riscv64,
lib/std/posix.zig+24-295
......@@ -192,10 +192,27 @@ pub const iovec_const = extern struct {
192192 len: usize,
193193};
194194
195pub const ACCMODE = enum(u2) {
196 RDONLY = 0,
197 WRONLY = 1,
198 RDWR = 2,
195pub const ACCMODE = switch (native_os) {
196 // POSIX has a note about the access mode values:
197 //
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 },
199216};
200217
201218pub const TCSA = enum(c_uint) {
......@@ -1035,6 +1052,7 @@ pub const TruncateError = error{
10351052 FileBusy,
10361053 AccessDenied,
10371054 PermissionDenied,
1055 NonResizable,
10381056} || UnexpectedError;
10391057
10401058/// Length must be positive when treated as an i64.
......@@ -1074,7 +1092,7 @@ pub fn ftruncate(fd: fd_t, length: u64) TruncateError!void {
10741092 .PERM => return error.PermissionDenied,
10751093 .TXTBSY => return error.FileBusy,
10761094 .BADF => unreachable, // Handle not open for writing
1077 .INVAL => unreachable, // Handle not open for writing, negative length, or non-resizable handle
1095 .INVAL => return error.NonResizable,
10781096 .NOTCAPABLE => return error.AccessDenied,
10791097 else => |err| return unexpectedErrno(err),
10801098 }
......@@ -1090,7 +1108,7 @@ pub fn ftruncate(fd: fd_t, length: u64) TruncateError!void {
10901108 .PERM => return error.PermissionDenied,
10911109 .TXTBSY => return error.FileBusy,
10921110 .BADF => unreachable, // Handle not open for writing
1093 .INVAL => unreachable, // Handle not open for writing, negative length, or non-resizable handle
1111 .INVAL => return error.NonResizable, // This is returned for /dev/null for example.
10941112 else => |err| return unexpectedErrno(err),
10951113 }
10961114 }
......@@ -6326,295 +6344,6 @@ pub fn send(
63266344 };
63276345}
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
66186347pub const CopyFileRangeError = error{
66196348 FileTooBig,
66206349 InputOutput,
lib/std/process/Child.zig+46-35
......@@ -14,6 +14,7 @@ const assert = std.debug.assert;
1414const native_os = builtin.os.tag;
1515const Allocator = std.mem.Allocator;
1616const ChildProcess = @This();
17const ArrayList = std.ArrayListUnmanaged;
1718
1819pub const Id = switch (native_os) {
1920 .windows => windows.HANDLE,
......@@ -348,19 +349,6 @@ pub const RunResult = struct {
348349 stderr: []u8,
349350};
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
364352/// Collect the output from the process's stdout and stderr. Will return once all output
365353/// has been collected. This does not mean that the process has ended. `wait` should still
366354/// be called to wait for and clean up the process.
......@@ -370,28 +358,48 @@ pub fn collectOutput(
370358 child: ChildProcess,
371359 /// Used for `stdout` and `stderr`.
372360 allocator: Allocator,
373 stdout: *std.ArrayListUnmanaged(u8),
374 stderr: *std.ArrayListUnmanaged(u8),
361 stdout: *ArrayList(u8),
362 stderr: *ArrayList(u8),
375363 max_output_bytes: usize,
376364) !void {
377365 assert(child.stdout_behavior == .Pipe);
378366 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 }, .{
381369 .stdout = child.stdout.?,
382370 .stderr = child.stderr.?,
383371 });
384372 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
386397 while (try poller.poll()) {
387 if (poller.fifo(.stdout).count > max_output_bytes)
398 if (stdout_r.bufferedLen() > max_output_bytes)
388399 return error.StdoutStreamTooLong;
389 if (poller.fifo(.stderr).count > max_output_bytes)
400 if (stderr_r.bufferedLen() > max_output_bytes)
390401 return error.StderrStreamTooLong;
391402 }
392
393 try writeFifoDataToArrayList(allocator, stdout, poller.fifo(.stdout));
394 try writeFifoDataToArrayList(allocator, stderr, poller.fifo(.stderr));
395403}
396404
397405pub const RunError = posix.GetCwdError || posix.ReadError || SpawnError || posix.PollError || error{
......@@ -421,10 +429,10 @@ pub fn run(args: struct {
421429 child.expand_arg0 = args.expand_arg0;
422430 child.progress_node = args.progress_node;
423431
424 var stdout: std.ArrayListUnmanaged(u8) = .empty;
425 errdefer stdout.deinit(args.allocator);
426 var stderr: std.ArrayListUnmanaged(u8) = .empty;
427 errdefer stderr.deinit(args.allocator);
432 var stdout: ArrayList(u8) = .empty;
433 defer stdout.deinit(args.allocator);
434 var stderr: ArrayList(u8) = .empty;
435 defer stderr.deinit(args.allocator);
428436
429437 try child.spawn();
430438 errdefer {
......@@ -432,7 +440,7 @@ pub fn run(args: struct {
432440 }
433441 try child.collectOutput(args.allocator, &stdout, &stderr, args.max_output_bytes);
434442
435 return RunResult{
443 return .{
436444 .stdout = try stdout.toOwnedSlice(args.allocator),
437445 .stderr = try stderr.toOwnedSlice(args.allocator),
438446 .term = try child.wait(),
......@@ -878,12 +886,12 @@ fn spawnWindows(self: *ChildProcess) SpawnError!void {
878886 var cmd_line_cache = WindowsCommandLineCache.init(self.allocator, self.argv);
879887 defer cmd_line_cache.deinit();
880888
881 var app_buf: std.ArrayListUnmanaged(u16) = .empty;
889 var app_buf: ArrayList(u16) = .empty;
882890 defer app_buf.deinit(self.allocator);
883891
884892 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;
887895 defer dir_buf.deinit(self.allocator);
888896
889897 if (cwd_path_w.len > 0) {
......@@ -1003,13 +1011,16 @@ fn forkChildErrReport(fd: i32, err: ChildProcess.SpawnError) noreturn {
10031011}
10041012
10051013fn writeIntFd(fd: i32, value: ErrInt) !void {
1006 const file: File = .{ .handle = fd };
1007 file.deprecatedWriter().writeInt(u64, @intCast(value), .little) catch return error.SystemResources;
1014 var buffer: [8]u8 = undefined;
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;
10081018}
10091019
10101020fn readIntFd(fd: i32) !ErrInt {
1011 const file: File = .{ .handle = fd };
1012 return @intCast(file.deprecatedReader().readInt(u64, .little) catch return error.SystemResources);
1021 var buffer: [8]u8 = undefined;
1022 var fr: std.fs.File.Reader = .initMode(.{ .handle = fd }, &buffer, .streaming);
1023 return @intCast(fr.interface.takeInt(u64, .little) catch return error.SystemResources);
10131024}
10141025
10151026const ErrInt = std.meta.Int(.unsigned, @sizeOf(anyerror) * 8);
......@@ -1020,8 +1031,8 @@ const ErrInt = std.meta.Int(.unsigned, @sizeOf(anyerror) * 8);
10201031/// Note: If the dir is the cwd, dir_buf should be empty (len = 0).
10211032fn windowsCreateProcessPathExt(
10221033 allocator: mem.Allocator,
1023 dir_buf: *std.ArrayListUnmanaged(u16),
1024 app_buf: *std.ArrayListUnmanaged(u16),
1034 dir_buf: *ArrayList(u16),
1035 app_buf: *ArrayList(u16),
10251036 pathext: [:0]const u16,
10261037 cmd_line_cache: *WindowsCommandLineCache,
10271038 envp_ptr: ?[*]u16,
......@@ -1504,7 +1515,7 @@ const WindowsCommandLineCache = struct {
15041515/// Returns the absolute path of `cmd.exe` within the Windows system directory.
15051516/// The caller owns the returned slice.
15061517fn 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);
15081519 errdefer buf.deinit(allocator);
15091520 while (true) {
15101521 const unused_slice = buf.unusedCapacitySlice();
lib/std/start.zig+5-54
......@@ -101,17 +101,11 @@ comptime {
101101// Simplified start code for stage2 until it supports more language features ///
102102
103103fn main2() callconv(.c) c_int {
104 root.main();
105 return 0;
104 return callMain();
106105}
107106
108107fn _start2() callconv(.withStackAlign(.c, 1)) noreturn {
109 callMain2();
110}
111
112fn callMain2() noreturn {
113 root.main();
114 exit2(0);
108 std.posix.exit(callMain());
115109}
116110
117111fn spirvMain2() callconv(.kernel) void {
......@@ -119,51 +113,7 @@ fn spirvMain2() callconv(.kernel) void {
119113}
120114
121115fn wWinMainCRTStartup2() callconv(.c) noreturn {
122 root.main();
123 exit2(0);
124}
125
126fn exit2(code: usize) noreturn {
127 switch (native_os) {
128 .linux => switch (builtin.cpu.arch) {
129 .x86_64 => {
130 asm volatile ("syscall"
131 :
132 : [number] "{rax}" (231),
133 [arg1] "{rdi}" (code),
134 : .{ .rcx = true, .r11 = true, .memory = true });
135 },
136 .arm => {
137 asm volatile ("svc #0"
138 :
139 : [number] "{r7}" (1),
140 [arg1] "{r0}" (code),
141 : .{ .memory = true });
142 },
143 .aarch64 => {
144 asm volatile ("svc #0"
145 :
146 : [number] "{x8}" (93),
147 [arg1] "{x0}" (code),
148 : .{ .memory = true });
149 },
150 .sparc64 => {
151 asm volatile ("ta 0x6d"
152 :
153 : [number] "{g1}" (1),
154 [arg1] "{o0}" (code),
155 : .{ .o0 = true, .o1 = true, .o2 = true, .o3 = true, .o4 = true, .o5 = true, .o6 = true, .o7 = true, .memory = true });
156 },
157 else => @compileError("TODO"),
158 },
159 // exits(0)
160 .plan9 => std.os.plan9.exits(null),
161 .windows => {
162 std.os.windows.ntdll.RtlExitUserProcess(@truncate(code));
163 },
164 else => @compileError("TODO"),
165 }
166 unreachable;
116 std.posix.exit(callMain());
167117}
168118
169119////////////////////////////////////////////////////////////////////////////////
......@@ -676,10 +626,11 @@ pub inline fn callMain() u8 {
676626
677627 const result = root.main() catch |err| {
678628 switch (builtin.zig_backend) {
629 .stage2_aarch64,
679630 .stage2_powerpc,
680631 .stage2_riscv64,
681632 => {
682 std.debug.print("error: failed with error\n", .{});
633 _ = std.posix.write(std.posix.STDERR_FILENO, "error: failed with error\n") catch {};
683634 return 1;
684635 },
685636 else => {},
lib/std/tar.zig+283-329
......@@ -19,7 +19,7 @@ const std = @import("std");
1919const assert = std.debug.assert;
2020const testing = std.testing;
2121
22pub const writer = @import("tar/writer.zig").writer;
22pub const Writer = @import("tar/Writer.zig");
2323
2424/// Provide this to receive detailed error messages.
2525/// When this is provided, some errors which would otherwise be returned
......@@ -293,28 +293,6 @@ fn nullStr(str: []const u8) []const u8 {
293293 return str;
294294}
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
318296/// Type of the file returned by iterator `next` method.
319297pub const FileKind = enum {
320298 directory,
......@@ -323,206 +301,192 @@ pub const FileKind = enum {
323301};
324302
325303/// Iterator over entries in the tar file represented by reader.
326pub fn Iterator(comptime ReaderType: type) type {
327 return struct {
328 reader: ReaderType,
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);
304pub const Iterator = struct {
305 reader: *std.Io.Reader,
306 diagnostics: ?*Diagnostics = null,
352307
353 pub fn reader(self: File) Reader {
354 return .{ .context = self };
355 }
308 // buffers for heeader and file attributes
309 header_buffer: [Header.SIZE]u8 = undefined,
310 file_name_buffer: []u8,
311 link_name_buffer: []u8,
356312
357 pub fn read(self: File, dest: []u8) ReaderType.Error!usize {
358 const buf = dest[0..@min(dest.len, self.unread_bytes.*)];
359 const n = try self.parent_reader.read(buf);
360 self.unread_bytes.* -= n;
361 return n;
362 }
313 // bytes of padding to the end of the block
314 padding: usize = 0,
315 // not consumed bytes of file from last next iteration
316 unread_file_bytes: u64 = 0,
363317
364 // Writes file content to writer.
365 pub fn writeAll(self: File, out_writer: anytype) !void {
366 var buffer: [4096]u8 = undefined;
318 /// Options for iterator.
319 /// Buffers should be provided by the caller.
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) {
369 const buf = buffer[0..@min(buffer.len, self.unread_bytes.*)];
370 try self.parent_reader.readNoEof(buf);
371 try out_writer.writeAll(buf);
372 self.unread_bytes.* -= buf.len;
373 }
374 }
329 /// Iterates over files in tar archive.
330 /// `next` returns each file in tar archive.
331 pub fn init(reader: *std.Io.Reader, options: Options) Iterator {
332 return .{
333 .reader = reader,
334 .diagnostics = options.diagnostics,
335 .file_name_buffer = options.file_name_buffer,
336 .link_name_buffer = options.link_name_buffer,
375337 };
338 }
376339
377 const Self = @This();
378
379 fn readHeader(self: *Self) !?Header {
380 if (self.padding > 0) {
381 try self.reader.skipBytes(self.padding, .{});
382 }
383 const n = try self.reader.readAll(&self.header_buffer);
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 }
340 pub const File = struct {
341 name: []const u8, // name of file, symlink or directory
342 link_name: []const u8, // target name of symlink
343 size: u64 = 0, // size of the file in bytes
344 mode: u32 = 0,
345 kind: FileKind = .file,
346 };
390347
391 fn readString(self: *Self, size: usize, buffer: []u8) ![]const u8 {
392 if (size > buffer.len) return error.TarInsufficientBuffer;
393 const buf = buffer[0..size];
394 try self.reader.readNoEof(buf);
395 return nullStr(buf);
348 fn readHeader(self: *Iterator) !?Header {
349 if (self.padding > 0) {
350 try self.reader.discardAll(self.padding);
396351 }
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 {
399 return .{
400 .name = self.file_name_buffer[0..0],
401 .link_name = self.link_name_buffer[0..0],
402 .parent_reader = self.reader,
403 .unread_bytes = &self.unread_file_bytes,
404 };
405 }
360 fn readString(self: *Iterator, size: usize, buffer: []u8) ![]const u8 {
361 if (size > buffer.len) return error.TarInsufficientBuffer;
362 const buf = buffer[0..size];
363 try self.reader.readSliceAll(buf);
364 return nullStr(buf);
365 }
406366
407 // Number of padding bytes in the last file block.
408 fn blockPadding(size: u64) usize {
409 const block_rounded = std.mem.alignForward(u64, size, Header.SIZE); // size rounded to te block boundary
410 return @intCast(block_rounded - size);
411 }
367 fn newFile(self: *Iterator) File {
368 return .{
369 .name = self.file_name_buffer[0..0],
370 .link_name = self.link_name_buffer[0..0],
371 };
372 }
412373
413 /// Iterates through the tar archive as if it is a series of files.
414 /// Internally, the tar format often uses entries (header with optional
415 /// content) to add meta data that describes the next file. These
416 /// entries should not normally be visible to the outside. As such, this
417 /// loop iterates through one or more entries until it collects a all
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 }
374 // Number of padding bytes in the last file block.
375 fn blockPadding(size: u64) usize {
376 const block_rounded = std.mem.alignForward(u64, size, Header.SIZE); // size rounded to te block boundary
377 return @intCast(block_rounded - size);
378 }
453379
454 self.padding = blockPadding(file.size);
455 self.unread_file_bytes = file.size;
456 return file;
457 },
458 // Prefix header types
459 .gnu_long_name => {
460 file.name = try self.readString(@intCast(size), self.file_name_buffer);
461 },
462 .gnu_long_link => {
463 file.link_name = try self.readString(@intCast(size), self.link_name_buffer);
464 },
465 .extended_header => {
466 // Use just attributes from last extended header.
467 file = self.newFile();
468
469 var rdr = paxIterator(self.reader, @intCast(size));
470 while (try rdr.next()) |attr| {
471 switch (attr.kind) {
472 .path => {
473 file.name = try attr.value(self.file_name_buffer);
474 },
475 .linkpath => {
476 file.link_name = try attr.value(self.link_name_buffer);
477 },
478 .size => {
479 var buf: [pax_max_size_attr_len]u8 = undefined;
480 file.size = try std.fmt.parseInt(u64, try attr.value(&buf), 10);
481 },
482 }
483 }
484 },
485 // Ignored header type
486 .global_extended_header => {
487 self.reader.skipBytes(size, .{}) catch return error.TarHeadersTooBig;
488 },
489 // All other are unsupported header types
490 else => {
491 const d = self.diagnostics orelse return error.TarUnsupportedHeader;
492 try d.errors.append(d.allocator, .{ .unsupported_file_type = .{
493 .file_name = try d.allocator.dupe(u8, header.name()),
494 .file_type = kind,
495 } });
496 if (kind == .gnu_sparse) {
497 try self.skipGnuSparseExtendedHeaders(header);
380 /// Iterates through the tar archive as if it is a series of files.
381 /// Internally, the tar format often uses entries (header with optional
382 /// content) to add meta data that describes the next file. These
383 /// entries should not normally be visible to the outside. As such, this
384 /// loop iterates through one or more entries until it collects a all
385 /// file attributes.
386 pub fn next(self: *Iterator) !?File {
387 if (self.unread_file_bytes > 0) {
388 // If file content was not consumed by caller
389 try self.reader.discardAll64(self.unread_file_bytes);
390 self.unread_file_bytes = 0;
391 }
392 var file: File = self.newFile();
393
394 while (try self.readHeader()) |header| {
395 const kind = header.kind();
396 const size: u64 = try header.size();
397 self.padding = blockPadding(size);
398
399 switch (kind) {
400 // File types to return upstream
401 .directory, .normal, .symbolic_link => {
402 file.kind = switch (kind) {
403 .directory => .directory,
404 .normal => .file,
405 .symbolic_link => .sym_link,
406 else => unreachable,
407 };
408 file.mode = try header.mode();
409
410 // set file attributes if not already set by prefix/extended headers
411 if (file.size == 0) {
412 file.size = size;
413 }
414 if (file.link_name.len == 0) {
415 file.link_name = try header.linkName(self.link_name_buffer);
416 }
417 if (file.name.len == 0) {
418 file.name = try header.fullName(self.file_name_buffer);
419 }
420
421 self.padding = blockPadding(file.size);
422 self.unread_file_bytes = file.size;
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 },
498452 }
499 self.reader.skipBytes(size, .{}) catch return error.TarHeadersTooBig;
500 },
501 }
453 }
454 },
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 },
502471 }
503 return null;
504472 }
473 return null;
474 }
505475
506 fn skipGnuSparseExtendedHeaders(self: *Self, header: Header) !void {
507 var is_extended = header.bytes[482] > 0;
508 while (is_extended) {
509 var buf: [Header.SIZE]u8 = undefined;
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}
476 pub fn streamRemaining(it: *Iterator, file: File, w: *std.Io.Writer) std.Io.Reader.StreamError!void {
477 try it.reader.streamExact64(w, file.size);
478 it.unread_file_bytes = 0;
479 }
517480
518/// Pax attributes iterator.
519/// Size is length of pax extended header in reader.
520fn paxIterator(reader: anytype, size: usize) PaxIterator(@TypeOf(reader)) {
521 return PaxIterator(@TypeOf(reader)){
522 .reader = reader,
523 .size = size,
524 };
525}
481 fn skipGnuSparseExtendedHeaders(self: *Iterator, header: Header) !void {
482 var is_extended = header.bytes[482] > 0;
483 while (is_extended) {
484 var buf: [Header.SIZE]u8 = undefined;
485 try self.reader.readSliceAll(&buf);
486 is_extended = buf[504] > 0;
487 }
488 }
489};
526490
527491const PaxAttributeKind = enum {
528492 path,
......@@ -533,108 +497,99 @@ const PaxAttributeKind = enum {
533497// maxInt(u64) has 20 chars, base 10 in practice we got 24 chars
534498const pax_max_size_attr_len = 64;
535499
536fn PaxIterator(comptime ReaderType: type) type {
537 return struct {
538 size: usize, // cumulative size of all pax attributes
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 };
500pub const PaxIterator = struct {
501 size: usize, // cumulative size of all pax attributes
502 reader: *std.Io.Reader,
563503
564 // Iterates over pax attributes. Returns known only known attributes.
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 }
504 const Self = @This();
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;
604522 }
523 };
605524
606 fn readUntil(self: *Self, delimiter: u8) ![]const u8 {
607 var fbs = std.io.fixedBufferStream(&self.scratch);
608 try self.reader.streamUntilDelimiter(fbs.writer(), delimiter, null);
609 return fbs.getWritten();
525 // Iterates over pax attributes. Returns known only known attributes.
526 // Caller has to call value in Attribute, to advance reader across value.
527 pub fn next(self: *Self) !?Attribute {
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 };
610562 }
611563
612 fn eql(a: []const u8, b: []const u8) bool {
613 return std.mem.eql(u8, a, b);
614 }
564 return null;
565 }
615566
616 fn hasNull(str: []const u8) bool {
617 return (std.mem.indexOfScalar(u8, str, 0)) != null;
618 }
567 fn eql(a: []const u8, b: []const u8) bool {
568 return std.mem.eql(u8, a, b);
569 }
619570
620 // Checks that each record ends with new line.
621 fn validateAttributeEnding(reader: ReaderType) !void {
622 if (try reader.readByte() != '\n') return error.PaxInvalidAttributeEnd;
623 }
624 };
625}
571 fn hasNull(str: []const u8) bool {
572 return (std.mem.indexOfScalar(u8, str, 0)) != null;
573 }
574
575 // Checks that each record ends with new line.
576 fn validateAttributeEnding(reader: *std.Io.Reader) !void {
577 if (try reader.takeByte() != '\n') return error.PaxInvalidAttributeEnd;
578 }
579};
626580
627581/// 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 {
629583 var file_name_buffer: [std.fs.max_path_bytes]u8 = undefined;
630584 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, .{
632587 .file_name_buffer = &file_name_buffer,
633588 .link_name_buffer = &link_name_buffer,
634589 .diagnostics = options.diagnostics,
635590 });
636591
637 while (try iter.next()) |file| {
592 while (try it.next()) |file| {
638593 const file_name = stripComponents(file.name, options.strip_components);
639594 if (file_name.len == 0 and file.kind != .directory) {
640595 const d = options.diagnostics orelse return error.TarComponentsOutsideStrippedPrefix;
......@@ -656,7 +611,9 @@ pub fn pipeToFileSystem(dir: std.fs.Dir, reader: anytype, options: PipeOptions)
656611 .file => {
657612 if (createDirAndFile(dir, file_name, fileMode(file.mode, options))) |fs_file| {
658613 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();
660617 } else |err| {
661618 const d = options.diagnostics orelse return err;
662619 try d.errors.append(d.allocator, .{ .unable_to_create_file = .{
......@@ -826,11 +783,14 @@ test PaxIterator {
826783 var buffer: [1024]u8 = undefined;
827784
828785 outer: for (cases) |case| {
829 var stream = std.io.fixedBufferStream(case.data);
830 var iter = paxIterator(stream.reader(), case.data.len);
786 var reader: std.Io.Reader = .fixed(case.data);
787 var it: PaxIterator = .{
788 .size = case.data.len,
789 .reader = &reader,
790 };
831791
832792 var i: usize = 0;
833 while (iter.next() catch |err| {
793 while (it.next() catch |err| {
834794 if (case.err) |e| {
835795 try testing.expectEqual(e, err);
836796 continue;
......@@ -853,12 +813,6 @@ test PaxIterator {
853813 }
854814}
855815
856test {
857 _ = @import("tar/test.zig");
858 _ = @import("tar/writer.zig");
859 _ = Diagnostics;
860}
861
862816test "header parse size" {
863817 const cases = [_]struct {
864818 in: []const u8,
......@@ -941,7 +895,7 @@ test "create file and symlink" {
941895 file.close();
942896}
943897
944test iterator {
898test Iterator {
945899 // Example tar file is created from this tree structure:
946900 // $ tree example
947901 // example
......@@ -962,19 +916,19 @@ test iterator {
962916 // example/empty/
963917
964918 const data = @embedFile("tar/testdata/example.tar");
965 var fbs = std.io.fixedBufferStream(data);
919 var reader: std.Io.Reader = .fixed(data);
966920
967921 // User provided buffers to the iterator
968922 var file_name_buffer: [std.fs.max_path_bytes]u8 = undefined;
969923 var link_name_buffer: [std.fs.max_path_bytes]u8 = undefined;
970924 // Create iterator
971 var iter = iterator(fbs.reader(), .{
925 var it: Iterator = .init(&reader, .{
972926 .file_name_buffer = &file_name_buffer,
973927 .link_name_buffer = &link_name_buffer,
974928 });
975929 // Iterate over files in example.tar
976930 var file_no: usize = 0;
977 while (try iter.next()) |file| : (file_no += 1) {
931 while (try it.next()) |file| : (file_no += 1) {
978932 switch (file.kind) {
979933 .directory => {
980934 switch (file_no) {
......@@ -987,10 +941,10 @@ test iterator {
987941 },
988942 .file => {
989943 try testing.expectEqualStrings("example/a/file", file.name);
990 // Read file content
991944 var buf: [16]u8 = undefined;
992 const n = try file.reader().readAll(&buf);
993 try testing.expectEqualStrings("content\n", buf[0..n]);
945 var w: std.Io.Writer = .fixed(&buf);
946 try it.streamRemaining(file, &w);
947 try testing.expectEqualStrings("content\n", w.buffered());
994948 },
995949 .sym_link => {
996950 try testing.expectEqualStrings("example/b/symlink", file.name);
......@@ -1021,15 +975,14 @@ test pipeToFileSystem {
1021975 // example/empty/
1022976
1023977 const data = @embedFile("tar/testdata/example.tar");
1024 var fbs = std.io.fixedBufferStream(data);
1025 const reader = fbs.reader();
978 var reader: std.Io.Reader = .fixed(data);
1026979
1027980 var tmp = testing.tmpDir(.{ .no_follow = true });
1028981 defer tmp.cleanup();
1029982 const dir = tmp.dir;
1030983
1031 // Save tar from `reader` to the file system `dir`
1032 pipeToFileSystem(dir, reader, .{
984 // Save tar from reader to the file system `dir`
985 pipeToFileSystem(dir, &reader, .{
1033986 .mode_mode = .ignore,
1034987 .strip_components = 1,
1035988 .exclude_empty_directories = true,
......@@ -1053,8 +1006,7 @@ test pipeToFileSystem {
10531006
10541007test "pipeToFileSystem root_dir" {
10551008 const data = @embedFile("tar/testdata/example.tar");
1056 var fbs = std.io.fixedBufferStream(data);
1057 const reader = fbs.reader();
1009 var reader: std.Io.Reader = .fixed(data);
10581010
10591011 // with strip_components = 1
10601012 {
......@@ -1063,7 +1015,7 @@ test "pipeToFileSystem root_dir" {
10631015 var diagnostics: Diagnostics = .{ .allocator = testing.allocator };
10641016 defer diagnostics.deinit();
10651017
1066 pipeToFileSystem(tmp.dir, reader, .{
1018 pipeToFileSystem(tmp.dir, &reader, .{
10671019 .strip_components = 1,
10681020 .diagnostics = &diagnostics,
10691021 }) catch |err| {
......@@ -1079,13 +1031,13 @@ test "pipeToFileSystem root_dir" {
10791031
10801032 // with strip_components = 0
10811033 {
1082 fbs.reset();
1034 reader = .fixed(data);
10831035 var tmp = testing.tmpDir(.{ .no_follow = true });
10841036 defer tmp.cleanup();
10851037 var diagnostics: Diagnostics = .{ .allocator = testing.allocator };
10861038 defer diagnostics.deinit();
10871039
1088 pipeToFileSystem(tmp.dir, reader, .{
1040 pipeToFileSystem(tmp.dir, &reader, .{
10891041 .strip_components = 0,
10901042 .diagnostics = &diagnostics,
10911043 }) catch |err| {
......@@ -1102,45 +1054,42 @@ test "pipeToFileSystem root_dir" {
11021054
11031055test "findRoot with single file archive" {
11041056 const data = @embedFile("tar/testdata/22752.tar");
1105 var fbs = std.io.fixedBufferStream(data);
1106 const reader = fbs.reader();
1057 var reader: std.Io.Reader = .fixed(data);
11071058
11081059 var tmp = testing.tmpDir(.{});
11091060 defer tmp.cleanup();
11101061
11111062 var diagnostics: Diagnostics = .{ .allocator = testing.allocator };
11121063 defer diagnostics.deinit();
1113 try pipeToFileSystem(tmp.dir, reader, .{ .diagnostics = &diagnostics });
1064 try pipeToFileSystem(tmp.dir, &reader, .{ .diagnostics = &diagnostics });
11141065
11151066 try testing.expectEqualStrings("", diagnostics.root_dir);
11161067}
11171068
11181069test "findRoot without explicit root dir" {
11191070 const data = @embedFile("tar/testdata/19820.tar");
1120 var fbs = std.io.fixedBufferStream(data);
1121 const reader = fbs.reader();
1071 var reader: std.Io.Reader = .fixed(data);
11221072
11231073 var tmp = testing.tmpDir(.{});
11241074 defer tmp.cleanup();
11251075
11261076 var diagnostics: Diagnostics = .{ .allocator = testing.allocator };
11271077 defer diagnostics.deinit();
1128 try pipeToFileSystem(tmp.dir, reader, .{ .diagnostics = &diagnostics });
1078 try pipeToFileSystem(tmp.dir, &reader, .{ .diagnostics = &diagnostics });
11291079
11301080 try testing.expectEqualStrings("root", diagnostics.root_dir);
11311081}
11321082
11331083test "pipeToFileSystem strip_components" {
11341084 const data = @embedFile("tar/testdata/example.tar");
1135 var fbs = std.io.fixedBufferStream(data);
1136 const reader = fbs.reader();
1085 var reader: std.Io.Reader = .fixed(data);
11371086
11381087 var tmp = testing.tmpDir(.{ .no_follow = true });
11391088 defer tmp.cleanup();
11401089 var diagnostics: Diagnostics = .{ .allocator = testing.allocator };
11411090 defer diagnostics.deinit();
11421091
1143 pipeToFileSystem(tmp.dir, reader, .{
1092 pipeToFileSystem(tmp.dir, &reader, .{
11441093 .strip_components = 3,
11451094 .diagnostics = &diagnostics,
11461095 }) catch |err| {
......@@ -1194,13 +1143,12 @@ test "executable bit" {
11941143 const data = @embedFile("tar/testdata/example.tar");
11951144
11961145 for ([_]PipeOptions.ModeMode{ .ignore, .executable_bit_only }) |opt| {
1197 var fbs = std.io.fixedBufferStream(data);
1198 const reader = fbs.reader();
1146 var reader: std.Io.Reader = .fixed(data);
11991147
12001148 var tmp = testing.tmpDir(.{ .no_follow = true });
12011149 //defer tmp.cleanup();
12021150
1203 pipeToFileSystem(tmp.dir, reader, .{
1151 pipeToFileSystem(tmp.dir, &reader, .{
12041152 .strip_components = 1,
12051153 .exclude_empty_directories = true,
12061154 .mode_mode = opt,
......@@ -1226,3 +1174,9 @@ test "executable bit" {
12261174 }
12271175 }
12281176}
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 {
1818 err: ?anyerror = null, // parsing should fail with this error
1919};
2020
21const cases = [_]Case{
22 .{
23 .data = @embedFile("testdata/gnu.tar"),
24 .files = &[_]Case.File{
25 .{
26 .name = "small.txt",
27 .size = 5,
28 .mode = 0o640,
29 },
30 .{
31 .name = "small2.txt",
32 .size = 11,
33 .mode = 0o640,
34 },
21const gnu_case: Case = .{
22 .data = @embedFile("testdata/gnu.tar"),
23 .files = &[_]Case.File{
24 .{
25 .name = "small.txt",
26 .size = 5,
27 .mode = 0o640,
3528 },
36 .chksums = &[_][]const u8{
37 "e38b27eaccb4391bdec553a7f3ae6b2f",
38 "c65bd2e50a56a2138bf1716f2fd56fe9",
29 .{
30 .name = "small2.txt",
31 .size = 11,
32 .mode = 0o640,
33 },
34 },
35 .chksums = &[_][]const u8{
36 "e38b27eaccb4391bdec553a7f3ae6b2f",
37 "c65bd2e50a56a2138bf1716f2fd56fe9",
38 },
39};
40
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,
3948 },
4049 },
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(.{
4283 .data = @embedFile("testdata/sparse-formats.tar"),
4384 .err = error.TarUnsupportedHeader,
44 },
45 .{
85 });
86 try testCase(.{
4687 .data = @embedFile("testdata/star.tar"),
4788 .files = &[_]Case.File{
4889 .{
......@@ -60,8 +101,8 @@ const cases = [_]Case{
60101 "e38b27eaccb4391bdec553a7f3ae6b2f",
61102 "c65bd2e50a56a2138bf1716f2fd56fe9",
62103 },
63 },
64 .{
104 });
105 try testCase(.{
65106 .data = @embedFile("testdata/v7.tar"),
66107 .files = &[_]Case.File{
67108 .{
......@@ -79,8 +120,8 @@ const cases = [_]Case{
79120 "e38b27eaccb4391bdec553a7f3ae6b2f",
80121 "c65bd2e50a56a2138bf1716f2fd56fe9",
81122 },
82 },
83 .{
123 });
124 try testCase(.{
84125 .data = @embedFile("testdata/pax.tar"),
85126 .files = &[_]Case.File{
86127 .{
......@@ -99,13 +140,13 @@ const cases = [_]Case{
99140 .chksums = &[_][]const u8{
100141 "3c382e8f5b6631aa2db52643912ffd4a",
101142 },
102 },
103 .{
143 });
144 try testCase(.{
104145 // pax attribute don't end with \n
105146 .data = @embedFile("testdata/pax-bad-hdr-file.tar"),
106147 .err = error.PaxInvalidAttributeEnd,
107 },
108 .{
148 });
149 try testCase(.{
109150 // size is in pax attribute
110151 .data = @embedFile("testdata/pax-pos-size-file.tar"),
111152 .files = &[_]Case.File{
......@@ -119,8 +160,8 @@ const cases = [_]Case{
119160 .chksums = &[_][]const u8{
120161 "0afb597b283fe61b5d4879669a350556",
121162 },
122 },
123 .{
163 });
164 try testCase(.{
124165 // has pax records which we are not interested in
125166 .data = @embedFile("testdata/pax-records.tar"),
126167 .files = &[_]Case.File{
......@@ -128,8 +169,8 @@ const cases = [_]Case{
128169 .name = "file",
129170 },
130171 },
131 },
132 .{
172 });
173 try testCase(.{
133174 // has global records which we are ignoring
134175 .data = @embedFile("testdata/pax-global-records.tar"),
135176 .files = &[_]Case.File{
......@@ -146,8 +187,8 @@ const cases = [_]Case{
146187 .name = "file4",
147188 },
148189 },
149 },
150 .{
190 });
191 try testCase(.{
151192 .data = @embedFile("testdata/nil-uid.tar"),
152193 .files = &[_]Case.File{
153194 .{
......@@ -160,8 +201,8 @@ const cases = [_]Case{
160201 .chksums = &[_][]const u8{
161202 "08d504674115e77a67244beac19668f5",
162203 },
163 },
164 .{
204 });
205 try testCase(.{
165206 // has xattrs and pax records which we are ignoring
166207 .data = @embedFile("testdata/xattrs.tar"),
167208 .files = &[_]Case.File{
......@@ -182,23 +223,14 @@ const cases = [_]Case{
182223 "e38b27eaccb4391bdec553a7f3ae6b2f",
183224 "c65bd2e50a56a2138bf1716f2fd56fe9",
184225 },
185 },
186 .{
187 .data = @embedFile("testdata/gnu-multi-hdrs.tar"),
188 .files = &[_]Case.File{
189 .{
190 .name = "GNU2/GNU2/long-path-name",
191 .link_name = "GNU4/GNU4/long-linkpath-name",
192 .kind = .sym_link,
193 },
194 },
195 },
196 .{
226 });
227 try testCase(gnu_multi_headers_case);
228 try testCase(.{
197229 // has gnu type D (directory) and S (sparse) blocks
198230 .data = @embedFile("testdata/gnu-incremental.tar"),
199231 .err = error.TarUnsupportedHeader,
200 },
201 .{
232 });
233 try testCase(.{
202234 // should use values only from last pax header
203235 .data = @embedFile("testdata/pax-multi-hdrs.tar"),
204236 .files = &[_]Case.File{
......@@ -208,8 +240,8 @@ const cases = [_]Case{
208240 .kind = .sym_link,
209241 },
210242 },
211 },
212 .{
243 });
244 try testCase(.{
213245 .data = @embedFile("testdata/gnu-long-nul.tar"),
214246 .files = &[_]Case.File{
215247 .{
......@@ -217,8 +249,8 @@ const cases = [_]Case{
217249 .mode = 0o644,
218250 },
219251 },
220 },
221 .{
252 });
253 try testCase(.{
222254 .data = @embedFile("testdata/gnu-utf8.tar"),
223255 .files = &[_]Case.File{
224256 .{
......@@ -226,8 +258,8 @@ const cases = [_]Case{
226258 .mode = 0o644,
227259 },
228260 },
229 },
230 .{
261 });
262 try testCase(.{
231263 .data = @embedFile("testdata/gnu-not-utf8.tar"),
232264 .files = &[_]Case.File{
233265 .{
......@@ -235,33 +267,33 @@ const cases = [_]Case{
235267 .mode = 0o644,
236268 },
237269 },
238 },
239 .{
270 });
271 try testCase(.{
240272 // null in pax key
241273 .data = @embedFile("testdata/pax-nul-xattrs.tar"),
242274 .err = error.PaxNullInKeyword,
243 },
244 .{
275 });
276 try testCase(.{
245277 .data = @embedFile("testdata/pax-nul-path.tar"),
246278 .err = error.PaxNullInValue,
247 },
248 .{
279 });
280 try testCase(.{
249281 .data = @embedFile("testdata/neg-size.tar"),
250282 .err = error.TarHeader,
251 },
252 .{
283 });
284 try testCase(.{
253285 .data = @embedFile("testdata/issue10968.tar"),
254286 .err = error.TarHeader,
255 },
256 .{
287 });
288 try testCase(.{
257289 .data = @embedFile("testdata/issue11169.tar"),
258290 .err = error.TarHeader,
259 },
260 .{
291 });
292 try testCase(.{
261293 .data = @embedFile("testdata/issue12435.tar"),
262294 .err = error.TarHeaderChksum,
263 },
264 .{
295 });
296 try testCase(.{
265297 // has magic with space at end instead of null
266298 .data = @embedFile("testdata/invalid-go17.tar"),
267299 .files = &[_]Case.File{
......@@ -269,8 +301,8 @@ const cases = [_]Case{
269301 .name = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/foo",
270302 },
271303 },
272 },
273 .{
304 });
305 try testCase(.{
274306 .data = @embedFile("testdata/ustar-file-devs.tar"),
275307 .files = &[_]Case.File{
276308 .{
......@@ -278,17 +310,9 @@ const cases = [_]Case{
278310 .mode = 0o644,
279311 },
280312 },
281 },
282 .{
283 .data = @embedFile("testdata/trailing-slash.tar"),
284 .files = &[_]Case.File{
285 .{
286 .name = "123456789/" ** 30,
287 .kind = .directory,
288 },
289 },
290 },
291 .{
313 });
314 try testCase(trailing_slash_case);
315 try testCase(.{
292316 // Has size in gnu extended format. To represent size bigger than 8 GB.
293317 .data = @embedFile("testdata/writer-big.tar"),
294318 .files = &[_]Case.File{
......@@ -299,120 +323,92 @@ const cases = [_]Case{
299323 .mode = 0o640,
300324 },
301325 },
302 },
303 .{
304 // Size in gnu extended format, and name in pax attribute.
305 .data = @embedFile("testdata/writer-big-long.tar"),
306 .files = &[_]Case.File{
307 .{
308 .name = "longname/" ** 15 ++ "16gig.txt",
309 .size = 16 * 1024 * 1024 * 1024,
310 .mode = 0o644,
311 .truncated = true,
312 },
313 },
314 },
315 .{
316 .data = @embedFile("testdata/fuzz1.tar"),
317 .err = error.TarInsufficientBuffer,
318 },
319 .{
326 });
327 try testCase(writer_big_long_case);
328 try testCase(fuzz1_case);
329 try testCase(.{
320330 .data = @embedFile("testdata/fuzz2.tar"),
321331 .err = error.PaxSizeAttrOverflow,
322 },
323};
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};
332 });
333}
343334
344test "run test cases" {
335fn testCase(case: Case) !void {
345336 var file_name_buffer: [std.fs.max_path_bytes]u8 = undefined;
346337 var link_name_buffer: [std.fs.max_path_bytes]u8 = undefined;
347338
348 for (cases) |case| {
349 var fsb = std.io.fixedBufferStream(case.data);
350 var iter = tar.iterator(fsb.reader(), .{
351 .file_name_buffer = &file_name_buffer,
352 .link_name_buffer = &link_name_buffer,
353 });
354 var i: usize = 0;
355 while (iter.next() catch |err| {
356 if (case.err) |e| {
357 try testing.expectEqual(e, err);
358 continue;
359 } else {
360 return err;
361 }
362 }) |actual| : (i += 1) {
363 const expected = case.files[i];
364 try testing.expectEqualStrings(expected.name, actual.name);
365 try testing.expectEqual(expected.size, actual.size);
366 try testing.expectEqual(expected.kind, actual.kind);
367 try testing.expectEqual(expected.mode, actual.mode);
368 try testing.expectEqualStrings(expected.link_name, actual.link_name);
339 var br: std.io.Reader = .fixed(case.data);
340 var it: tar.Iterator = .init(&br, .{
341 .file_name_buffer = &file_name_buffer,
342 .link_name_buffer = &link_name_buffer,
343 });
344 var i: usize = 0;
345 while (it.next() catch |err| {
346 if (case.err) |e| {
347 try testing.expectEqual(e, err);
348 return;
349 } else {
350 return err;
351 }
352 }) |actual| : (i += 1) {
353 const expected = case.files[i];
354 try testing.expectEqualStrings(expected.name, actual.name);
355 try testing.expectEqual(expected.size, actual.size);
356 try testing.expectEqual(expected.kind, actual.kind);
357 try testing.expectEqual(expected.mode, actual.mode);
358 try testing.expectEqualStrings(expected.link_name, actual.link_name);
369359
370 if (case.chksums.len > i) {
371 var md5writer = Md5Writer{};
372 try actual.writeAll(&md5writer);
373 const chksum = md5writer.chksum();
374 try testing.expectEqualStrings(case.chksums[i], &chksum);
375 } else {
376 if (expected.truncated) {
377 iter.unread_file_bytes = 0;
378 }
360 if (case.chksums.len > i) {
361 var aw: std.Io.Writer.Allocating = .init(std.testing.allocator);
362 defer aw.deinit();
363 try it.streamRemaining(actual, &aw.writer);
364 const chksum = std.fmt.bytesToHex(std.crypto.hash.Md5.hashResult(aw.getWritten()), .lower);
365 try testing.expectEqualStrings(case.chksums[i], &chksum);
366 } else {
367 if (expected.truncated) {
368 it.unread_file_bytes = 0;
379369 }
380370 }
381 try testing.expectEqual(case.files.len, i);
382371 }
372 try testing.expectEqual(case.files.len, i);
383373}
384374
385375test "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 {
386385 // should fail with insufficient buffer error
387386
388387 var min_file_name_buffer: [256]u8 = undefined;
389388 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| {
393 var fsb = std.io.fixedBufferStream(case.data);
394 var iter = tar.iterator(fsb.reader(), .{
395 .file_name_buffer = &min_file_name_buffer,
396 .link_name_buffer = &min_link_name_buffer,
397 });
390 var br: std.io.Reader = .fixed(case.data);
391 var iter: tar.Iterator = .init(&br, .{
392 .file_name_buffer = &min_file_name_buffer,
393 .link_name_buffer = &min_link_name_buffer,
394 });
398395
399 var iter_err: ?anyerror = null;
400 while (iter.next() catch |err| brk: {
401 iter_err = err;
402 break :brk null;
403 }) |_| {}
396 var iter_err: ?anyerror = null;
397 while (iter.next() catch |err| brk: {
398 iter_err = err;
399 break :brk null;
400 }) |_| {}
404401
405 try testing.expect(iter_err != null);
406 try testing.expectEqual(error.TarInsufficientBuffer, iter_err.?);
407 }
402 try testing.expect(iter_err != null);
403 try testing.expectEqual(error.TarInsufficientBuffer, iter_err.?);
408404}
409405
410406test "insufficient buffer in Header name filed" {
411407 var min_file_name_buffer: [9]u8 = undefined;
412408 var min_link_name_buffer: [100]u8 = undefined;
413409
414 var fsb = std.io.fixedBufferStream(cases[0].data);
415 var iter = tar.iterator(fsb.reader(), .{
410 var br: std.io.Reader = .fixed(gnu_case.data);
411 var iter: tar.Iterator = .init(&br, .{
416412 .file_name_buffer = &min_file_name_buffer,
417413 .link_name_buffer = &min_link_name_buffer,
418414 });
......@@ -466,21 +462,21 @@ test "should not overwrite existing file" {
466462 // This ensures that file is not overwritten.
467463 //
468464 const data = @embedFile("testdata/overwrite_file.tar");
469 var fsb = std.io.fixedBufferStream(data);
465 var r: std.io.Reader = .fixed(data);
470466
471467 // Unpack with strip_components = 1 should fail
472468 var root = std.testing.tmpDir(.{});
473469 defer root.cleanup();
474470 try testing.expectError(
475471 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 }),
477473 );
478474
479475 // Unpack with strip_components = 0 should pass
480 fsb.reset();
476 r = .fixed(data);
481477 var root2 = std.testing.tmpDir(.{});
482478 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 });
484480}
485481
486482test "case sensitivity" {
......@@ -494,12 +490,12 @@ test "case sensitivity" {
494490 // 18089/alacritty/Darkermatrix.yml
495491 //
496492 const data = @embedFile("testdata/18089.tar");
497 var fsb = std.io.fixedBufferStream(data);
493 var r: std.io.Reader = .fixed(data);
498494
499495 var root = std.testing.tmpDir(.{});
500496 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| {
503499 // on case insensitive fs we fail on overwrite existing file
504500 try testing.expectEqual(error.PathAlreadyExists, err);
505501 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;
3333
3434// Disable printing in tests for simple backends.
3535pub const backend_can_print = switch (builtin.zig_backend) {
36 .stage2_aarch64,
3637 .stage2_powerpc,
3738 .stage2_riscv64,
3839 .stage2_spirv,
lib/std/zig.zig+30-9
......@@ -321,6 +321,27 @@ pub const BuildId = union(enum) {
321321 try std.testing.expectError(error.InvalidCharacter, parse("0xfoobbb"));
322322 try std.testing.expectError(error.InvalidBuildIdStyle, parse("yaddaxxx"));
323323 }
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 }
324345};
325346
326347pub const LtoMode = enum { none, full, thin };
......@@ -364,23 +385,23 @@ pub fn serializeCpuAlloc(ally: Allocator, cpu: std.Target.Cpu) Allocator.Error![
364385/// Return a Formatter for a Zig identifier, escaping it with `@""` syntax if needed.
365386///
366387/// See also `fmtIdFlags`.
367pub fn fmtId(bytes: []const u8) std.fmt.Formatter(FormatId, FormatId.render) {
368 return .{ .data = .{ .bytes = bytes, .flags = .{} } };
388pub fn fmtId(bytes: []const u8) FormatId {
389 return .{ .bytes = bytes, .flags = .{} };
369390}
370391
371392/// Return a Formatter for a Zig identifier, escaping it with `@""` syntax if needed.
372393///
373394/// See also `fmtId`.
374pub fn fmtIdFlags(bytes: []const u8, flags: FormatId.Flags) std.fmt.Formatter(FormatId, FormatId.render) {
375 return .{ .data = .{ .bytes = bytes, .flags = flags } };
395pub fn fmtIdFlags(bytes: []const u8, flags: FormatId.Flags) FormatId {
396 return .{ .bytes = bytes, .flags = flags };
376397}
377398
378pub fn fmtIdPU(bytes: []const u8) std.fmt.Formatter(FormatId, FormatId.render) {
379 return .{ .data = .{ .bytes = bytes, .flags = .{ .allow_primitive = true, .allow_underscore = true } } };
399pub fn fmtIdPU(bytes: []const u8) FormatId {
400 return .{ .bytes = bytes, .flags = .{ .allow_primitive = true, .allow_underscore = true } };
380401}
381402
382pub fn fmtIdP(bytes: []const u8) std.fmt.Formatter(FormatId, FormatId.render) {
383 return .{ .data = .{ .bytes = bytes, .flags = .{ .allow_primitive = true } } };
403pub fn fmtIdP(bytes: []const u8) FormatId {
404 return .{ .bytes = bytes, .flags = .{ .allow_primitive = true } };
384405}
385406
386407test fmtId {
......@@ -426,7 +447,7 @@ pub const FormatId = struct {
426447 };
427448
428449 /// 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 {
430451 const bytes = ctx.bytes;
431452 if (isValidId(bytes) and
432453 (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 {
342342 }
343343
344344 // `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 = &.{} });
346346 defer af.deinit();
347 try af.file.writeAll(file.source.?);
347 try af.file_writer.interface.writeAll(file.source.?);
348348 af.finish() catch |err| switch (err) {
349349 error.AccessDenied => switch (builtin.os.tag) {
350350 .windows => {
src/Compilation.zig+166-149
......@@ -1816,10 +1816,12 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
18161816 if (options.skip_linker_dependencies) break :s .none;
18171817 const want = options.want_compiler_rt orelse is_exe_or_dyn_lib;
18181818 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)) {
18201820 if (output_mode == .Obj) break :s .zcu;
1821 if (target.ofmt == .coff and target_util.zigBackend(target, use_llvm) == .stage2_x86_64)
1822 break :s if (is_exe_or_dyn_lib) .dyn_lib else .zcu;
1821 if (switch (target_util.zigBackend(target, use_llvm)) {
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;
18231825 }
18241826 if (is_exe_or_dyn_lib) break :s .lib;
18251827 break :s .obj;
......@@ -1850,11 +1852,11 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
18501852 // approach, since the ubsan runtime uses quite a lot of the standard library
18511853 // and this reduces unnecessary bloat.
18521854 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);
18541856 const want_ubsan_rt = options.want_ubsan_rt orelse (can_build_ubsan_rt and any_sanitize_c == .full and is_exe_or_dyn_lib);
18551857 if (!want_ubsan_rt) break :s .none;
18561858 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;
18581860 if (is_exe_or_dyn_lib) break :s .lib;
18591861 break :s .obj;
18601862 };
......@@ -3382,7 +3384,7 @@ pub fn saveState(comp: *Compilation) !void {
33823384
33833385 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);
33863388 defer bufs.deinit();
33873389
33883390 var pt_headers = std.ArrayList(Header.PerThread).init(gpa);
......@@ -3421,50 +3423,50 @@ pub fn saveState(comp: *Compilation) !void {
34213423
34223424 try bufs.ensureTotalCapacityPrecise(14 + 8 * pt_headers.items.len);
34233425 addBuf(&bufs, mem.asBytes(&header));
3424 addBuf(&bufs, mem.sliceAsBytes(pt_headers.items));
3425
3426 addBuf(&bufs, mem.sliceAsBytes(ip.src_hash_deps.keys()));
3427 addBuf(&bufs, mem.sliceAsBytes(ip.src_hash_deps.values()));
3428 addBuf(&bufs, mem.sliceAsBytes(ip.nav_val_deps.keys()));
3429 addBuf(&bufs, mem.sliceAsBytes(ip.nav_val_deps.values()));
3430 addBuf(&bufs, mem.sliceAsBytes(ip.nav_ty_deps.keys()));
3431 addBuf(&bufs, mem.sliceAsBytes(ip.nav_ty_deps.values()));
3432 addBuf(&bufs, mem.sliceAsBytes(ip.interned_deps.keys()));
3433 addBuf(&bufs, mem.sliceAsBytes(ip.interned_deps.values()));
3434 addBuf(&bufs, mem.sliceAsBytes(ip.zon_file_deps.keys()));
3435 addBuf(&bufs, mem.sliceAsBytes(ip.zon_file_deps.values()));
3436 addBuf(&bufs, mem.sliceAsBytes(ip.embed_file_deps.keys()));
3437 addBuf(&bufs, mem.sliceAsBytes(ip.embed_file_deps.values()));
3438 addBuf(&bufs, mem.sliceAsBytes(ip.namespace_deps.keys()));
3439 addBuf(&bufs, mem.sliceAsBytes(ip.namespace_deps.values()));
3440 addBuf(&bufs, mem.sliceAsBytes(ip.namespace_name_deps.keys()));
3441 addBuf(&bufs, mem.sliceAsBytes(ip.namespace_name_deps.values()));
3442
3443 addBuf(&bufs, mem.sliceAsBytes(ip.first_dependency.keys()));
3444 addBuf(&bufs, mem.sliceAsBytes(ip.first_dependency.values()));
3445 addBuf(&bufs, mem.sliceAsBytes(ip.dep_entries.items));
3446 addBuf(&bufs, mem.sliceAsBytes(ip.free_dep_entries.items));
3426 addBuf(&bufs, @ptrCast(pt_headers.items));
3427
3428 addBuf(&bufs, @ptrCast(ip.src_hash_deps.keys()));
3429 addBuf(&bufs, @ptrCast(ip.src_hash_deps.values()));
3430 addBuf(&bufs, @ptrCast(ip.nav_val_deps.keys()));
3431 addBuf(&bufs, @ptrCast(ip.nav_val_deps.values()));
3432 addBuf(&bufs, @ptrCast(ip.nav_ty_deps.keys()));
3433 addBuf(&bufs, @ptrCast(ip.nav_ty_deps.values()));
3434 addBuf(&bufs, @ptrCast(ip.interned_deps.keys()));
3435 addBuf(&bufs, @ptrCast(ip.interned_deps.values()));
3436 addBuf(&bufs, @ptrCast(ip.zon_file_deps.keys()));
3437 addBuf(&bufs, @ptrCast(ip.zon_file_deps.values()));
3438 addBuf(&bufs, @ptrCast(ip.embed_file_deps.keys()));
3439 addBuf(&bufs, @ptrCast(ip.embed_file_deps.values()));
3440 addBuf(&bufs, @ptrCast(ip.namespace_deps.keys()));
3441 addBuf(&bufs, @ptrCast(ip.namespace_deps.values()));
3442 addBuf(&bufs, @ptrCast(ip.namespace_name_deps.keys()));
3443 addBuf(&bufs, @ptrCast(ip.namespace_name_deps.values()));
3444
3445 addBuf(&bufs, @ptrCast(ip.first_dependency.keys()));
3446 addBuf(&bufs, @ptrCast(ip.first_dependency.values()));
3447 addBuf(&bufs, @ptrCast(ip.dep_entries.items));
3448 addBuf(&bufs, @ptrCast(ip.free_dep_entries.items));
34473449
34483450 for (ip.locals, pt_headers.items) |*local, pt_header| {
34493451 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]));
34513453 }
34523454 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]));
34543456 }
34553457 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]));
3457 addBuf(&bufs, mem.sliceAsBytes(local.shared.items.view().items(.tag)[0..pt_header.intern_pool.items_len]));
3458 addBuf(&bufs, @ptrCast(local.shared.items.view().items(.data)[0..pt_header.intern_pool.items_len]));
3459 addBuf(&bufs, @ptrCast(local.shared.items.view().items(.tag)[0..pt_header.intern_pool.items_len]));
34583460 }
34593461 if (pt_header.intern_pool.string_bytes_len > 0) {
34603462 addBuf(&bufs, local.shared.strings.view().items(.@"0")[0..pt_header.intern_pool.string_bytes_len]);
34613463 }
34623464 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]));
34643466 }
34653467 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]));
3467 addBuf(&bufs, mem.sliceAsBytes(local.shared.files.view().items(.root_type)[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]));
3469 addBuf(&bufs, @ptrCast(local.shared.files.view().items(.root_type)[0..pt_header.intern_pool.files_len]));
34683470 }
34693471 }
34703472
......@@ -3482,95 +3484,95 @@ pub fn saveState(comp: *Compilation) !void {
34823484 try bufs.ensureUnusedCapacity(85);
34833485 addBuf(&bufs, wasm.string_bytes.items);
34843486 // TODO make it well-defined memory layout
3485 //addBuf(&bufs, mem.sliceAsBytes(wasm.objects.items));
3486 addBuf(&bufs, mem.sliceAsBytes(wasm.func_types.keys()));
3487 addBuf(&bufs, mem.sliceAsBytes(wasm.object_function_imports.keys()));
3488 addBuf(&bufs, mem.sliceAsBytes(wasm.object_function_imports.values()));
3489 addBuf(&bufs, mem.sliceAsBytes(wasm.object_functions.items));
3490 addBuf(&bufs, mem.sliceAsBytes(wasm.object_global_imports.keys()));
3491 addBuf(&bufs, mem.sliceAsBytes(wasm.object_global_imports.values()));
3492 addBuf(&bufs, mem.sliceAsBytes(wasm.object_globals.items));
3493 addBuf(&bufs, mem.sliceAsBytes(wasm.object_table_imports.keys()));
3494 addBuf(&bufs, mem.sliceAsBytes(wasm.object_table_imports.values()));
3495 addBuf(&bufs, mem.sliceAsBytes(wasm.object_tables.items));
3496 addBuf(&bufs, mem.sliceAsBytes(wasm.object_memory_imports.keys()));
3497 addBuf(&bufs, mem.sliceAsBytes(wasm.object_memory_imports.values()));
3498 addBuf(&bufs, mem.sliceAsBytes(wasm.object_memories.items));
3499 addBuf(&bufs, mem.sliceAsBytes(wasm.object_relocations.items(.tag)));
3500 addBuf(&bufs, mem.sliceAsBytes(wasm.object_relocations.items(.offset)));
3487 //addBuf(&bufs, @ptrCast(wasm.objects.items));
3488 addBuf(&bufs, @ptrCast(wasm.func_types.keys()));
3489 addBuf(&bufs, @ptrCast(wasm.object_function_imports.keys()));
3490 addBuf(&bufs, @ptrCast(wasm.object_function_imports.values()));
3491 addBuf(&bufs, @ptrCast(wasm.object_functions.items));
3492 addBuf(&bufs, @ptrCast(wasm.object_global_imports.keys()));
3493 addBuf(&bufs, @ptrCast(wasm.object_global_imports.values()));
3494 addBuf(&bufs, @ptrCast(wasm.object_globals.items));
3495 addBuf(&bufs, @ptrCast(wasm.object_table_imports.keys()));
3496 addBuf(&bufs, @ptrCast(wasm.object_table_imports.values()));
3497 addBuf(&bufs, @ptrCast(wasm.object_tables.items));
3498 addBuf(&bufs, @ptrCast(wasm.object_memory_imports.keys()));
3499 addBuf(&bufs, @ptrCast(wasm.object_memory_imports.values()));
3500 addBuf(&bufs, @ptrCast(wasm.object_memories.items));
3501 addBuf(&bufs, @ptrCast(wasm.object_relocations.items(.tag)));
3502 addBuf(&bufs, @ptrCast(wasm.object_relocations.items(.offset)));
35013503 // TODO handle the union safety field
3502 //addBuf(&bufs, mem.sliceAsBytes(wasm.object_relocations.items(.pointee)));
3503 addBuf(&bufs, mem.sliceAsBytes(wasm.object_relocations.items(.addend)));
3504 addBuf(&bufs, mem.sliceAsBytes(wasm.object_init_funcs.items));
3505 addBuf(&bufs, mem.sliceAsBytes(wasm.object_data_segments.items));
3506 addBuf(&bufs, mem.sliceAsBytes(wasm.object_datas.items));
3507 addBuf(&bufs, mem.sliceAsBytes(wasm.object_data_imports.keys()));
3508 addBuf(&bufs, mem.sliceAsBytes(wasm.object_data_imports.values()));
3509 addBuf(&bufs, mem.sliceAsBytes(wasm.object_custom_segments.keys()));
3510 addBuf(&bufs, mem.sliceAsBytes(wasm.object_custom_segments.values()));
3504 //addBuf(&bufs, @ptrCast(wasm.object_relocations.items(.pointee)));
3505 addBuf(&bufs, @ptrCast(wasm.object_relocations.items(.addend)));
3506 addBuf(&bufs, @ptrCast(wasm.object_init_funcs.items));
3507 addBuf(&bufs, @ptrCast(wasm.object_data_segments.items));
3508 addBuf(&bufs, @ptrCast(wasm.object_datas.items));
3509 addBuf(&bufs, @ptrCast(wasm.object_data_imports.keys()));
3510 addBuf(&bufs, @ptrCast(wasm.object_data_imports.values()));
3511 addBuf(&bufs, @ptrCast(wasm.object_custom_segments.keys()));
3512 addBuf(&bufs, @ptrCast(wasm.object_custom_segments.values()));
35113513 // TODO make it well-defined memory layout
3512 // addBuf(&bufs, mem.sliceAsBytes(wasm.object_comdats.items));
3513 addBuf(&bufs, mem.sliceAsBytes(wasm.object_relocations_table.keys()));
3514 addBuf(&bufs, mem.sliceAsBytes(wasm.object_relocations_table.values()));
3515 addBuf(&bufs, mem.sliceAsBytes(wasm.object_comdat_symbols.items(.kind)));
3516 addBuf(&bufs, mem.sliceAsBytes(wasm.object_comdat_symbols.items(.index)));
3517 addBuf(&bufs, mem.sliceAsBytes(wasm.out_relocs.items(.tag)));
3518 addBuf(&bufs, mem.sliceAsBytes(wasm.out_relocs.items(.offset)));
3514 // addBuf(&bufs, @ptrCast(wasm.object_comdats.items));
3515 addBuf(&bufs, @ptrCast(wasm.object_relocations_table.keys()));
3516 addBuf(&bufs, @ptrCast(wasm.object_relocations_table.values()));
3517 addBuf(&bufs, @ptrCast(wasm.object_comdat_symbols.items(.kind)));
3518 addBuf(&bufs, @ptrCast(wasm.object_comdat_symbols.items(.index)));
3519 addBuf(&bufs, @ptrCast(wasm.out_relocs.items(.tag)));
3520 addBuf(&bufs, @ptrCast(wasm.out_relocs.items(.offset)));
35193521 // TODO handle the union safety field
3520 //addBuf(&bufs, mem.sliceAsBytes(wasm.out_relocs.items(.pointee)));
3521 addBuf(&bufs, mem.sliceAsBytes(wasm.out_relocs.items(.addend)));
3522 addBuf(&bufs, mem.sliceAsBytes(wasm.uav_fixups.items));
3523 addBuf(&bufs, mem.sliceAsBytes(wasm.nav_fixups.items));
3524 addBuf(&bufs, mem.sliceAsBytes(wasm.func_table_fixups.items));
3522 //addBuf(&bufs, @ptrCast(wasm.out_relocs.items(.pointee)));
3523 addBuf(&bufs, @ptrCast(wasm.out_relocs.items(.addend)));
3524 addBuf(&bufs, @ptrCast(wasm.uav_fixups.items));
3525 addBuf(&bufs, @ptrCast(wasm.nav_fixups.items));
3526 addBuf(&bufs, @ptrCast(wasm.func_table_fixups.items));
35253527 if (is_obj) {
3526 addBuf(&bufs, mem.sliceAsBytes(wasm.navs_obj.keys()));
3527 addBuf(&bufs, mem.sliceAsBytes(wasm.navs_obj.values()));
3528 addBuf(&bufs, mem.sliceAsBytes(wasm.uavs_obj.keys()));
3529 addBuf(&bufs, mem.sliceAsBytes(wasm.uavs_obj.values()));
3528 addBuf(&bufs, @ptrCast(wasm.navs_obj.keys()));
3529 addBuf(&bufs, @ptrCast(wasm.navs_obj.values()));
3530 addBuf(&bufs, @ptrCast(wasm.uavs_obj.keys()));
3531 addBuf(&bufs, @ptrCast(wasm.uavs_obj.values()));
35303532 } else {
3531 addBuf(&bufs, mem.sliceAsBytes(wasm.navs_exe.keys()));
3532 addBuf(&bufs, mem.sliceAsBytes(wasm.navs_exe.values()));
3533 addBuf(&bufs, mem.sliceAsBytes(wasm.uavs_exe.keys()));
3534 addBuf(&bufs, mem.sliceAsBytes(wasm.uavs_exe.values()));
3533 addBuf(&bufs, @ptrCast(wasm.navs_exe.keys()));
3534 addBuf(&bufs, @ptrCast(wasm.navs_exe.values()));
3535 addBuf(&bufs, @ptrCast(wasm.uavs_exe.keys()));
3536 addBuf(&bufs, @ptrCast(wasm.uavs_exe.values()));
35353537 }
3536 addBuf(&bufs, mem.sliceAsBytes(wasm.overaligned_uavs.keys()));
3537 addBuf(&bufs, mem.sliceAsBytes(wasm.overaligned_uavs.values()));
3538 addBuf(&bufs, mem.sliceAsBytes(wasm.zcu_funcs.keys()));
3538 addBuf(&bufs, @ptrCast(wasm.overaligned_uavs.keys()));
3539 addBuf(&bufs, @ptrCast(wasm.overaligned_uavs.values()));
3540 addBuf(&bufs, @ptrCast(wasm.zcu_funcs.keys()));
35393541 // TODO handle the union safety field
3540 // addBuf(&bufs, mem.sliceAsBytes(wasm.zcu_funcs.values()));
3541 addBuf(&bufs, mem.sliceAsBytes(wasm.nav_exports.keys()));
3542 addBuf(&bufs, mem.sliceAsBytes(wasm.nav_exports.values()));
3543 addBuf(&bufs, mem.sliceAsBytes(wasm.uav_exports.keys()));
3544 addBuf(&bufs, mem.sliceAsBytes(wasm.uav_exports.values()));
3545 addBuf(&bufs, mem.sliceAsBytes(wasm.imports.keys()));
3546 addBuf(&bufs, mem.sliceAsBytes(wasm.missing_exports.keys()));
3547 addBuf(&bufs, mem.sliceAsBytes(wasm.function_exports.keys()));
3548 addBuf(&bufs, mem.sliceAsBytes(wasm.function_exports.values()));
3549 addBuf(&bufs, mem.sliceAsBytes(wasm.hidden_function_exports.keys()));
3550 addBuf(&bufs, mem.sliceAsBytes(wasm.hidden_function_exports.values()));
3551 addBuf(&bufs, mem.sliceAsBytes(wasm.global_exports.items));
3552 addBuf(&bufs, mem.sliceAsBytes(wasm.functions.keys()));
3553 addBuf(&bufs, mem.sliceAsBytes(wasm.function_imports.keys()));
3554 addBuf(&bufs, mem.sliceAsBytes(wasm.function_imports.values()));
3555 addBuf(&bufs, mem.sliceAsBytes(wasm.data_imports.keys()));
3556 addBuf(&bufs, mem.sliceAsBytes(wasm.data_imports.values()));
3557 addBuf(&bufs, mem.sliceAsBytes(wasm.data_segments.keys()));
3558 addBuf(&bufs, mem.sliceAsBytes(wasm.globals.keys()));
3559 addBuf(&bufs, mem.sliceAsBytes(wasm.global_imports.keys()));
3560 addBuf(&bufs, mem.sliceAsBytes(wasm.global_imports.values()));
3561 addBuf(&bufs, mem.sliceAsBytes(wasm.tables.keys()));
3562 addBuf(&bufs, mem.sliceAsBytes(wasm.table_imports.keys()));
3563 addBuf(&bufs, mem.sliceAsBytes(wasm.table_imports.values()));
3564 addBuf(&bufs, mem.sliceAsBytes(wasm.zcu_indirect_function_set.keys()));
3565 addBuf(&bufs, mem.sliceAsBytes(wasm.object_indirect_function_import_set.keys()));
3566 addBuf(&bufs, mem.sliceAsBytes(wasm.object_indirect_function_set.keys()));
3567 addBuf(&bufs, mem.sliceAsBytes(wasm.mir_instructions.items(.tag)));
3542 // addBuf(&bufs, @ptrCast(wasm.zcu_funcs.values()));
3543 addBuf(&bufs, @ptrCast(wasm.nav_exports.keys()));
3544 addBuf(&bufs, @ptrCast(wasm.nav_exports.values()));
3545 addBuf(&bufs, @ptrCast(wasm.uav_exports.keys()));
3546 addBuf(&bufs, @ptrCast(wasm.uav_exports.values()));
3547 addBuf(&bufs, @ptrCast(wasm.imports.keys()));
3548 addBuf(&bufs, @ptrCast(wasm.missing_exports.keys()));
3549 addBuf(&bufs, @ptrCast(wasm.function_exports.keys()));
3550 addBuf(&bufs, @ptrCast(wasm.function_exports.values()));
3551 addBuf(&bufs, @ptrCast(wasm.hidden_function_exports.keys()));
3552 addBuf(&bufs, @ptrCast(wasm.hidden_function_exports.values()));
3553 addBuf(&bufs, @ptrCast(wasm.global_exports.items));
3554 addBuf(&bufs, @ptrCast(wasm.functions.keys()));
3555 addBuf(&bufs, @ptrCast(wasm.function_imports.keys()));
3556 addBuf(&bufs, @ptrCast(wasm.function_imports.values()));
3557 addBuf(&bufs, @ptrCast(wasm.data_imports.keys()));
3558 addBuf(&bufs, @ptrCast(wasm.data_imports.values()));
3559 addBuf(&bufs, @ptrCast(wasm.data_segments.keys()));
3560 addBuf(&bufs, @ptrCast(wasm.globals.keys()));
3561 addBuf(&bufs, @ptrCast(wasm.global_imports.keys()));
3562 addBuf(&bufs, @ptrCast(wasm.global_imports.values()));
3563 addBuf(&bufs, @ptrCast(wasm.tables.keys()));
3564 addBuf(&bufs, @ptrCast(wasm.table_imports.keys()));
3565 addBuf(&bufs, @ptrCast(wasm.table_imports.values()));
3566 addBuf(&bufs, @ptrCast(wasm.zcu_indirect_function_set.keys()));
3567 addBuf(&bufs, @ptrCast(wasm.object_indirect_function_import_set.keys()));
3568 addBuf(&bufs, @ptrCast(wasm.object_indirect_function_set.keys()));
3569 addBuf(&bufs, @ptrCast(wasm.mir_instructions.items(.tag)));
35683570 // TODO handle the union safety field
3569 //addBuf(&bufs, mem.sliceAsBytes(wasm.mir_instructions.items(.data)));
3570 addBuf(&bufs, mem.sliceAsBytes(wasm.mir_extra.items));
3571 addBuf(&bufs, mem.sliceAsBytes(wasm.mir_locals.items));
3572 addBuf(&bufs, mem.sliceAsBytes(wasm.tag_name_bytes.items));
3573 addBuf(&bufs, mem.sliceAsBytes(wasm.tag_name_offs.items));
3571 //addBuf(&bufs, @ptrCast(wasm.mir_instructions.items(.data)));
3572 addBuf(&bufs, @ptrCast(wasm.mir_extra.items));
3573 addBuf(&bufs, @ptrCast(wasm.mir_locals.items));
3574 addBuf(&bufs, @ptrCast(wasm.tag_name_bytes.items));
3575 addBuf(&bufs, @ptrCast(wasm.tag_name_offs.items));
35743576
35753577 // TODO add as header fields
35763578 // entry_resolution: FunctionImport.Resolution
......@@ -3596,16 +3598,16 @@ pub fn saveState(comp: *Compilation) !void {
35963598
35973599 // Using an atomic file prevents a crash or power failure from corrupting
35983600 // 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 });
36003603 defer af.deinit();
3601 try af.file.pwritevAll(bufs.items, 0);
3604 try af.file_writer.interface.writeVecAll(bufs.items);
36023605 try af.finish();
36033606}
36043607
3605fn addBuf(list: *std.ArrayList(std.posix.iovec_const), buf: []const u8) void {
3606 // Even when len=0, the undefined pointer might cause EFAULT.
3608fn addBuf(list: *std.ArrayList([]const u8), buf: []const u8) void {
36073609 if (buf.len == 0) return;
3608 list.appendAssumeCapacity(.{ .base = buf.ptr, .len = buf.len });
3610 list.appendAssumeCapacity(buf);
36093611}
36103612
36113613/// This function is temporally single-threaded.
......@@ -4862,6 +4864,9 @@ fn docsCopyFallible(comp: *Compilation) anyerror!void {
48624864 };
48634865 defer tar_file.close();
48644866
4867 var buffer: [1024]u8 = undefined;
4868 var tar_file_writer = tar_file.writer(&buffer);
4869
48654870 var seen_table: std.AutoArrayHashMapUnmanaged(*Package.Module, []const u8) = .empty;
48664871 defer seen_table.deinit(comp.gpa);
48674872
......@@ -4871,32 +4876,45 @@ fn docsCopyFallible(comp: *Compilation) anyerror!void {
48714876 var i: usize = 0;
48724877 while (i < seen_table.count()) : (i += 1) {
48734878 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
48764881 const deps = mod.deps.values();
48774882 try seen_table.ensureUnusedCapacity(comp.gpa, deps.len);
48784883 for (deps) |dep| seen_table.putAssumeCapacity(dep, dep.fully_qualified_name);
48794884 }
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 };
48804893}
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 {
48834901 const root = module.root;
48844902 var mod_dir = d: {
48854903 const root_dir, const sub_path = root.openInfo(comp.dirs);
48864904 break :d root_dir.openDir(sub_path, .{ .iterate = true });
48874905 } catch |err| {
4888 return comp.lockAndSetMiscFailure(.docs_copy, "unable to open directory '{f}': {s}", .{
4889 root.fmt(comp), @errorName(err),
4890 });
4906 return comp.lockAndSetMiscFailure(.docs_copy, "unable to open directory '{f}': {t}", .{ root.fmt(comp), err });
48914907 };
48924908 defer mod_dir.close();
48934909
48944910 var walker = try mod_dir.walk(comp.gpa);
48954911 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 };
48984914 archiver.prefix = name;
48994915
4916 var buffer: [1024]u8 = undefined;
4917
49004918 while (try walker.next()) |entry| {
49014919 switch (entry.kind) {
49024920 .file => {
......@@ -4907,14 +4925,17 @@ fn docsCopyModule(comp: *Compilation, module: *Package.Module, name: []const u8,
49074925 else => continue,
49084926 }
49094927 var file = mod_dir.openFile(entry.path, .{}) catch |err| {
4910 return comp.lockAndSetMiscFailure(.docs_copy, "unable to open '{f}{s}': {s}", .{
4911 root.fmt(comp), entry.path, @errorName(err),
4928 return comp.lockAndSetMiscFailure(.docs_copy, "unable to open {f}{s}: {t}", .{
4929 root.fmt(comp), entry.path, err,
49124930 });
49134931 };
49144932 defer file.close();
4915 archiver.writeFile(entry.path, file) catch |err| {
4916 return comp.lockAndSetMiscFailure(.docs_copy, "unable to archive '{f}{s}': {s}", .{
4917 root.fmt(comp), entry.path, @errorName(err),
4933 const stat = try file.stat();
4934 var file_reader: fs.File.Reader = .initSize(file, &buffer, stat.size);
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,
49184939 });
49194940 };
49204941 }
......@@ -4926,9 +4947,7 @@ fn workerDocsWasm(comp: *Compilation, parent_prog_node: std.Progress.Node) void
49264947
49274948 workerDocsWasmFallible(comp, prog_node) catch |err| switch (err) {
49284949 error.SubCompilationFailed => return, // error reported already
4929 else => comp.lockAndSetMiscFailure(.docs_wasm, "unable to build autodocs: {s}", .{
4930 @errorName(err),
4931 }),
4950 else => comp.lockAndSetMiscFailure(.docs_wasm, "unable to build autodocs: {t}", .{err}),
49324951 };
49334952}
49344953
......@@ -6206,19 +6225,20 @@ fn spawnZigRc(
62066225 return comp.failWin32Resource(win32_resource, "unable to spawn {s} rc: {s}", .{ argv[0], @errorName(err) });
62076226 };
62086227
6209 var poller = std.io.poll(comp.gpa, enum { stdout }, .{
6228 var poller = std.Io.poll(comp.gpa, enum { stdout, stderr }, .{
62106229 .stdout = child.stdout.?,
6230 .stderr = child.stderr.?,
62116231 });
62126232 defer poller.deinit();
62136233
6214 const stdout = poller.fifo(.stdout);
6234 const stdout = poller.reader(.stdout);
62156235
62166236 poll: while (true) {
6217 while (stdout.readableLength() < @sizeOf(std.zig.Server.Message.Header)) if (!try poller.poll()) break :poll;
6218 var header: std.zig.Server.Message.Header = undefined;
6219 assert(stdout.read(std.mem.asBytes(&header)) == @sizeOf(std.zig.Server.Message.Header));
6220 while (stdout.readableLength() < header.bytes_len) if (!try poller.poll()) break :poll;
6221 const body = stdout.readableSliceOfLen(header.bytes_len);
6237 const MessageHeader = std.zig.Server.Message.Header;
6238 while (stdout.buffered().len < @sizeOf(MessageHeader)) if (!try poller.poll()) break :poll;
6239 const header = stdout.takeStruct(MessageHeader, .little) catch unreachable;
6240 while (stdout.buffered().len < header.bytes_len) if (!try poller.poll()) break :poll;
6241 const body = stdout.take(header.bytes_len) catch unreachable;
62226242
62236243 switch (header.tag) {
62246244 // We expect exactly one ErrorBundle, and if any error_bundle header is
......@@ -6241,13 +6261,10 @@ fn spawnZigRc(
62416261 },
62426262 else => {}, // ignore other messages
62436263 }
6244
6245 stdout.discard(body.len);
62466264 }
62476265
62486266 // 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();
6250 const stderr = try stderr_reader.readAllAlloc(arena, 10 * 1024 * 1024);
6267 const stderr = poller.reader(.stderr);
62516268
62526269 const term = child.wait() catch |err| {
62536270 return comp.failWin32Resource(win32_resource, "unable to wait for {s} rc: {s}", .{ argv[0], @errorName(err) });
......@@ -6256,12 +6273,12 @@ fn spawnZigRc(
62566273 switch (term) {
62576274 .Exited => |code| {
62586275 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()});
62606277 return comp.failWin32Resource(win32_resource, "zig rc exited with code {d}", .{code});
62616278 }
62626279 },
62636280 else => {
6264 log.err("zig rc terminated with stderr:\n{s}", .{stderr});
6281 log.err("zig rc terminated with stderr:\n{s}", .{stderr.buffered()});
62656282 return comp.failWin32Resource(win32_resource, "zig rc terminated unexpectedly", .{});
62666283 },
62676284 }
src/InternPool.zig+10-4
......@@ -7556,12 +7556,18 @@ fn extraFuncCoerced(ip: *const InternPool, extra: Local.Extra, extra_index: u32)
75567556fn indexToKeyBigInt(ip: *const InternPool, tid: Zcu.PerThread.Id, limb_index: u32, positive: bool) Key {
75577557 const limbs_items = ip.getLocalShared(tid).getLimbs().view().items(.@"0");
75587558 const int: Int = @bitCast(limbs_items[limb_index..][0..Int.limbs_items_len].*);
7559 const big_int: BigIntConst = .{
7560 .limbs = limbs_items[limb_index + Int.limbs_items_len ..][0..int.limbs_len],
7561 .positive = positive,
7562 };
75597563 return .{ .int = .{
75607564 .ty = int.ty,
7561 .storage = .{ .big_int = .{
7562 .limbs = limbs_items[limb_index + Int.limbs_items_len ..][0..int.limbs_len],
7563 .positive = positive,
7564 } },
7565 .storage = if (big_int.toInt(u64)) |x|
7566 .{ .u64 = x }
7567 else |_| if (big_int.toInt(i64)) |x|
7568 .{ .i64 = x }
7569 else |_|
7570 .{ .big_int = big_int },
75657571 } };
75667572}
75677573
src/Package/Fetch.zig+22-14
......@@ -1197,12 +1197,18 @@ fn unpackResource(
11971197 };
11981198
11991199 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 },
12011205 .@"tar.gz" => {
12021206 const reader = resource.reader();
12031207 var br = std.io.bufferedReaderSize(std.crypto.tls.max_ciphertext_record_len, reader);
12041208 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);
12061212 },
12071213 .@"tar.xz" => {
12081214 const gpa = f.arena.child_allocator;
......@@ -1215,17 +1221,19 @@ fn unpackResource(
12151221 ));
12161222 };
12171223 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);
12191227 },
12201228 .@"tar.zst" => {
1221 const window_size = std.compress.zstd.DecompressorOptions.default_window_buffer_len;
1229 const window_size = std.compress.zstd.default_window_len;
12221230 const window_buffer = try f.arena.allocator().create([window_size]u8);
1223 const reader = resource.reader();
1224 var br = std.io.bufferedReaderSize(std.crypto.tls.max_ciphertext_record_len, reader);
1225 var dcp = std.compress.zstd.decompressor(br.reader(), .{
1226 .window_buffer = window_buffer,
1231 var adapter_buffer: [std.crypto.tls.max_ciphertext_record_len]u8 = undefined;
1232 var adapter = resource.reader().adaptToNewApi(&adapter_buffer);
1233 var decompress: std.compress.zstd.Decompress = .init(&adapter.new_interface, window_buffer, .{
1234 .verify_checksum = false,
12271235 });
1228 return try unpackTarball(f, tmp_directory.handle, dcp.reader());
1236 return try unpackTarball(f, tmp_directory.handle, &decompress.reader);
12291237 },
12301238 .git_pack => return unpackGitPack(f, tmp_directory.handle, &resource.git) catch |err| switch (err) {
12311239 error.FetchFailed => return error.FetchFailed,
......@@ -1239,7 +1247,7 @@ fn unpackResource(
12391247 }
12401248}
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 {
12431251 const eb = &f.error_bundle;
12441252 const arena = f.arena.allocator();
12451253
......@@ -1250,10 +1258,10 @@ fn unpackTarball(f: *Fetch, out_dir: fs.Dir, reader: anytype) RunError!UnpackRes
12501258 .strip_components = 0,
12511259 .mode_mode = .ignore,
12521260 .exclude_empty_directories = true,
1253 }) catch |err| return f.fail(f.location_tok, try eb.printString(
1254 "unable to unpack tarball to temporary directory: {s}",
1255 .{@errorName(err)},
1256 ));
1261 }) catch |err| return f.fail(
1262 f.location_tok,
1263 try eb.printString("unable to unpack tarball to temporary directory: {t}", .{err}),
1264 );
12571265
12581266 var res: UnpackResult = .{ .root_dir = diagnostics.root_dir };
12591267 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
12811281 }
12821282 @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));
12851285 const writer = index_hashed_writer.writer();
12861286 try writer.writeAll(IndexHeader.signature);
12871287 try writer.writeInt(u32, IndexHeader.supported_version, .big);
......@@ -1331,7 +1331,7 @@ fn indexPackFirstPass(
13311331) !Oid {
13321332 var pack_buffered_reader = std.io.bufferedReader(pack.deprecatedReader());
13331333 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));
13351335 const pack_reader = pack_hashed_reader.reader();
13361336
13371337 const pack_header = try PackHeader.read(pack_reader);
......@@ -1339,13 +1339,13 @@ fn indexPackFirstPass(
13391339 var current_entry: u32 = 0;
13401340 while (current_entry < pack_header.total_objects) : (current_entry += 1) {
13411341 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());
13431343 const entry_header = try EntryHeader.read(format, entry_crc32_reader.reader());
13441344 switch (entry_header) {
13451345 .commit, .tree, .blob, .tag => |object| {
13461346 var entry_decompress_stream = std.compress.zlib.decompressor(entry_crc32_reader.reader());
13471347 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));
13491349 const entry_writer = entry_hashed_writer.writer();
13501350 // The object header is not included in the pack data but is
13511351 // part of the object's ID
......@@ -1432,7 +1432,7 @@ fn indexPackHashDelta(
14321432 const base_data = try resolveDeltaChain(allocator, format, pack, base_object, delta_offsets.items, cache);
14331433
14341434 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);
14361436 try entry_hashed_writer.writer().print("{s} {}\x00", .{ @tagName(base_object.type), base_data.len });
14371437 entry_hasher.update(base_data);
14381438 return entry_hasher.finalResult();
......@@ -1703,3 +1703,58 @@ pub fn main() !void {
17031703 std.debug.print("Diagnostic: {}\n", .{err});
17041704 }
17051705}
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 {
250250 };
251251
252252 const stack_check = b: {
253 if (!target_util.supportsStackProbing(target)) {
253 if (!target_util.supportsStackProbing(target, zig_backend)) {
254254 if (options.inherited.stack_check == true)
255255 return error.StackCheckUnsupportedByTarget;
256256 break :b false;
src/Sema.zig+19-12
......@@ -16522,7 +16522,7 @@ fn zirAsm(
1652216522 break :empty try sema.structInitEmpty(block, clobbers_ty, src, src);
1652316523 } else try sema.resolveInst(extra.data.clobbers); // Already coerced by AstGen.
1652416524 const clobbers_val = try sema.resolveConstDefinedValue(block, src, clobbers, .{ .simple = .clobber });
16525 needed_capacity += (asm_source.len + 3) / 4;
16525 needed_capacity += asm_source.len / 4 + 1;
1652616526
1652716527 const gpa = sema.gpa;
1652816528 try sema.air_extra.ensureUnusedCapacity(gpa, needed_capacity);
......@@ -16562,7 +16562,8 @@ fn zirAsm(
1656216562 {
1656316563 const buffer = mem.sliceAsBytes(sema.air_extra.unusedCapacitySlice());
1656416564 @memcpy(buffer[0..asm_source.len], asm_source);
16565 sema.air_extra.items.len += (asm_source.len + 3) / 4;
16565 buffer[asm_source.len] = 0;
16566 sema.air_extra.items.len += asm_source.len / 4 + 1;
1656616567 }
1656716568 return asm_air;
1656816569}
......@@ -22482,11 +22483,18 @@ fn ptrCastFull(
2248222483 .slice => {},
2248322484 .many, .c, .one => break :len null,
2248422485 }
22485 // `null` 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 .one => 1,
22488 .slice => src_len: {
22489 const operand_val = try sema.resolveValue(operand) orelse break :src_len null;
22486 // A `null` length means the operand is a runtime-known slice (so the length is runtime-known).
22487 // `src_elem_type` is different from `src_info.child` if the latter is an array, to ensure we ignore sentinels.
22488 const src_elem_ty: Type, const opt_src_len: ?u64 = switch (src_info.flags.size) {
22489 .one => src: {
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 };
2249022498 if (operand_val.isUndef(zcu)) break :len .undef;
2249122499 const slice_val = switch (operand_ty.zigTypeTag(zcu)) {
2249222500 .optional => operand_val.optionalValue(zcu) orelse break :len .undef,
......@@ -22495,14 +22503,13 @@ fn ptrCastFull(
2249522503 };
2249622504 const slice_len_resolved = try sema.resolveLazyValue(.fromInterned(zcu.intern_pool.sliceLen(slice_val.toIntern())));
2249722505 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) };
2249922507 },
2250022508 .many, .c => {
2250122509 return sema.fail(block, src, "cannot infer length of slice from {s}", .{pointerSizeString(src_info.flags.size)});
2250222510 },
2250322511 };
2250422512 const dest_elem_ty: Type = .fromInterned(dest_info.child);
22505 const src_elem_ty: Type = .fromInterned(src_info.child);
2250622513 if (dest_elem_ty.toIntern() == src_elem_ty.toIntern()) {
2250722514 break :len if (opt_src_len) |l| .{ .constant = l } else .equal_runtime_src_slice;
2250822515 }
......@@ -22518,7 +22525,7 @@ fn ptrCastFull(
2251822525 const bytes = src_len * src_elem_size;
2251922526 const dest_len = std.math.divExact(u64, bytes, dest_elem_size) catch switch (src_info.flags.size) {
2252022527 .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)}),
2252222529 else => unreachable,
2252322530 };
2252422531 break :len .{ .constant = dest_len };
......@@ -24846,7 +24853,7 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins
2484624853 },
2484724854 .@"packed" => {
2484824855 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) -
2485024857 actual_field_ptr_info.packed_offset.bit_offset), 8) catch
2485124858 return sema.fail(block, inst_src, "pointer bit-offset mismatch", .{});
2485224859 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
2487324880 // Logic lifted from type computation above - I'm just assuming it's correct.
2487424881 // `catch unreachable` since error case handled above.
2487524882 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) -
2487724884 actual_field_ptr_info.packed_offset.bit_offset), 8) catch unreachable;
2487824885 const parent_ptr_val = try sema.ptrSubtract(block, field_ptr_src, field_ptr_val, byte_offset, actual_parent_ptr_ty);
2487924886 break :result Air.internedToRef(parent_ptr_val.toIntern());
src/Type.zig+1-1
......@@ -4166,7 +4166,7 @@ pub const generic_poison: Type = .{ .ip_index = .generic_poison_type };
41664166pub fn smallestUnsignedBits(max: u64) u16 {
41674167 return switch (max) {
41684168 0 => 0,
4169 else => 1 + std.math.log2_int(u64, max),
4169 else => @as(u16, 1) + std.math.log2_int(u64, max),
41704170 };
41714171}
41724172
src/Zcu.zig+24-5
......@@ -3891,6 +3891,29 @@ pub fn typeToPackedStruct(zcu: *const Zcu, ty: Type) ?InternPool.LoadedStructTyp
38913891 return s;
38923892}
38933893
3894/// https://github.com/ziglang/zig/issues/17178 explored storing these bit offsets
3895/// into the packed struct InternPool data rather than computing this on the
3896/// fly, however it was found to perform worse when measured on real world
3897/// projects.
3898pub fn structPackedFieldBitOffset(
3899 zcu: *Zcu,
3900 struct_type: InternPool.LoadedStructType,
3901 field_index: u32,
3902) u16 {
3903 const ip = &zcu.intern_pool;
3904 assert(struct_type.layout == .@"packed");
3905 assert(struct_type.haveLayout(ip));
3906 var bit_sum: u64 = 0;
3907 for (0..struct_type.field_types.len) |i| {
3908 if (i == field_index) {
3909 return @intCast(bit_sum);
3910 }
3911 const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[i]);
3912 bit_sum += field_ty.bitSize(zcu);
3913 }
3914 unreachable; // index out of bounds
3915}
3916
38943917pub fn typeToUnion(zcu: *const Zcu, ty: Type) ?InternPool.LoadedUnionType {
38953918 if (ty.ip_index == .none) return null;
38963919 const ip = &zcu.intern_pool;
......@@ -4436,11 +4459,7 @@ pub fn callconvSupported(zcu: *Zcu, cc: std.builtin.CallingConvention) union(enu
44364459 else => false,
44374460 },
44384461 .stage2_aarch64 => switch (cc) {
4439 .aarch64_aapcs,
4440 .aarch64_aapcs_darwin,
4441 .aarch64_aapcs_win,
4442 => |opts| opts.incoming_stack_alignment == null,
4443 .naked => true,
4462 .aarch64_aapcs, .aarch64_aapcs_darwin, .naked => true,
44444463 else => false,
44454464 },
44464465 .stage2_x86 => switch (cc) {
src/Zcu/PerThread.zig+7-28
......@@ -3737,30 +3737,6 @@ pub fn intBitsForValue(pt: Zcu.PerThread, val: Value, sign: bool) u16 {
37373737 }
37383738}
37393739
3740/// https://github.com/ziglang/zig/issues/17178 explored storing these bit offsets
3741/// into the packed struct InternPool data rather than computing this on the
3742/// fly, however it was found to perform worse when measured on real world
3743/// projects.
3744pub fn structPackedFieldBitOffset(
3745 pt: Zcu.PerThread,
3746 struct_type: InternPool.LoadedStructType,
3747 field_index: u32,
3748) u16 {
3749 const zcu = pt.zcu;
3750 const ip = &zcu.intern_pool;
3751 assert(struct_type.layout == .@"packed");
3752 assert(struct_type.haveLayout(ip));
3753 var bit_sum: u64 = 0;
3754 for (0..struct_type.field_types.len) |i| {
3755 if (i == field_index) {
3756 return @intCast(bit_sum);
3757 }
3758 const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[i]);
3759 bit_sum += field_ty.bitSize(zcu);
3760 }
3761 unreachable; // index out of bounds
3762}
3763
37643740pub fn navPtrType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Allocator.Error!Type {
37653741 const zcu = pt.zcu;
37663742 const ip = &zcu.intern_pool;
......@@ -4381,8 +4357,11 @@ fn runCodegenInner(pt: Zcu.PerThread, func_index: InternPool.Index, air: *Air) e
43814357 try air.legalize(pt, features);
43824358 }
43834359
4384 var liveness: Air.Liveness = try .analyze(zcu, air.*, ip);
4385 defer liveness.deinit(gpa);
4360 var liveness: ?Air.Liveness = if (codegen.wantsLiveness(pt, nav))
4361 try .analyze(zcu, air.*, ip)
4362 else
4363 null;
4364 defer if (liveness) |*l| l.deinit(gpa);
43864365
43874366 if (build_options.enable_debug_extensions and comp.verbose_air) {
43884367 const stderr = std.debug.lockStderrWriter(&.{});
......@@ -4392,12 +4371,12 @@ fn runCodegenInner(pt: Zcu.PerThread, func_index: InternPool.Index, air: *Air) e
43924371 stderr.print("# End Function AIR: {f}\n\n", .{fqn.fmt(ip)}) catch {};
43934372 }
43944373
4395 if (std.debug.runtime_safety) {
4374 if (std.debug.runtime_safety) verify_liveness: {
43964375 var verify: Air.Liveness.Verify = .{
43974376 .gpa = gpa,
43984377 .zcu = zcu,
43994378 .air = air.*,
4400 .liveness = liveness,
4379 .liveness = liveness orelse break :verify_liveness,
44014380 .intern_pool = ip,
44024381 };
44034382 defer verify.deinit();
src/arch/aarch64/bits.zig deleted-2063
......@@ -1,2063 +0,0 @@
1const std = @import("std");
2const builtin = @import("builtin");
3const assert = std.debug.assert;
4const testing = std.testing;
5
6/// Disjoint sets of registers. Every register must belong to
7/// exactly one register class.
8pub const RegisterClass = enum {
9 general_purpose,
10 stack_pointer,
11 floating_point,
12};
13
14/// Registers in the AArch64 instruction set
15pub const Register = enum(u8) {
16 // zig fmt: off
17 // 64-bit general-purpose registers
18 x0, x1, x2, x3, x4, x5, x6, x7,
19 x8, x9, x10, x11, x12, x13, x14, x15,
20 x16, x17, x18, x19, x20, x21, x22, x23,
21 x24, x25, x26, x27, x28, x29, x30, xzr,
22
23 // 32-bit general-purpose registers
24 w0, w1, w2, w3, w4, w5, w6, w7,
25 w8, w9, w10, w11, w12, w13, w14, w15,
26 w16, w17, w18, w19, w20, w21, w22, w23,
27 w24, w25, w26, w27, w28, w29, w30, wzr,
28
29 // Stack pointer
30 sp, wsp,
31
32 // 128-bit floating-point registers
33 q0, q1, q2, q3, q4, q5, q6, q7,
34 q8, q9, q10, q11, q12, q13, q14, q15,
35 q16, q17, q18, q19, q20, q21, q22, q23,
36 q24, q25, q26, q27, q28, q29, q30, q31,
37
38 // 64-bit floating-point registers
39 d0, d1, d2, d3, d4, d5, d6, d7,
40 d8, d9, d10, d11, d12, d13, d14, d15,
41 d16, d17, d18, d19, d20, d21, d22, d23,
42 d24, d25, d26, d27, d28, d29, d30, d31,
43
44 // 32-bit floating-point registers
45 s0, s1, s2, s3, s4, s5, s6, s7,
46 s8, s9, s10, s11, s12, s13, s14, s15,
47 s16, s17, s18, s19, s20, s21, s22, s23,
48 s24, s25, s26, s27, s28, s29, s30, s31,
49
50 // 16-bit floating-point registers
51 h0, h1, h2, h3, h4, h5, h6, h7,
52 h8, h9, h10, h11, h12, h13, h14, h15,
53 h16, h17, h18, h19, h20, h21, h22, h23,
54 h24, h25, h26, h27, h28, h29, h30, h31,
55
56 // 8-bit floating-point registers
57 b0, b1, b2, b3, b4, b5, b6, b7,
58 b8, b9, b10, b11, b12, b13, b14, b15,
59 b16, b17, b18, b19, b20, b21, b22, b23,
60 b24, b25, b26, b27, b28, b29, b30, b31,
61 // zig fmt: on
62
63 pub fn class(self: Register) RegisterClass {
64 return switch (@intFromEnum(self)) {
65 @intFromEnum(Register.x0)...@intFromEnum(Register.xzr) => .general_purpose,
66 @intFromEnum(Register.w0)...@intFromEnum(Register.wzr) => .general_purpose,
67
68 @intFromEnum(Register.sp) => .stack_pointer,
69 @intFromEnum(Register.wsp) => .stack_pointer,
70
71 @intFromEnum(Register.q0)...@intFromEnum(Register.q31) => .floating_point,
72 @intFromEnum(Register.d0)...@intFromEnum(Register.d31) => .floating_point,
73 @intFromEnum(Register.s0)...@intFromEnum(Register.s31) => .floating_point,
74 @intFromEnum(Register.h0)...@intFromEnum(Register.h31) => .floating_point,
75 @intFromEnum(Register.b0)...@intFromEnum(Register.b31) => .floating_point,
76 else => unreachable,
77 };
78 }
79
80 pub fn id(self: Register) u6 {
81 return switch (@intFromEnum(self)) {
82 @intFromEnum(Register.x0)...@intFromEnum(Register.xzr) => @as(u6, @intCast(@intFromEnum(self) - @intFromEnum(Register.x0))),
83 @intFromEnum(Register.w0)...@intFromEnum(Register.wzr) => @as(u6, @intCast(@intFromEnum(self) - @intFromEnum(Register.w0))),
84
85 @intFromEnum(Register.sp) => 32,
86 @intFromEnum(Register.wsp) => 32,
87
88 @intFromEnum(Register.q0)...@intFromEnum(Register.q31) => @as(u6, @intCast(@intFromEnum(self) - @intFromEnum(Register.q0) + 33)),
89 @intFromEnum(Register.d0)...@intFromEnum(Register.d31) => @as(u6, @intCast(@intFromEnum(self) - @intFromEnum(Register.d0) + 33)),
90 @intFromEnum(Register.s0)...@intFromEnum(Register.s31) => @as(u6, @intCast(@intFromEnum(self) - @intFromEnum(Register.s0) + 33)),
91 @intFromEnum(Register.h0)...@intFromEnum(Register.h31) => @as(u6, @intCast(@intFromEnum(self) - @intFromEnum(Register.h0) + 33)),
92 @intFromEnum(Register.b0)...@intFromEnum(Register.b31) => @as(u6, @intCast(@intFromEnum(self) - @intFromEnum(Register.b0) + 33)),
93 else => unreachable,
94 };
95 }
96
97 pub fn enc(self: Register) u5 {
98 return switch (@intFromEnum(self)) {
99 @intFromEnum(Register.x0)...@intFromEnum(Register.xzr) => @as(u5, @intCast(@intFromEnum(self) - @intFromEnum(Register.x0))),
100 @intFromEnum(Register.w0)...@intFromEnum(Register.wzr) => @as(u5, @intCast(@intFromEnum(self) - @intFromEnum(Register.w0))),
101
102 @intFromEnum(Register.sp) => 31,
103 @intFromEnum(Register.wsp) => 31,
104
105 @intFromEnum(Register.q0)...@intFromEnum(Register.q31) => @as(u5, @intCast(@intFromEnum(self) - @intFromEnum(Register.q0))),
106 @intFromEnum(Register.d0)...@intFromEnum(Register.d31) => @as(u5, @intCast(@intFromEnum(self) - @intFromEnum(Register.d0))),
107 @intFromEnum(Register.s0)...@intFromEnum(Register.s31) => @as(u5, @intCast(@intFromEnum(self) - @intFromEnum(Register.s0))),
108 @intFromEnum(Register.h0)...@intFromEnum(Register.h31) => @as(u5, @intCast(@intFromEnum(self) - @intFromEnum(Register.h0))),
109 @intFromEnum(Register.b0)...@intFromEnum(Register.b31) => @as(u5, @intCast(@intFromEnum(self) - @intFromEnum(Register.b0))),
110 else => unreachable,
111 };
112 }
113
114 /// Returns the bit-width of the register.
115 pub fn size(self: Register) u8 {
116 return switch (@intFromEnum(self)) {
117 @intFromEnum(Register.x0)...@intFromEnum(Register.xzr) => 64,
118 @intFromEnum(Register.w0)...@intFromEnum(Register.wzr) => 32,
119
120 @intFromEnum(Register.sp) => 64,
121 @intFromEnum(Register.wsp) => 32,
122
123 @intFromEnum(Register.q0)...@intFromEnum(Register.q31) => 128,
124 @intFromEnum(Register.d0)...@intFromEnum(Register.d31) => 64,
125 @intFromEnum(Register.s0)...@intFromEnum(Register.s31) => 32,
126 @intFromEnum(Register.h0)...@intFromEnum(Register.h31) => 16,
127 @intFromEnum(Register.b0)...@intFromEnum(Register.b31) => 8,
128 else => unreachable,
129 };
130 }
131
132 /// Convert from a general-purpose register to its 64 bit alias.
133 pub fn toX(self: Register) Register {
134 return switch (@intFromEnum(self)) {
135 @intFromEnum(Register.x0)...@intFromEnum(Register.xzr) => @as(
136 Register,
137 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.x0) + @intFromEnum(Register.x0)),
138 ),
139 @intFromEnum(Register.w0)...@intFromEnum(Register.wzr) => @as(
140 Register,
141 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.w0) + @intFromEnum(Register.x0)),
142 ),
143 else => unreachable,
144 };
145 }
146
147 /// Convert from a general-purpose register to its 32 bit alias.
148 pub fn toW(self: Register) Register {
149 return switch (@intFromEnum(self)) {
150 @intFromEnum(Register.x0)...@intFromEnum(Register.xzr) => @as(
151 Register,
152 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.x0) + @intFromEnum(Register.w0)),
153 ),
154 @intFromEnum(Register.w0)...@intFromEnum(Register.wzr) => @as(
155 Register,
156 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.w0) + @intFromEnum(Register.w0)),
157 ),
158 else => unreachable,
159 };
160 }
161
162 /// Convert from a floating-point register to its 128 bit alias.
163 pub fn toQ(self: Register) Register {
164 return switch (@intFromEnum(self)) {
165 @intFromEnum(Register.q0)...@intFromEnum(Register.q31) => @as(
166 Register,
167 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.q0) + @intFromEnum(Register.q0)),
168 ),
169 @intFromEnum(Register.d0)...@intFromEnum(Register.d31) => @as(
170 Register,
171 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.d0) + @intFromEnum(Register.q0)),
172 ),
173 @intFromEnum(Register.s0)...@intFromEnum(Register.s31) => @as(
174 Register,
175 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.s0) + @intFromEnum(Register.q0)),
176 ),
177 @intFromEnum(Register.h0)...@intFromEnum(Register.h31) => @as(
178 Register,
179 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.h0) + @intFromEnum(Register.q0)),
180 ),
181 @intFromEnum(Register.b0)...@intFromEnum(Register.b31) => @as(
182 Register,
183 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.b0) + @intFromEnum(Register.q0)),
184 ),
185 else => unreachable,
186 };
187 }
188
189 /// Convert from a floating-point register to its 64 bit alias.
190 pub fn toD(self: Register) Register {
191 return switch (@intFromEnum(self)) {
192 @intFromEnum(Register.q0)...@intFromEnum(Register.q31) => @as(
193 Register,
194 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.q0) + @intFromEnum(Register.d0)),
195 ),
196 @intFromEnum(Register.d0)...@intFromEnum(Register.d31) => @as(
197 Register,
198 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.d0) + @intFromEnum(Register.d0)),
199 ),
200 @intFromEnum(Register.s0)...@intFromEnum(Register.s31) => @as(
201 Register,
202 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.s0) + @intFromEnum(Register.d0)),
203 ),
204 @intFromEnum(Register.h0)...@intFromEnum(Register.h31) => @as(
205 Register,
206 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.h0) + @intFromEnum(Register.d0)),
207 ),
208 @intFromEnum(Register.b0)...@intFromEnum(Register.b31) => @as(
209 Register,
210 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.b0) + @intFromEnum(Register.d0)),
211 ),
212 else => unreachable,
213 };
214 }
215
216 /// Convert from a floating-point register to its 32 bit alias.
217 pub fn toS(self: Register) Register {
218 return switch (@intFromEnum(self)) {
219 @intFromEnum(Register.q0)...@intFromEnum(Register.q31) => @as(
220 Register,
221 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.q0) + @intFromEnum(Register.s0)),
222 ),
223 @intFromEnum(Register.d0)...@intFromEnum(Register.d31) => @as(
224 Register,
225 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.d0) + @intFromEnum(Register.s0)),
226 ),
227 @intFromEnum(Register.s0)...@intFromEnum(Register.s31) => @as(
228 Register,
229 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.s0) + @intFromEnum(Register.s0)),
230 ),
231 @intFromEnum(Register.h0)...@intFromEnum(Register.h31) => @as(
232 Register,
233 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.h0) + @intFromEnum(Register.s0)),
234 ),
235 @intFromEnum(Register.b0)...@intFromEnum(Register.b31) => @as(
236 Register,
237 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.b0) + @intFromEnum(Register.s0)),
238 ),
239 else => unreachable,
240 };
241 }
242
243 /// Convert from a floating-point register to its 16 bit alias.
244 pub fn toH(self: Register) Register {
245 return switch (@intFromEnum(self)) {
246 @intFromEnum(Register.q0)...@intFromEnum(Register.q31) => @as(
247 Register,
248 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.q0) + @intFromEnum(Register.h0)),
249 ),
250 @intFromEnum(Register.d0)...@intFromEnum(Register.d31) => @as(
251 Register,
252 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.d0) + @intFromEnum(Register.h0)),
253 ),
254 @intFromEnum(Register.s0)...@intFromEnum(Register.s31) => @as(
255 Register,
256 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.s0) + @intFromEnum(Register.h0)),
257 ),
258 @intFromEnum(Register.h0)...@intFromEnum(Register.h31) => @as(
259 Register,
260 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.h0) + @intFromEnum(Register.h0)),
261 ),
262 @intFromEnum(Register.b0)...@intFromEnum(Register.b31) => @as(
263 Register,
264 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.b0) + @intFromEnum(Register.h0)),
265 ),
266 else => unreachable,
267 };
268 }
269
270 /// Convert from a floating-point register to its 8 bit alias.
271 pub fn toB(self: Register) Register {
272 return switch (@intFromEnum(self)) {
273 @intFromEnum(Register.q0)...@intFromEnum(Register.q31) => @as(
274 Register,
275 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.q0) + @intFromEnum(Register.b0)),
276 ),
277 @intFromEnum(Register.d0)...@intFromEnum(Register.d31) => @as(
278 Register,
279 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.d0) + @intFromEnum(Register.b0)),
280 ),
281 @intFromEnum(Register.s0)...@intFromEnum(Register.s31) => @as(
282 Register,
283 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.s0) + @intFromEnum(Register.b0)),
284 ),
285 @intFromEnum(Register.h0)...@intFromEnum(Register.h31) => @as(
286 Register,
287 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.h0) + @intFromEnum(Register.b0)),
288 ),
289 @intFromEnum(Register.b0)...@intFromEnum(Register.b31) => @as(
290 Register,
291 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.b0) + @intFromEnum(Register.b0)),
292 ),
293 else => unreachable,
294 };
295 }
296
297 pub fn dwarfNum(self: Register) u5 {
298 return self.enc();
299 }
300};
301
302test "Register.enc" {
303 try testing.expectEqual(@as(u5, 0), Register.x0.enc());
304 try testing.expectEqual(@as(u5, 0), Register.w0.enc());
305
306 try testing.expectEqual(@as(u5, 31), Register.xzr.enc());
307 try testing.expectEqual(@as(u5, 31), Register.wzr.enc());
308
309 try testing.expectEqual(@as(u5, 31), Register.sp.enc());
310 try testing.expectEqual(@as(u5, 31), Register.sp.enc());
311}
312
313test "Register.size" {
314 try testing.expectEqual(@as(u8, 64), Register.x19.size());
315 try testing.expectEqual(@as(u8, 32), Register.w3.size());
316}
317
318test "Register.toX/toW" {
319 try testing.expectEqual(Register.x0, Register.w0.toX());
320 try testing.expectEqual(Register.x0, Register.x0.toX());
321
322 try testing.expectEqual(Register.w3, Register.w3.toW());
323 try testing.expectEqual(Register.w3, Register.x3.toW());
324}
325
326/// Represents an instruction in the AArch64 instruction set
327pub const Instruction = union(enum) {
328 move_wide_immediate: packed struct {
329 rd: u5,
330 imm16: u16,
331 hw: u2,
332 fixed: u6 = 0b100101,
333 opc: u2,
334 sf: u1,
335 },
336 pc_relative_address: packed struct {
337 rd: u5,
338 immhi: u19,
339 fixed: u5 = 0b10000,
340 immlo: u2,
341 op: u1,
342 },
343 load_store_register: packed struct {
344 rt: u5,
345 rn: u5,
346 offset: u12,
347 opc: u2,
348 op1: u2,
349 v: u1,
350 fixed: u3 = 0b111,
351 size: u2,
352 },
353 load_store_register_pair: packed struct {
354 rt1: u5,
355 rn: u5,
356 rt2: u5,
357 imm7: u7,
358 load: u1,
359 encoding: u2,
360 fixed: u5 = 0b101_0_0,
361 opc: u2,
362 },
363 load_literal: packed struct {
364 rt: u5,
365 imm19: u19,
366 fixed: u6 = 0b011_0_00,
367 opc: u2,
368 },
369 exception_generation: packed struct {
370 ll: u2,
371 op2: u3,
372 imm16: u16,
373 opc: u3,
374 fixed: u8 = 0b1101_0100,
375 },
376 unconditional_branch_register: packed struct {
377 op4: u5,
378 rn: u5,
379 op3: u6,
380 op2: u5,
381 opc: u4,
382 fixed: u7 = 0b1101_011,
383 },
384 unconditional_branch_immediate: packed struct {
385 imm26: u26,
386 fixed: u5 = 0b00101,
387 op: u1,
388 },
389 no_operation: packed struct {
390 fixed: u32 = 0b1101010100_0_00_011_0010_0000_000_11111,
391 },
392 logical_shifted_register: packed struct {
393 rd: u5,
394 rn: u5,
395 imm6: u6,
396 rm: u5,
397 n: u1,
398 shift: u2,
399 fixed: u5 = 0b01010,
400 opc: u2,
401 sf: u1,
402 },
403 add_subtract_immediate: packed struct {
404 rd: u5,
405 rn: u5,
406 imm12: u12,
407 sh: u1,
408 fixed: u6 = 0b100010,
409 s: u1,
410 op: u1,
411 sf: u1,
412 },
413 logical_immediate: packed struct {
414 rd: u5,
415 rn: u5,
416 imms: u6,
417 immr: u6,
418 n: u1,
419 fixed: u6 = 0b100100,
420 opc: u2,
421 sf: u1,
422 },
423 bitfield: packed struct {
424 rd: u5,
425 rn: u5,
426 imms: u6,
427 immr: u6,
428 n: u1,
429 fixed: u6 = 0b100110,
430 opc: u2,
431 sf: u1,
432 },
433 add_subtract_shifted_register: packed struct {
434 rd: u5,
435 rn: u5,
436 imm6: u6,
437 rm: u5,
438 fixed_1: u1 = 0b0,
439 shift: u2,
440 fixed_2: u5 = 0b01011,
441 s: u1,
442 op: u1,
443 sf: u1,
444 },
445 add_subtract_extended_register: packed struct {
446 rd: u5,
447 rn: u5,
448 imm3: u3,
449 option: u3,
450 rm: u5,
451 fixed: u8 = 0b01011_00_1,
452 s: u1,
453 op: u1,
454 sf: u1,
455 },
456 conditional_branch: struct {
457 cond: u4,
458 o0: u1,
459 imm19: u19,
460 o1: u1,
461 fixed: u7 = 0b0101010,
462 },
463 compare_and_branch: struct {
464 rt: u5,
465 imm19: u19,
466 op: u1,
467 fixed: u6 = 0b011010,
468 sf: u1,
469 },
470 conditional_select: struct {
471 rd: u5,
472 rn: u5,
473 op2: u2,
474 cond: u4,
475 rm: u5,
476 fixed: u8 = 0b11010100,
477 s: u1,
478 op: u1,
479 sf: u1,
480 },
481 data_processing_3_source: packed struct {
482 rd: u5,
483 rn: u5,
484 ra: u5,
485 o0: u1,
486 rm: u5,
487 op31: u3,
488 fixed: u5 = 0b11011,
489 op54: u2,
490 sf: u1,
491 },
492 data_processing_2_source: packed struct {
493 rd: u5,
494 rn: u5,
495 opcode: u6,
496 rm: u5,
497 fixed_1: u8 = 0b11010110,
498 s: u1,
499 fixed_2: u1 = 0b0,
500 sf: u1,
501 },
502
503 pub const Condition = enum(u4) {
504 /// Integer: Equal
505 /// Floating point: Equal
506 eq,
507 /// Integer: Not equal
508 /// Floating point: Not equal or unordered
509 ne,
510 /// Integer: Carry set
511 /// Floating point: Greater than, equal, or unordered
512 cs,
513 /// Integer: Carry clear
514 /// Floating point: Less than
515 cc,
516 /// Integer: Minus, negative
517 /// Floating point: Less than
518 mi,
519 /// Integer: Plus, positive or zero
520 /// Floating point: Greater than, equal, or unordered
521 pl,
522 /// Integer: Overflow
523 /// Floating point: Unordered
524 vs,
525 /// Integer: No overflow
526 /// Floating point: Ordered
527 vc,
528 /// Integer: Unsigned higher
529 /// Floating point: Greater than, or unordered
530 hi,
531 /// Integer: Unsigned lower or same
532 /// Floating point: Less than or equal
533 ls,
534 /// Integer: Signed greater than or equal
535 /// Floating point: Greater than or equal
536 ge,
537 /// Integer: Signed less than
538 /// Floating point: Less than, or unordered
539 lt,
540 /// Integer: Signed greater than
541 /// Floating point: Greater than
542 gt,
543 /// Integer: Signed less than or equal
544 /// Floating point: Less than, equal, or unordered
545 le,
546 /// Integer: Always
547 /// Floating point: Always
548 al,
549 /// Integer: Always
550 /// Floating point: Always
551 nv,
552
553 /// Converts a std.math.CompareOperator into a condition flag,
554 /// i.e. returns the condition that is true iff the result of the
555 /// comparison is true. Assumes signed comparison
556 pub fn fromCompareOperatorSigned(op: std.math.CompareOperator) Condition {
557 return switch (op) {
558 .gte => .ge,
559 .gt => .gt,
560 .neq => .ne,
561 .lt => .lt,
562 .lte => .le,
563 .eq => .eq,
564 };
565 }
566
567 /// Converts a std.math.CompareOperator into a condition flag,
568 /// i.e. returns the condition that is true iff the result of the
569 /// comparison is true. Assumes unsigned comparison
570 pub fn fromCompareOperatorUnsigned(op: std.math.CompareOperator) Condition {
571 return switch (op) {
572 .gte => .cs,
573 .gt => .hi,
574 .neq => .ne,
575 .lt => .cc,
576 .lte => .ls,
577 .eq => .eq,
578 };
579 }
580
581 /// Returns the condition which is true iff the given condition is
582 /// false (if such a condition exists)
583 pub fn negate(cond: Condition) Condition {
584 return switch (cond) {
585 .eq => .ne,
586 .ne => .eq,
587 .cs => .cc,
588 .cc => .cs,
589 .mi => .pl,
590 .pl => .mi,
591 .vs => .vc,
592 .vc => .vs,
593 .hi => .ls,
594 .ls => .hi,
595 .ge => .lt,
596 .lt => .ge,
597 .gt => .le,
598 .le => .gt,
599 .al => unreachable,
600 .nv => unreachable,
601 };
602 }
603 };
604
605 pub fn toU32(self: Instruction) u32 {
606 return switch (self) {
607 .move_wide_immediate => |v| @as(u32, @bitCast(v)),
608 .pc_relative_address => |v| @as(u32, @bitCast(v)),
609 .load_store_register => |v| @as(u32, @bitCast(v)),
610 .load_store_register_pair => |v| @as(u32, @bitCast(v)),
611 .load_literal => |v| @as(u32, @bitCast(v)),
612 .exception_generation => |v| @as(u32, @bitCast(v)),
613 .unconditional_branch_register => |v| @as(u32, @bitCast(v)),
614 .unconditional_branch_immediate => |v| @as(u32, @bitCast(v)),
615 .no_operation => |v| @as(u32, @bitCast(v)),
616 .logical_shifted_register => |v| @as(u32, @bitCast(v)),
617 .add_subtract_immediate => |v| @as(u32, @bitCast(v)),
618 .logical_immediate => |v| @as(u32, @bitCast(v)),
619 .bitfield => |v| @as(u32, @bitCast(v)),
620 .add_subtract_shifted_register => |v| @as(u32, @bitCast(v)),
621 .add_subtract_extended_register => |v| @as(u32, @bitCast(v)),
622 // TODO once packed structs work, this can be refactored
623 .conditional_branch => |v| @as(u32, v.cond) | (@as(u32, v.o0) << 4) | (@as(u32, v.imm19) << 5) | (@as(u32, v.o1) << 24) | (@as(u32, v.fixed) << 25),
624 .compare_and_branch => |v| @as(u32, v.rt) | (@as(u32, v.imm19) << 5) | (@as(u32, v.op) << 24) | (@as(u32, v.fixed) << 25) | (@as(u32, v.sf) << 31),
625 .conditional_select => |v| @as(u32, v.rd) | @as(u32, v.rn) << 5 | @as(u32, v.op2) << 10 | @as(u32, v.cond) << 12 | @as(u32, v.rm) << 16 | @as(u32, v.fixed) << 21 | @as(u32, v.s) << 29 | @as(u32, v.op) << 30 | @as(u32, v.sf) << 31,
626 .data_processing_3_source => |v| @as(u32, @bitCast(v)),
627 .data_processing_2_source => |v| @as(u32, @bitCast(v)),
628 };
629 }
630
631 fn moveWideImmediate(
632 opc: u2,
633 rd: Register,
634 imm16: u16,
635 shift: u6,
636 ) Instruction {
637 assert(shift % 16 == 0);
638 assert(!(rd.size() == 32 and shift > 16));
639 assert(!(rd.size() == 64 and shift > 48));
640
641 return Instruction{
642 .move_wide_immediate = .{
643 .rd = rd.enc(),
644 .imm16 = imm16,
645 .hw = @as(u2, @intCast(shift / 16)),
646 .opc = opc,
647 .sf = switch (rd.size()) {
648 32 => 0,
649 64 => 1,
650 else => unreachable, // unexpected register size
651 },
652 },
653 };
654 }
655
656 fn pcRelativeAddress(rd: Register, imm21: i21, op: u1) Instruction {
657 assert(rd.size() == 64);
658 const imm21_u = @as(u21, @bitCast(imm21));
659 return Instruction{
660 .pc_relative_address = .{
661 .rd = rd.enc(),
662 .immlo = @as(u2, @truncate(imm21_u)),
663 .immhi = @as(u19, @truncate(imm21_u >> 2)),
664 .op = op,
665 },
666 };
667 }
668
669 pub const LoadStoreOffsetImmediate = union(enum) {
670 post_index: i9,
671 pre_index: i9,
672 unsigned: u12,
673 };
674
675 pub const LoadStoreOffsetRegister = struct {
676 rm: u5,
677 shift: union(enum) {
678 uxtw: u2,
679 lsl: u2,
680 sxtw: u2,
681 sxtx: u2,
682 },
683 };
684
685 /// Represents the offset operand of a load or store instruction.
686 /// Data can be loaded from memory with either an immediate offset
687 /// or an offset that is stored in some register.
688 pub const LoadStoreOffset = union(enum) {
689 immediate: LoadStoreOffsetImmediate,
690 register: LoadStoreOffsetRegister,
691
692 pub const none = LoadStoreOffset{
693 .immediate = .{ .unsigned = 0 },
694 };
695
696 pub fn toU12(self: LoadStoreOffset) u12 {
697 return switch (self) {
698 .immediate => |imm_type| switch (imm_type) {
699 .post_index => |v| (@as(u12, @intCast(@as(u9, @bitCast(v)))) << 2) + 1,
700 .pre_index => |v| (@as(u12, @intCast(@as(u9, @bitCast(v)))) << 2) + 3,
701 .unsigned => |v| v,
702 },
703 .register => |r| switch (r.shift) {
704 .uxtw => |v| (@as(u12, @intCast(r.rm)) << 6) + (@as(u12, @intCast(v)) << 2) + 16 + 2050,
705 .lsl => |v| (@as(u12, @intCast(r.rm)) << 6) + (@as(u12, @intCast(v)) << 2) + 24 + 2050,
706 .sxtw => |v| (@as(u12, @intCast(r.rm)) << 6) + (@as(u12, @intCast(v)) << 2) + 48 + 2050,
707 .sxtx => |v| (@as(u12, @intCast(r.rm)) << 6) + (@as(u12, @intCast(v)) << 2) + 56 + 2050,
708 },
709 };
710 }
711
712 pub fn imm(offset: u12) LoadStoreOffset {
713 return .{
714 .immediate = .{ .unsigned = offset },
715 };
716 }
717
718 pub fn imm_post_index(offset: i9) LoadStoreOffset {
719 return .{
720 .immediate = .{ .post_index = offset },
721 };
722 }
723
724 pub fn imm_pre_index(offset: i9) LoadStoreOffset {
725 return .{
726 .immediate = .{ .pre_index = offset },
727 };
728 }
729
730 pub fn reg(rm: Register) LoadStoreOffset {
731 return .{
732 .register = .{
733 .rm = rm.enc(),
734 .shift = .{
735 .lsl = 0,
736 },
737 },
738 };
739 }
740
741 pub fn reg_uxtw(rm: Register, shift: u2) LoadStoreOffset {
742 assert(rm.size() == 32 and (shift == 0 or shift == 2));
743 return .{
744 .register = .{
745 .rm = rm.enc(),
746 .shift = .{
747 .uxtw = shift,
748 },
749 },
750 };
751 }
752
753 pub fn reg_lsl(rm: Register, shift: u2) LoadStoreOffset {
754 assert(rm.size() == 64 and (shift == 0 or shift == 3));
755 return .{
756 .register = .{
757 .rm = rm.enc(),
758 .shift = .{
759 .lsl = shift,
760 },
761 },
762 };
763 }
764
765 pub fn reg_sxtw(rm: Register, shift: u2) LoadStoreOffset {
766 assert(rm.size() == 32 and (shift == 0 or shift == 2));
767 return .{
768 .register = .{
769 .rm = rm.enc(),
770 .shift = .{
771 .sxtw = shift,
772 },
773 },
774 };
775 }
776
777 pub fn reg_sxtx(rm: Register, shift: u2) LoadStoreOffset {
778 assert(rm.size() == 64 and (shift == 0 or shift == 3));
779 return .{
780 .register = .{
781 .rm = rm.enc(),
782 .shift = .{
783 .sxtx = shift,
784 },
785 },
786 };
787 }
788 };
789
790 /// Which kind of load/store to perform
791 const LoadStoreVariant = enum {
792 /// 32 bits or 64 bits
793 str,
794 /// 8 bits, zero-extended
795 strb,
796 /// 16 bits, zero-extended
797 strh,
798 /// 32 bits or 64 bits
799 ldr,
800 /// 8 bits, zero-extended
801 ldrb,
802 /// 16 bits, zero-extended
803 ldrh,
804 /// 8 bits, sign extended
805 ldrsb,
806 /// 16 bits, sign extended
807 ldrsh,
808 /// 32 bits, sign extended
809 ldrsw,
810 };
811
812 fn loadStoreRegister(
813 rt: Register,
814 rn: Register,
815 offset: LoadStoreOffset,
816 variant: LoadStoreVariant,
817 ) Instruction {
818 assert(rn.size() == 64);
819 assert(rn.id() != Register.xzr.id());
820
821 const off = offset.toU12();
822
823 const op1: u2 = blk: {
824 switch (offset) {
825 .immediate => |imm| switch (imm) {
826 .unsigned => break :blk 0b01,
827 else => {},
828 },
829 else => {},
830 }
831 break :blk 0b00;
832 };
833
834 const opc: u2 = blk: {
835 switch (variant) {
836 .ldr, .ldrh, .ldrb => break :blk 0b01,
837 .str, .strh, .strb => break :blk 0b00,
838 .ldrsb,
839 .ldrsh,
840 => switch (rt.size()) {
841 32 => break :blk 0b11,
842 64 => break :blk 0b10,
843 else => unreachable, // unexpected register size
844 },
845 .ldrsw => break :blk 0b10,
846 }
847 };
848
849 const size: u2 = blk: {
850 switch (variant) {
851 .ldr, .str => switch (rt.size()) {
852 32 => break :blk 0b10,
853 64 => break :blk 0b11,
854 else => unreachable, // unexpected register size
855 },
856 .ldrsw => break :blk 0b10,
857 .ldrh, .ldrsh, .strh => break :blk 0b01,
858 .ldrb, .ldrsb, .strb => break :blk 0b00,
859 }
860 };
861
862 return Instruction{
863 .load_store_register = .{
864 .rt = rt.enc(),
865 .rn = rn.enc(),
866 .offset = off,
867 .opc = opc,
868 .op1 = op1,
869 .v = 0,
870 .size = size,
871 },
872 };
873 }
874
875 fn loadStoreRegisterPair(
876 rt1: Register,
877 rt2: Register,
878 rn: Register,
879 offset: i9,
880 encoding: u2,
881 load: bool,
882 ) Instruction {
883 assert(rn.size() == 64);
884 assert(rn.id() != Register.xzr.id());
885
886 switch (rt1.size()) {
887 32 => {
888 assert(-256 <= offset and offset <= 252);
889 const imm7 = @as(u7, @truncate(@as(u9, @bitCast(offset >> 2))));
890 return Instruction{
891 .load_store_register_pair = .{
892 .rt1 = rt1.enc(),
893 .rn = rn.enc(),
894 .rt2 = rt2.enc(),
895 .imm7 = imm7,
896 .load = @intFromBool(load),
897 .encoding = encoding,
898 .opc = 0b00,
899 },
900 };
901 },
902 64 => {
903 assert(-512 <= offset and offset <= 504);
904 const imm7 = @as(u7, @truncate(@as(u9, @bitCast(offset >> 3))));
905 return Instruction{
906 .load_store_register_pair = .{
907 .rt1 = rt1.enc(),
908 .rn = rn.enc(),
909 .rt2 = rt2.enc(),
910 .imm7 = imm7,
911 .load = @intFromBool(load),
912 .encoding = encoding,
913 .opc = 0b10,
914 },
915 };
916 },
917 else => unreachable, // unexpected register size
918 }
919 }
920
921 fn loadLiteral(rt: Register, imm19: u19) Instruction {
922 return Instruction{
923 .load_literal = .{
924 .rt = rt.enc(),
925 .imm19 = imm19,
926 .opc = switch (rt.size()) {
927 32 => 0b00,
928 64 => 0b01,
929 else => unreachable, // unexpected register size
930 },
931 },
932 };
933 }
934
935 fn exceptionGeneration(
936 opc: u3,
937 op2: u3,
938 ll: u2,
939 imm16: u16,
940 ) Instruction {
941 return Instruction{
942 .exception_generation = .{
943 .ll = ll,
944 .op2 = op2,
945 .imm16 = imm16,
946 .opc = opc,
947 },
948 };
949 }
950
951 fn unconditionalBranchRegister(
952 opc: u4,
953 op2: u5,
954 op3: u6,
955 rn: Register,
956 op4: u5,
957 ) Instruction {
958 assert(rn.size() == 64);
959
960 return Instruction{
961 .unconditional_branch_register = .{
962 .op4 = op4,
963 .rn = rn.enc(),
964 .op3 = op3,
965 .op2 = op2,
966 .opc = opc,
967 },
968 };
969 }
970
971 fn unconditionalBranchImmediate(
972 op: u1,
973 offset: i28,
974 ) Instruction {
975 return Instruction{
976 .unconditional_branch_immediate = .{
977 .imm26 = @as(u26, @bitCast(@as(i26, @intCast(offset >> 2)))),
978 .op = op,
979 },
980 };
981 }
982
983 pub const LogicalShiftedRegisterShift = enum(u2) { lsl, lsr, asr, ror };
984
985 fn logicalShiftedRegister(
986 opc: u2,
987 n: u1,
988 rd: Register,
989 rn: Register,
990 rm: Register,
991 shift: LogicalShiftedRegisterShift,
992 amount: u6,
993 ) Instruction {
994 assert(rd.size() == rn.size());
995 assert(rd.size() == rm.size());
996 if (rd.size() == 32) assert(amount < 32);
997
998 return Instruction{
999 .logical_shifted_register = .{
1000 .rd = rd.enc(),
1001 .rn = rn.enc(),
1002 .imm6 = amount,
1003 .rm = rm.enc(),
1004 .n = n,
1005 .shift = @intFromEnum(shift),
1006 .opc = opc,
1007 .sf = switch (rd.size()) {
1008 32 => 0b0,
1009 64 => 0b1,
1010 else => unreachable,
1011 },
1012 },
1013 };
1014 }
1015
1016 fn addSubtractImmediate(
1017 op: u1,
1018 s: u1,
1019 rd: Register,
1020 rn: Register,
1021 imm12: u12,
1022 shift: bool,
1023 ) Instruction {
1024 assert(rd.size() == rn.size());
1025 assert(rn.id() != Register.xzr.id());
1026
1027 return Instruction{
1028 .add_subtract_immediate = .{
1029 .rd = rd.enc(),
1030 .rn = rn.enc(),
1031 .imm12 = imm12,
1032 .sh = @intFromBool(shift),
1033 .s = s,
1034 .op = op,
1035 .sf = switch (rd.size()) {
1036 32 => 0b0,
1037 64 => 0b1,
1038 else => unreachable, // unexpected register size
1039 },
1040 },
1041 };
1042 }
1043
1044 fn logicalImmediate(
1045 opc: u2,
1046 rd: Register,
1047 rn: Register,
1048 imms: u6,
1049 immr: u6,
1050 n: u1,
1051 ) Instruction {
1052 assert(rd.size() == rn.size());
1053 assert(!(rd.size() == 32 and n != 0));
1054
1055 return Instruction{
1056 .logical_immediate = .{
1057 .rd = rd.enc(),
1058 .rn = rn.enc(),
1059 .imms = imms,
1060 .immr = immr,
1061 .n = n,
1062 .opc = opc,
1063 .sf = switch (rd.size()) {
1064 32 => 0b0,
1065 64 => 0b1,
1066 else => unreachable, // unexpected register size
1067 },
1068 },
1069 };
1070 }
1071
1072 fn initBitfield(
1073 opc: u2,
1074 n: u1,
1075 rd: Register,
1076 rn: Register,
1077 immr: u6,
1078 imms: u6,
1079 ) Instruction {
1080 assert(rd.size() == rn.size());
1081 assert(!(rd.size() == 64 and n != 1));
1082 assert(!(rd.size() == 32 and (n != 0 or immr >> 5 != 0 or immr >> 5 != 0)));
1083
1084 return Instruction{
1085 .bitfield = .{
1086 .rd = rd.enc(),
1087 .rn = rn.enc(),
1088 .imms = imms,
1089 .immr = immr,
1090 .n = n,
1091 .opc = opc,
1092 .sf = switch (rd.size()) {
1093 32 => 0b0,
1094 64 => 0b1,
1095 else => unreachable, // unexpected register size
1096 },
1097 },
1098 };
1099 }
1100
1101 pub const AddSubtractShiftedRegisterShift = enum(u2) { lsl, lsr, asr, _ };
1102
1103 fn addSubtractShiftedRegister(
1104 op: u1,
1105 s: u1,
1106 shift: AddSubtractShiftedRegisterShift,
1107 rd: Register,
1108 rn: Register,
1109 rm: Register,
1110 imm6: u6,
1111 ) Instruction {
1112 assert(rd.size() == rn.size());
1113 assert(rd.size() == rm.size());
1114
1115 return Instruction{
1116 .add_subtract_shifted_register = .{
1117 .rd = rd.enc(),
1118 .rn = rn.enc(),
1119 .imm6 = imm6,
1120 .rm = rm.enc(),
1121 .shift = @intFromEnum(shift),
1122 .s = s,
1123 .op = op,
1124 .sf = switch (rd.size()) {
1125 32 => 0b0,
1126 64 => 0b1,
1127 else => unreachable, // unexpected register size
1128 },
1129 },
1130 };
1131 }
1132
1133 pub const AddSubtractExtendedRegisterOption = enum(u3) {
1134 uxtb,
1135 uxth,
1136 uxtw,
1137 uxtx, // serves also as lsl
1138 sxtb,
1139 sxth,
1140 sxtw,
1141 sxtx,
1142 };
1143
1144 fn addSubtractExtendedRegister(
1145 op: u1,
1146 s: u1,
1147 rd: Register,
1148 rn: Register,
1149 rm: Register,
1150 extend: AddSubtractExtendedRegisterOption,
1151 imm3: u3,
1152 ) Instruction {
1153 return Instruction{
1154 .add_subtract_extended_register = .{
1155 .rd = rd.enc(),
1156 .rn = rn.enc(),
1157 .imm3 = imm3,
1158 .option = @intFromEnum(extend),
1159 .rm = rm.enc(),
1160 .s = s,
1161 .op = op,
1162 .sf = switch (rd.size()) {
1163 32 => 0b0,
1164 64 => 0b1,
1165 else => unreachable, // unexpected register size
1166 },
1167 },
1168 };
1169 }
1170
1171 fn conditionalBranch(
1172 o0: u1,
1173 o1: u1,
1174 cond: Condition,
1175 offset: i21,
1176 ) Instruction {
1177 assert(offset & 0b11 == 0b00);
1178
1179 return Instruction{
1180 .conditional_branch = .{
1181 .cond = @intFromEnum(cond),
1182 .o0 = o0,
1183 .imm19 = @as(u19, @bitCast(@as(i19, @intCast(offset >> 2)))),
1184 .o1 = o1,
1185 },
1186 };
1187 }
1188
1189 fn compareAndBranch(
1190 op: u1,
1191 rt: Register,
1192 offset: i21,
1193 ) Instruction {
1194 assert(offset & 0b11 == 0b00);
1195
1196 return Instruction{
1197 .compare_and_branch = .{
1198 .rt = rt.enc(),
1199 .imm19 = @as(u19, @bitCast(@as(i19, @intCast(offset >> 2)))),
1200 .op = op,
1201 .sf = switch (rt.size()) {
1202 32 => 0b0,
1203 64 => 0b1,
1204 else => unreachable, // unexpected register size
1205 },
1206 },
1207 };
1208 }
1209
1210 fn conditionalSelect(
1211 op2: u2,
1212 op: u1,
1213 s: u1,
1214 rd: Register,
1215 rn: Register,
1216 rm: Register,
1217 cond: Condition,
1218 ) Instruction {
1219 assert(rd.size() == rn.size());
1220 assert(rd.size() == rm.size());
1221
1222 return Instruction{
1223 .conditional_select = .{
1224 .rd = rd.enc(),
1225 .rn = rn.enc(),
1226 .op2 = op2,
1227 .cond = @intFromEnum(cond),
1228 .rm = rm.enc(),
1229 .s = s,
1230 .op = op,
1231 .sf = switch (rd.size()) {
1232 32 => 0b0,
1233 64 => 0b1,
1234 else => unreachable, // unexpected register size
1235 },
1236 },
1237 };
1238 }
1239
1240 fn dataProcessing3Source(
1241 op54: u2,
1242 op31: u3,
1243 o0: u1,
1244 rd: Register,
1245 rn: Register,
1246 rm: Register,
1247 ra: Register,
1248 ) Instruction {
1249 return Instruction{
1250 .data_processing_3_source = .{
1251 .rd = rd.enc(),
1252 .rn = rn.enc(),
1253 .ra = ra.enc(),
1254 .o0 = o0,
1255 .rm = rm.enc(),
1256 .op31 = op31,
1257 .op54 = op54,
1258 .sf = switch (rd.size()) {
1259 32 => 0b0,
1260 64 => 0b1,
1261 else => unreachable, // unexpected register size
1262 },
1263 },
1264 };
1265 }
1266
1267 fn dataProcessing2Source(
1268 s: u1,
1269 opcode: u6,
1270 rd: Register,
1271 rn: Register,
1272 rm: Register,
1273 ) Instruction {
1274 assert(rd.size() == rn.size());
1275 assert(rd.size() == rm.size());
1276
1277 return Instruction{
1278 .data_processing_2_source = .{
1279 .rd = rd.enc(),
1280 .rn = rn.enc(),
1281 .opcode = opcode,
1282 .rm = rm.enc(),
1283 .s = s,
1284 .sf = switch (rd.size()) {
1285 32 => 0b0,
1286 64 => 0b1,
1287 else => unreachable, // unexpected register size
1288 },
1289 },
1290 };
1291 }
1292
1293 // Helper functions for assembly syntax functions
1294
1295 // Move wide (immediate)
1296
1297 pub fn movn(rd: Register, imm16: u16, shift: u6) Instruction {
1298 return moveWideImmediate(0b00, rd, imm16, shift);
1299 }
1300
1301 pub fn movz(rd: Register, imm16: u16, shift: u6) Instruction {
1302 return moveWideImmediate(0b10, rd, imm16, shift);
1303 }
1304
1305 pub fn movk(rd: Register, imm16: u16, shift: u6) Instruction {
1306 return moveWideImmediate(0b11, rd, imm16, shift);
1307 }
1308
1309 // PC relative address
1310
1311 pub fn adr(rd: Register, imm21: i21) Instruction {
1312 return pcRelativeAddress(rd, imm21, 0b0);
1313 }
1314
1315 pub fn adrp(rd: Register, imm21: i21) Instruction {
1316 return pcRelativeAddress(rd, imm21, 0b1);
1317 }
1318
1319 // Load or store register
1320
1321 pub fn ldrLiteral(rt: Register, literal: u19) Instruction {
1322 return loadLiteral(rt, literal);
1323 }
1324
1325 pub fn ldr(rt: Register, rn: Register, offset: LoadStoreOffset) Instruction {
1326 return loadStoreRegister(rt, rn, offset, .ldr);
1327 }
1328
1329 pub fn ldrh(rt: Register, rn: Register, offset: LoadStoreOffset) Instruction {
1330 return loadStoreRegister(rt, rn, offset, .ldrh);
1331 }
1332
1333 pub fn ldrb(rt: Register, rn: Register, offset: LoadStoreOffset) Instruction {
1334 return loadStoreRegister(rt, rn, offset, .ldrb);
1335 }
1336
1337 pub fn ldrsb(rt: Register, rn: Register, offset: LoadStoreOffset) Instruction {
1338 return loadStoreRegister(rt, rn, offset, .ldrsb);
1339 }
1340
1341 pub fn ldrsh(rt: Register, rn: Register, offset: LoadStoreOffset) Instruction {
1342 return loadStoreRegister(rt, rn, offset, .ldrsh);
1343 }
1344
1345 pub fn ldrsw(rt: Register, rn: Register, offset: LoadStoreOffset) Instruction {
1346 return loadStoreRegister(rt, rn, offset, .ldrsw);
1347 }
1348
1349 pub fn str(rt: Register, rn: Register, offset: LoadStoreOffset) Instruction {
1350 return loadStoreRegister(rt, rn, offset, .str);
1351 }
1352
1353 pub fn strh(rt: Register, rn: Register, offset: LoadStoreOffset) Instruction {
1354 return loadStoreRegister(rt, rn, offset, .strh);
1355 }
1356
1357 pub fn strb(rt: Register, rn: Register, offset: LoadStoreOffset) Instruction {
1358 return loadStoreRegister(rt, rn, offset, .strb);
1359 }
1360
1361 // Load or store pair of registers
1362
1363 pub const LoadStorePairOffset = struct {
1364 encoding: enum(u2) {
1365 post_index = 0b01,
1366 signed = 0b10,
1367 pre_index = 0b11,
1368 },
1369 offset: i9,
1370
1371 pub fn none() LoadStorePairOffset {
1372 return .{ .encoding = .signed, .offset = 0 };
1373 }
1374
1375 pub fn post_index(imm: i9) LoadStorePairOffset {
1376 return .{ .encoding = .post_index, .offset = imm };
1377 }
1378
1379 pub fn pre_index(imm: i9) LoadStorePairOffset {
1380 return .{ .encoding = .pre_index, .offset = imm };
1381 }
1382
1383 pub fn signed(imm: i9) LoadStorePairOffset {
1384 return .{ .encoding = .signed, .offset = imm };
1385 }
1386 };
1387
1388 pub fn ldp(rt1: Register, rt2: Register, rn: Register, offset: LoadStorePairOffset) Instruction {
1389 return loadStoreRegisterPair(rt1, rt2, rn, offset.offset, @intFromEnum(offset.encoding), true);
1390 }
1391
1392 pub fn ldnp(rt1: Register, rt2: Register, rn: Register, offset: i9) Instruction {
1393 return loadStoreRegisterPair(rt1, rt2, rn, offset, 0, true);
1394 }
1395
1396 pub fn stp(rt1: Register, rt2: Register, rn: Register, offset: LoadStorePairOffset) Instruction {
1397 return loadStoreRegisterPair(rt1, rt2, rn, offset.offset, @intFromEnum(offset.encoding), false);
1398 }
1399
1400 pub fn stnp(rt1: Register, rt2: Register, rn: Register, offset: i9) Instruction {
1401 return loadStoreRegisterPair(rt1, rt2, rn, offset, 0, false);
1402 }
1403
1404 // Exception generation
1405
1406 pub fn svc(imm16: u16) Instruction {
1407 return exceptionGeneration(0b000, 0b000, 0b01, imm16);
1408 }
1409
1410 pub fn hvc(imm16: u16) Instruction {
1411 return exceptionGeneration(0b000, 0b000, 0b10, imm16);
1412 }
1413
1414 pub fn smc(imm16: u16) Instruction {
1415 return exceptionGeneration(0b000, 0b000, 0b11, imm16);
1416 }
1417
1418 pub fn brk(imm16: u16) Instruction {
1419 return exceptionGeneration(0b001, 0b000, 0b00, imm16);
1420 }
1421
1422 pub fn hlt(imm16: u16) Instruction {
1423 return exceptionGeneration(0b010, 0b000, 0b00, imm16);
1424 }
1425
1426 // Unconditional branch (register)
1427
1428 pub fn br(rn: Register) Instruction {
1429 return unconditionalBranchRegister(0b0000, 0b11111, 0b000000, rn, 0b00000);
1430 }
1431
1432 pub fn blr(rn: Register) Instruction {
1433 return unconditionalBranchRegister(0b0001, 0b11111, 0b000000, rn, 0b00000);
1434 }
1435
1436 pub fn ret(rn: ?Register) Instruction {
1437 return unconditionalBranchRegister(0b0010, 0b11111, 0b000000, rn orelse .x30, 0b00000);
1438 }
1439
1440 // Unconditional branch (immediate)
1441
1442 pub fn b(offset: i28) Instruction {
1443 return unconditionalBranchImmediate(0, offset);
1444 }
1445
1446 pub fn bl(offset: i28) Instruction {
1447 return unconditionalBranchImmediate(1, offset);
1448 }
1449
1450 // Nop
1451
1452 pub fn nop() Instruction {
1453 return Instruction{ .no_operation = .{} };
1454 }
1455
1456 // Logical (shifted register)
1457
1458 pub fn andShiftedRegister(
1459 rd: Register,
1460 rn: Register,
1461 rm: Register,
1462 shift: LogicalShiftedRegisterShift,
1463 amount: u6,
1464 ) Instruction {
1465 return logicalShiftedRegister(0b00, 0b0, rd, rn, rm, shift, amount);
1466 }
1467
1468 pub fn bicShiftedRegister(
1469 rd: Register,
1470 rn: Register,
1471 rm: Register,
1472 shift: LogicalShiftedRegisterShift,
1473 amount: u6,
1474 ) Instruction {
1475 return logicalShiftedRegister(0b00, 0b1, rd, rn, rm, shift, amount);
1476 }
1477
1478 pub fn orrShiftedRegister(
1479 rd: Register,
1480 rn: Register,
1481 rm: Register,
1482 shift: LogicalShiftedRegisterShift,
1483 amount: u6,
1484 ) Instruction {
1485 return logicalShiftedRegister(0b01, 0b0, rd, rn, rm, shift, amount);
1486 }
1487
1488 pub fn ornShiftedRegister(
1489 rd: Register,
1490 rn: Register,
1491 rm: Register,
1492 shift: LogicalShiftedRegisterShift,
1493 amount: u6,
1494 ) Instruction {
1495 return logicalShiftedRegister(0b01, 0b1, rd, rn, rm, shift, amount);
1496 }
1497
1498 pub fn eorShiftedRegister(
1499 rd: Register,
1500 rn: Register,
1501 rm: Register,
1502 shift: LogicalShiftedRegisterShift,
1503 amount: u6,
1504 ) Instruction {
1505 return logicalShiftedRegister(0b10, 0b0, rd, rn, rm, shift, amount);
1506 }
1507
1508 pub fn eonShiftedRegister(
1509 rd: Register,
1510 rn: Register,
1511 rm: Register,
1512 shift: LogicalShiftedRegisterShift,
1513 amount: u6,
1514 ) Instruction {
1515 return logicalShiftedRegister(0b10, 0b1, rd, rn, rm, shift, amount);
1516 }
1517
1518 pub fn andsShiftedRegister(
1519 rd: Register,
1520 rn: Register,
1521 rm: Register,
1522 shift: LogicalShiftedRegisterShift,
1523 amount: u6,
1524 ) Instruction {
1525 return logicalShiftedRegister(0b11, 0b0, rd, rn, rm, shift, amount);
1526 }
1527
1528 pub fn bicsShiftedRegister(
1529 rd: Register,
1530 rn: Register,
1531 rm: Register,
1532 shift: LogicalShiftedRegisterShift,
1533 amount: u6,
1534 ) Instruction {
1535 return logicalShiftedRegister(0b11, 0b1, rd, rn, rm, shift, amount);
1536 }
1537
1538 // Add/subtract (immediate)
1539
1540 pub fn add(rd: Register, rn: Register, imm: u12, shift: bool) Instruction {
1541 return addSubtractImmediate(0b0, 0b0, rd, rn, imm, shift);
1542 }
1543
1544 pub fn adds(rd: Register, rn: Register, imm: u12, shift: bool) Instruction {
1545 return addSubtractImmediate(0b0, 0b1, rd, rn, imm, shift);
1546 }
1547
1548 pub fn sub(rd: Register, rn: Register, imm: u12, shift: bool) Instruction {
1549 return addSubtractImmediate(0b1, 0b0, rd, rn, imm, shift);
1550 }
1551
1552 pub fn subs(rd: Register, rn: Register, imm: u12, shift: bool) Instruction {
1553 return addSubtractImmediate(0b1, 0b1, rd, rn, imm, shift);
1554 }
1555
1556 // Logical (immediate)
1557
1558 pub fn andImmediate(rd: Register, rn: Register, imms: u6, immr: u6, n: u1) Instruction {
1559 return logicalImmediate(0b00, rd, rn, imms, immr, n);
1560 }
1561
1562 pub fn orrImmediate(rd: Register, rn: Register, imms: u6, immr: u6, n: u1) Instruction {
1563 return logicalImmediate(0b01, rd, rn, imms, immr, n);
1564 }
1565
1566 pub fn eorImmediate(rd: Register, rn: Register, imms: u6, immr: u6, n: u1) Instruction {
1567 return logicalImmediate(0b10, rd, rn, imms, immr, n);
1568 }
1569
1570 pub fn andsImmediate(rd: Register, rn: Register, imms: u6, immr: u6, n: u1) Instruction {
1571 return logicalImmediate(0b11, rd, rn, imms, immr, n);
1572 }
1573
1574 // Bitfield
1575
1576 pub fn sbfm(rd: Register, rn: Register, immr: u6, imms: u6) Instruction {
1577 const n: u1 = switch (rd.size()) {
1578 32 => 0b0,
1579 64 => 0b1,
1580 else => unreachable, // unexpected register size
1581 };
1582 return initBitfield(0b00, n, rd, rn, immr, imms);
1583 }
1584
1585 pub fn bfm(rd: Register, rn: Register, immr: u6, imms: u6) Instruction {
1586 const n: u1 = switch (rd.size()) {
1587 32 => 0b0,
1588 64 => 0b1,
1589 else => unreachable, // unexpected register size
1590 };
1591 return initBitfield(0b01, n, rd, rn, immr, imms);
1592 }
1593
1594 pub fn ubfm(rd: Register, rn: Register, immr: u6, imms: u6) Instruction {
1595 const n: u1 = switch (rd.size()) {
1596 32 => 0b0,
1597 64 => 0b1,
1598 else => unreachable, // unexpected register size
1599 };
1600 return initBitfield(0b10, n, rd, rn, immr, imms);
1601 }
1602
1603 pub fn asrImmediate(rd: Register, rn: Register, shift: u6) Instruction {
1604 const imms = @as(u6, @intCast(rd.size() - 1));
1605 return sbfm(rd, rn, shift, imms);
1606 }
1607
1608 pub fn sbfx(rd: Register, rn: Register, lsb: u6, width: u7) Instruction {
1609 return sbfm(rd, rn, lsb, @as(u6, @intCast(lsb + width - 1)));
1610 }
1611
1612 pub fn sxtb(rd: Register, rn: Register) Instruction {
1613 return sbfm(rd, rn, 0, 7);
1614 }
1615
1616 pub fn sxth(rd: Register, rn: Register) Instruction {
1617 return sbfm(rd, rn, 0, 15);
1618 }
1619
1620 pub fn sxtw(rd: Register, rn: Register) Instruction {
1621 assert(rd.size() == 64);
1622 return sbfm(rd, rn, 0, 31);
1623 }
1624
1625 pub fn lslImmediate(rd: Register, rn: Register, shift: u6) Instruction {
1626 const size = @as(u6, @intCast(rd.size() - 1));
1627 return ubfm(rd, rn, size - shift + 1, size - shift);
1628 }
1629
1630 pub fn lsrImmediate(rd: Register, rn: Register, shift: u6) Instruction {
1631 const imms = @as(u6, @intCast(rd.size() - 1));
1632 return ubfm(rd, rn, shift, imms);
1633 }
1634
1635 pub fn ubfx(rd: Register, rn: Register, lsb: u6, width: u7) Instruction {
1636 return ubfm(rd, rn, lsb, @as(u6, @intCast(lsb + width - 1)));
1637 }
1638
1639 pub fn uxtb(rd: Register, rn: Register) Instruction {
1640 return ubfm(rd, rn, 0, 7);
1641 }
1642
1643 pub fn uxth(rd: Register, rn: Register) Instruction {
1644 return ubfm(rd, rn, 0, 15);
1645 }
1646
1647 // Add/subtract (shifted register)
1648
1649 pub fn addShiftedRegister(
1650 rd: Register,
1651 rn: Register,
1652 rm: Register,
1653 shift: AddSubtractShiftedRegisterShift,
1654 imm6: u6,
1655 ) Instruction {
1656 return addSubtractShiftedRegister(0b0, 0b0, shift, rd, rn, rm, imm6);
1657 }
1658
1659 pub fn addsShiftedRegister(
1660 rd: Register,
1661 rn: Register,
1662 rm: Register,
1663 shift: AddSubtractShiftedRegisterShift,
1664 imm6: u6,
1665 ) Instruction {
1666 return addSubtractShiftedRegister(0b0, 0b1, shift, rd, rn, rm, imm6);
1667 }
1668
1669 pub fn subShiftedRegister(
1670 rd: Register,
1671 rn: Register,
1672 rm: Register,
1673 shift: AddSubtractShiftedRegisterShift,
1674 imm6: u6,
1675 ) Instruction {
1676 return addSubtractShiftedRegister(0b1, 0b0, shift, rd, rn, rm, imm6);
1677 }
1678
1679 pub fn subsShiftedRegister(
1680 rd: Register,
1681 rn: Register,
1682 rm: Register,
1683 shift: AddSubtractShiftedRegisterShift,
1684 imm6: u6,
1685 ) Instruction {
1686 return addSubtractShiftedRegister(0b1, 0b1, shift, rd, rn, rm, imm6);
1687 }
1688
1689 // Add/subtract (extended register)
1690
1691 pub fn addExtendedRegister(
1692 rd: Register,
1693 rn: Register,
1694 rm: Register,
1695 extend: AddSubtractExtendedRegisterOption,
1696 imm3: u3,
1697 ) Instruction {
1698 return addSubtractExtendedRegister(0b0, 0b0, rd, rn, rm, extend, imm3);
1699 }
1700
1701 pub fn addsExtendedRegister(
1702 rd: Register,
1703 rn: Register,
1704 rm: Register,
1705 extend: AddSubtractExtendedRegisterOption,
1706 imm3: u3,
1707 ) Instruction {
1708 return addSubtractExtendedRegister(0b0, 0b1, rd, rn, rm, extend, imm3);
1709 }
1710
1711 pub fn subExtendedRegister(
1712 rd: Register,
1713 rn: Register,
1714 rm: Register,
1715 extend: AddSubtractExtendedRegisterOption,
1716 imm3: u3,
1717 ) Instruction {
1718 return addSubtractExtendedRegister(0b1, 0b0, rd, rn, rm, extend, imm3);
1719 }
1720
1721 pub fn subsExtendedRegister(
1722 rd: Register,
1723 rn: Register,
1724 rm: Register,
1725 extend: AddSubtractExtendedRegisterOption,
1726 imm3: u3,
1727 ) Instruction {
1728 return addSubtractExtendedRegister(0b1, 0b1, rd, rn, rm, extend, imm3);
1729 }
1730
1731 // Conditional branch
1732
1733 pub fn bCond(cond: Condition, offset: i21) Instruction {
1734 return conditionalBranch(0b0, 0b0, cond, offset);
1735 }
1736
1737 // Compare and branch
1738
1739 pub fn cbz(rt: Register, offset: i21) Instruction {
1740 return compareAndBranch(0b0, rt, offset);
1741 }
1742
1743 pub fn cbnz(rt: Register, offset: i21) Instruction {
1744 return compareAndBranch(0b1, rt, offset);
1745 }
1746
1747 // Conditional select
1748
1749 pub fn csel(rd: Register, rn: Register, rm: Register, cond: Condition) Instruction {
1750 return conditionalSelect(0b00, 0b0, 0b0, rd, rn, rm, cond);
1751 }
1752
1753 pub fn csinc(rd: Register, rn: Register, rm: Register, cond: Condition) Instruction {
1754 return conditionalSelect(0b01, 0b0, 0b0, rd, rn, rm, cond);
1755 }
1756
1757 pub fn csinv(rd: Register, rn: Register, rm: Register, cond: Condition) Instruction {
1758 return conditionalSelect(0b00, 0b1, 0b0, rd, rn, rm, cond);
1759 }
1760
1761 pub fn csneg(rd: Register, rn: Register, rm: Register, cond: Condition) Instruction {
1762 return conditionalSelect(0b01, 0b1, 0b0, rd, rn, rm, cond);
1763 }
1764
1765 // Data processing (3 source)
1766
1767 pub fn madd(rd: Register, rn: Register, rm: Register, ra: Register) Instruction {
1768 return dataProcessing3Source(0b00, 0b000, 0b0, rd, rn, rm, ra);
1769 }
1770
1771 pub fn smaddl(rd: Register, rn: Register, rm: Register, ra: Register) Instruction {
1772 assert(rd.size() == 64 and rn.size() == 32 and rm.size() == 32 and ra.size() == 64);
1773 return dataProcessing3Source(0b00, 0b001, 0b0, rd, rn, rm, ra);
1774 }
1775
1776 pub fn umaddl(rd: Register, rn: Register, rm: Register, ra: Register) Instruction {
1777 assert(rd.size() == 64 and rn.size() == 32 and rm.size() == 32 and ra.size() == 64);
1778 return dataProcessing3Source(0b00, 0b101, 0b0, rd, rn, rm, ra);
1779 }
1780
1781 pub fn msub(rd: Register, rn: Register, rm: Register, ra: Register) Instruction {
1782 return dataProcessing3Source(0b00, 0b000, 0b1, rd, rn, rm, ra);
1783 }
1784
1785 pub fn mul(rd: Register, rn: Register, rm: Register) Instruction {
1786 return madd(rd, rn, rm, .xzr);
1787 }
1788
1789 pub fn smull(rd: Register, rn: Register, rm: Register) Instruction {
1790 return smaddl(rd, rn, rm, .xzr);
1791 }
1792
1793 pub fn smulh(rd: Register, rn: Register, rm: Register) Instruction {
1794 assert(rd.size() == 64);
1795 return dataProcessing3Source(0b00, 0b010, 0b0, rd, rn, rm, .xzr);
1796 }
1797
1798 pub fn umull(rd: Register, rn: Register, rm: Register) Instruction {
1799 return umaddl(rd, rn, rm, .xzr);
1800 }
1801
1802 pub fn umulh(rd: Register, rn: Register, rm: Register) Instruction {
1803 assert(rd.size() == 64);
1804 return dataProcessing3Source(0b00, 0b110, 0b0, rd, rn, rm, .xzr);
1805 }
1806
1807 pub fn mneg(rd: Register, rn: Register, rm: Register) Instruction {
1808 return msub(rd, rn, rm, .xzr);
1809 }
1810
1811 // Data processing (2 source)
1812
1813 pub fn udiv(rd: Register, rn: Register, rm: Register) Instruction {
1814 return dataProcessing2Source(0b0, 0b000010, rd, rn, rm);
1815 }
1816
1817 pub fn sdiv(rd: Register, rn: Register, rm: Register) Instruction {
1818 return dataProcessing2Source(0b0, 0b000011, rd, rn, rm);
1819 }
1820
1821 pub fn lslv(rd: Register, rn: Register, rm: Register) Instruction {
1822 return dataProcessing2Source(0b0, 0b001000, rd, rn, rm);
1823 }
1824
1825 pub fn lsrv(rd: Register, rn: Register, rm: Register) Instruction {
1826 return dataProcessing2Source(0b0, 0b001001, rd, rn, rm);
1827 }
1828
1829 pub fn asrv(rd: Register, rn: Register, rm: Register) Instruction {
1830 return dataProcessing2Source(0b0, 0b001010, rd, rn, rm);
1831 }
1832
1833 pub const asrRegister = asrv;
1834 pub const lslRegister = lslv;
1835 pub const lsrRegister = lsrv;
1836};
1837
1838test {
1839 testing.refAllDecls(@This());
1840}
1841
1842test "serialize instructions" {
1843 const Testcase = struct {
1844 inst: Instruction,
1845 expected: u32,
1846 };
1847
1848 const testcases = [_]Testcase{
1849 .{ // orr x0, xzr, x1
1850 .inst = Instruction.orrShiftedRegister(.x0, .xzr, .x1, .lsl, 0),
1851 .expected = 0b1_01_01010_00_0_00001_000000_11111_00000,
1852 },
1853 .{ // orn x0, xzr, x1
1854 .inst = Instruction.ornShiftedRegister(.x0, .xzr, .x1, .lsl, 0),
1855 .expected = 0b1_01_01010_00_1_00001_000000_11111_00000,
1856 },
1857 .{ // movz x1, #4
1858 .inst = Instruction.movz(.x1, 4, 0),
1859 .expected = 0b1_10_100101_00_0000000000000100_00001,
1860 },
1861 .{ // movz x1, #4, lsl 16
1862 .inst = Instruction.movz(.x1, 4, 16),
1863 .expected = 0b1_10_100101_01_0000000000000100_00001,
1864 },
1865 .{ // movz x1, #4, lsl 32
1866 .inst = Instruction.movz(.x1, 4, 32),
1867 .expected = 0b1_10_100101_10_0000000000000100_00001,
1868 },
1869 .{ // movz x1, #4, lsl 48
1870 .inst = Instruction.movz(.x1, 4, 48),
1871 .expected = 0b1_10_100101_11_0000000000000100_00001,
1872 },
1873 .{ // movz w1, #4
1874 .inst = Instruction.movz(.w1, 4, 0),
1875 .expected = 0b0_10_100101_00_0000000000000100_00001,
1876 },
1877 .{ // movz w1, #4, lsl 16
1878 .inst = Instruction.movz(.w1, 4, 16),
1879 .expected = 0b0_10_100101_01_0000000000000100_00001,
1880 },
1881 .{ // svc #0
1882 .inst = Instruction.svc(0),
1883 .expected = 0b1101_0100_000_0000000000000000_00001,
1884 },
1885 .{ // svc #0x80 ; typical on Darwin
1886 .inst = Instruction.svc(0x80),
1887 .expected = 0b1101_0100_000_0000000010000000_00001,
1888 },
1889 .{ // ret
1890 .inst = Instruction.ret(null),
1891 .expected = 0b1101_011_00_10_11111_0000_00_11110_00000,
1892 },
1893 .{ // bl #0x10
1894 .inst = Instruction.bl(0x10),
1895 .expected = 0b1_00101_00_0000_0000_0000_0000_0000_0100,
1896 },
1897 .{ // ldr x2, [x1]
1898 .inst = Instruction.ldr(.x2, .x1, Instruction.LoadStoreOffset.none),
1899 .expected = 0b11_111_0_01_01_000000000000_00001_00010,
1900 },
1901 .{ // ldr x2, [x1, #1]!
1902 .inst = Instruction.ldr(.x2, .x1, Instruction.LoadStoreOffset.imm_pre_index(1)),
1903 .expected = 0b11_111_0_00_01_0_000000001_11_00001_00010,
1904 },
1905 .{ // ldr x2, [x1], #-1
1906 .inst = Instruction.ldr(.x2, .x1, Instruction.LoadStoreOffset.imm_post_index(-1)),
1907 .expected = 0b11_111_0_00_01_0_111111111_01_00001_00010,
1908 },
1909 .{ // ldr x2, [x1], (x3)
1910 .inst = Instruction.ldr(.x2, .x1, Instruction.LoadStoreOffset.reg(.x3)),
1911 .expected = 0b11_111_0_00_01_1_00011_011_0_10_00001_00010,
1912 },
1913 .{ // ldr x2, label
1914 .inst = Instruction.ldrLiteral(.x2, 0x1),
1915 .expected = 0b01_011_0_00_0000000000000000001_00010,
1916 },
1917 .{ // ldrh x7, [x4], #0xaa
1918 .inst = Instruction.ldrh(.x7, .x4, Instruction.LoadStoreOffset.imm_post_index(0xaa)),
1919 .expected = 0b01_111_0_00_01_0_010101010_01_00100_00111,
1920 },
1921 .{ // ldrb x9, [x15, #0xff]!
1922 .inst = Instruction.ldrb(.x9, .x15, Instruction.LoadStoreOffset.imm_pre_index(0xff)),
1923 .expected = 0b00_111_0_00_01_0_011111111_11_01111_01001,
1924 },
1925 .{ // str x2, [x1]
1926 .inst = Instruction.str(.x2, .x1, Instruction.LoadStoreOffset.none),
1927 .expected = 0b11_111_0_01_00_000000000000_00001_00010,
1928 },
1929 .{ // str x2, [x1], (x3)
1930 .inst = Instruction.str(.x2, .x1, Instruction.LoadStoreOffset.reg(.x3)),
1931 .expected = 0b11_111_0_00_00_1_00011_011_0_10_00001_00010,
1932 },
1933 .{ // strh w0, [x1]
1934 .inst = Instruction.strh(.w0, .x1, Instruction.LoadStoreOffset.none),
1935 .expected = 0b01_111_0_01_00_000000000000_00001_00000,
1936 },
1937 .{ // strb w8, [x9]
1938 .inst = Instruction.strb(.w8, .x9, Instruction.LoadStoreOffset.none),
1939 .expected = 0b00_111_0_01_00_000000000000_01001_01000,
1940 },
1941 .{ // adr x2, #0x8
1942 .inst = Instruction.adr(.x2, 0x8),
1943 .expected = 0b0_00_10000_0000000000000000010_00010,
1944 },
1945 .{ // adr x2, -#0x8
1946 .inst = Instruction.adr(.x2, -0x8),
1947 .expected = 0b0_00_10000_1111111111111111110_00010,
1948 },
1949 .{ // adrp x2, #0x8
1950 .inst = Instruction.adrp(.x2, 0x8),
1951 .expected = 0b1_00_10000_0000000000000000010_00010,
1952 },
1953 .{ // adrp x2, -#0x8
1954 .inst = Instruction.adrp(.x2, -0x8),
1955 .expected = 0b1_00_10000_1111111111111111110_00010,
1956 },
1957 .{ // stp x1, x2, [sp, #8]
1958 .inst = Instruction.stp(.x1, .x2, .sp, Instruction.LoadStorePairOffset.signed(8)),
1959 .expected = 0b10_101_0_010_0_0000001_00010_11111_00001,
1960 },
1961 .{ // ldp x1, x2, [sp, #8]
1962 .inst = Instruction.ldp(.x1, .x2, .sp, Instruction.LoadStorePairOffset.signed(8)),
1963 .expected = 0b10_101_0_010_1_0000001_00010_11111_00001,
1964 },
1965 .{ // stp x1, x2, [sp, #-16]!
1966 .inst = Instruction.stp(.x1, .x2, .sp, Instruction.LoadStorePairOffset.pre_index(-16)),
1967 .expected = 0b10_101_0_011_0_1111110_00010_11111_00001,
1968 },
1969 .{ // ldp x1, x2, [sp], #16
1970 .inst = Instruction.ldp(.x1, .x2, .sp, Instruction.LoadStorePairOffset.post_index(16)),
1971 .expected = 0b10_101_0_001_1_0000010_00010_11111_00001,
1972 },
1973 .{ // and x0, x4, x2
1974 .inst = Instruction.andShiftedRegister(.x0, .x4, .x2, .lsl, 0),
1975 .expected = 0b1_00_01010_00_0_00010_000000_00100_00000,
1976 },
1977 .{ // and x0, x4, x2, lsl #0x8
1978 .inst = Instruction.andShiftedRegister(.x0, .x4, .x2, .lsl, 0x8),
1979 .expected = 0b1_00_01010_00_0_00010_001000_00100_00000,
1980 },
1981 .{ // add x0, x10, #10
1982 .inst = Instruction.add(.x0, .x10, 10, false),
1983 .expected = 0b1_0_0_100010_0_0000_0000_1010_01010_00000,
1984 },
1985 .{ // subs x0, x5, #11, lsl #12
1986 .inst = Instruction.subs(.x0, .x5, 11, true),
1987 .expected = 0b1_1_1_100010_1_0000_0000_1011_00101_00000,
1988 },
1989 .{ // b.hi #-4
1990 .inst = Instruction.bCond(.hi, -4),
1991 .expected = 0b0101010_0_1111111111111111111_0_1000,
1992 },
1993 .{ // cbz x10, #40
1994 .inst = Instruction.cbz(.x10, 40),
1995 .expected = 0b1_011010_0_0000000000000001010_01010,
1996 },
1997 .{ // add x0, x1, x2, lsl #5
1998 .inst = Instruction.addShiftedRegister(.x0, .x1, .x2, .lsl, 5),
1999 .expected = 0b1_0_0_01011_00_0_00010_000101_00001_00000,
2000 },
2001 .{ // csinc x1, x2, x4, eq
2002 .inst = Instruction.csinc(.x1, .x2, .x4, .eq),
2003 .expected = 0b1_0_0_11010100_00100_0000_0_1_00010_00001,
2004 },
2005 .{ // mul x1, x4, x9
2006 .inst = Instruction.mul(.x1, .x4, .x9),
2007 .expected = 0b1_00_11011_000_01001_0_11111_00100_00001,
2008 },
2009 .{ // eor x3, x5, #1
2010 .inst = Instruction.eorImmediate(.x3, .x5, 0b000000, 0b000000, 0b1),
2011 .expected = 0b1_10_100100_1_000000_000000_00101_00011,
2012 },
2013 .{ // lslv x6, x9, x10
2014 .inst = Instruction.lslv(.x6, .x9, .x10),
2015 .expected = 0b1_0_0_11010110_01010_0010_00_01001_00110,
2016 },
2017 .{ // lsl x4, x2, #42
2018 .inst = Instruction.lslImmediate(.x4, .x2, 42),
2019 .expected = 0b1_10_100110_1_010110_010101_00010_00100,
2020 },
2021 .{ // lsl x4, x2, #63
2022 .inst = Instruction.lslImmediate(.x4, .x2, 63),
2023 .expected = 0b1_10_100110_1_000001_000000_00010_00100,
2024 },
2025 .{ // lsr x4, x2, #42
2026 .inst = Instruction.lsrImmediate(.x4, .x2, 42),
2027 .expected = 0b1_10_100110_1_101010_111111_00010_00100,
2028 },
2029 .{ // lsr x4, x2, #63
2030 .inst = Instruction.lsrImmediate(.x4, .x2, 63),
2031 .expected = 0b1_10_100110_1_111111_111111_00010_00100,
2032 },
2033 .{ // umull x0, w0, w1
2034 .inst = Instruction.umull(.x0, .w0, .w1),
2035 .expected = 0b1_00_11011_1_01_00001_0_11111_00000_00000,
2036 },
2037 .{ // smull x0, w0, w1
2038 .inst = Instruction.smull(.x0, .w0, .w1),
2039 .expected = 0b1_00_11011_0_01_00001_0_11111_00000_00000,
2040 },
2041 .{ // tst x0, #0xffffffff00000000
2042 .inst = Instruction.andsImmediate(.xzr, .x0, 0b011111, 0b100000, 0b1),
2043 .expected = 0b1_11_100100_1_100000_011111_00000_11111,
2044 },
2045 .{ // umulh x0, x1, x2
2046 .inst = Instruction.umulh(.x0, .x1, .x2),
2047 .expected = 0b1_00_11011_1_10_00010_0_11111_00001_00000,
2048 },
2049 .{ // smulh x0, x1, x2
2050 .inst = Instruction.smulh(.x0, .x1, .x2),
2051 .expected = 0b1_00_11011_0_10_00010_0_11111_00001_00000,
2052 },
2053 .{ // adds x0, x1, x2, sxtx
2054 .inst = Instruction.addsExtendedRegister(.x0, .x1, .x2, .sxtx, 0),
2055 .expected = 0b1_0_1_01011_00_1_00010_111_000_00001_00000,
2056 },
2057 };
2058
2059 for (testcases) |case| {
2060 const actual = case.inst.toU32();
2061 try testing.expectEqual(case.expected, actual);
2062 }
2063}
src/arch/riscv64/CodeGen.zig+5-5
......@@ -744,7 +744,7 @@ pub fn generate(
744744 src_loc: Zcu.LazySrcLoc,
745745 func_index: InternPool.Index,
746746 air: *const Air,
747 liveness: *const Air.Liveness,
747 liveness: *const ?Air.Liveness,
748748) CodeGenError!Mir {
749749 const zcu = pt.zcu;
750750 const gpa = zcu.gpa;
......@@ -767,7 +767,7 @@ pub fn generate(
767767 .pt = pt,
768768 .mod = mod,
769769 .bin_file = bin_file,
770 .liveness = liveness.*,
770 .liveness = liveness.*.?,
771771 .target = &mod.resolved_target.result,
772772 .owner = .{ .nav_index = func.owner_nav },
773773 .args = undefined, // populated after `resolveCallingConventionValues`
......@@ -4584,7 +4584,7 @@ fn structFieldPtr(func: *Func, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde
45844584 const field_offset: i32 = switch (container_ty.containerLayout(zcu)) {
45854585 .auto, .@"extern" => @intCast(container_ty.structFieldOffset(index, zcu)),
45864586 .@"packed" => @divExact(@as(i32, ptr_container_ty.ptrInfo(zcu).packed_offset.bit_offset) +
4587 (if (zcu.typeToStruct(container_ty)) |struct_obj| pt.structPackedFieldBitOffset(struct_obj, index) else 0) -
4587 (if (zcu.typeToStruct(container_ty)) |struct_obj| zcu.structPackedFieldBitOffset(struct_obj, index) else 0) -
45884588 ptr_field_ty.ptrInfo(zcu).packed_offset.bit_offset, 8),
45894589 };
45904590
......@@ -4615,7 +4615,7 @@ fn airStructFieldVal(func: *Func, inst: Air.Inst.Index) !void {
46154615 const field_off: u32 = switch (struct_ty.containerLayout(zcu)) {
46164616 .auto, .@"extern" => @intCast(struct_ty.structFieldOffset(index, zcu) * 8),
46174617 .@"packed" => if (zcu.typeToStruct(struct_ty)) |struct_type|
4618 pt.structPackedFieldBitOffset(struct_type, index)
4618 zcu.structPackedFieldBitOffset(struct_type, index)
46194619 else
46204620 0,
46214621 };
......@@ -8059,7 +8059,7 @@ fn airAggregateInit(func: *Func, inst: Air.Inst.Index) !void {
80598059
80608060 const elem_abi_size: u32 = @intCast(elem_ty.abiSize(zcu));
80618061 const elem_abi_bits = elem_abi_size * 8;
8062 const elem_off = pt.structPackedFieldBitOffset(struct_obj, elem_i);
8062 const elem_off = zcu.structPackedFieldBitOffset(struct_obj, elem_i);
80638063 const elem_byte_off: i32 = @intCast(elem_off / elem_abi_bits * elem_abi_size);
80648064 const elem_bit_off = elem_off % elem_abi_bits;
80658065 const elem_mcv = try func.resolveInst(elem);
src/arch/sparc64/CodeGen.zig+2-2
......@@ -267,7 +267,7 @@ pub fn generate(
267267 src_loc: Zcu.LazySrcLoc,
268268 func_index: InternPool.Index,
269269 air: *const Air,
270 liveness: *const Air.Liveness,
270 liveness: *const ?Air.Liveness,
271271) CodeGenError!Mir {
272272 const zcu = pt.zcu;
273273 const gpa = zcu.gpa;
......@@ -288,7 +288,7 @@ pub fn generate(
288288 .gpa = gpa,
289289 .pt = pt,
290290 .air = air.*,
291 .liveness = liveness.*,
291 .liveness = liveness.*.?,
292292 .target = target,
293293 .bin_file = lf,
294294 .func_index = func_index,
src/arch/wasm/CodeGen.zig+14-17
......@@ -1173,7 +1173,7 @@ pub fn generate(
11731173 src_loc: Zcu.LazySrcLoc,
11741174 func_index: InternPool.Index,
11751175 air: *const Air,
1176 liveness: *const Air.Liveness,
1176 liveness: *const ?Air.Liveness,
11771177) Error!Mir {
11781178 _ = src_loc;
11791179 _ = bin_file;
......@@ -1194,7 +1194,7 @@ pub fn generate(
11941194 .gpa = gpa,
11951195 .pt = pt,
11961196 .air = air.*,
1197 .liveness = liveness.*,
1197 .liveness = liveness.*.?,
11981198 .owner_nav = cg.owner_nav,
11991199 .target = target,
12001200 .ptr_size = switch (target.cpu.arch) {
......@@ -1886,8 +1886,10 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
18861886 .call_never_tail => cg.airCall(inst, .never_tail),
18871887 .call_never_inline => cg.airCall(inst, .never_inline),
18881888
1889 .is_err => cg.airIsErr(inst, .i32_ne),
1890 .is_non_err => cg.airIsErr(inst, .i32_eq),
1889 .is_err => cg.airIsErr(inst, .i32_ne, .value),
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
18921894 .is_null => cg.airIsNull(inst, .i32_eq, .value),
18931895 .is_non_null => cg.airIsNull(inst, .i32_ne, .value),
......@@ -1970,8 +1972,6 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
19701972 .runtime_nav_ptr => cg.airRuntimeNavPtr(inst),
19711973
19721974 .assembly,
1973 .is_err_ptr,
1974 .is_non_err_ptr,
19751975
19761976 .err_return_trace,
19771977 .set_err_return_trace,
......@@ -3776,7 +3776,7 @@ fn structFieldPtr(
37763776 break :offset @as(u32, 0);
37773777 }
37783778 const struct_type = zcu.typeToStruct(struct_ty).?;
3779 break :offset @divExact(pt.structPackedFieldBitOffset(struct_type, index) + struct_ptr_ty_info.packed_offset.bit_offset, 8);
3779 break :offset @divExact(zcu.structPackedFieldBitOffset(struct_type, index) + struct_ptr_ty_info.packed_offset.bit_offset, 8);
37803780 },
37813781 .@"union" => 0,
37823782 else => unreachable,
......@@ -3812,7 +3812,7 @@ fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
38123812 .@"packed" => switch (struct_ty.zigTypeTag(zcu)) {
38133813 .@"struct" => result: {
38143814 const packed_struct = zcu.typeToPackedStruct(struct_ty).?;
3815 const offset = pt.structPackedFieldBitOffset(packed_struct, field_index);
3815 const offset = zcu.structPackedFieldBitOffset(packed_struct, field_index);
38163816 const backing_ty = Type.fromInterned(packed_struct.backingIntTypeUnordered(ip));
38173817 const host_bits = backing_ty.intInfo(zcu).bits;
38183818
......@@ -4105,7 +4105,7 @@ fn airSwitchDispatch(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
41054105 return cg.finishAir(inst, .none, &.{br.operand});
41064106}
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 {
41094109 const zcu = cg.pt.zcu;
41104110 const un_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
41114111 const operand = try cg.resolveInst(un_op);
......@@ -4122,7 +4122,7 @@ fn airIsErr(cg: *CodeGen, inst: Air.Inst.Index, opcode: std.wasm.Opcode) InnerEr
41224122 }
41234123
41244124 try cg.emitWValue(operand);
4125 if (pl_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
4125 if (op_kind == .ptr or pl_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
41264126 try cg.addMemArg(.i32_load16_u, .{
41274127 .offset = operand.offset() + @as(u32, @intCast(errUnionErrorOffset(pl_ty, zcu))),
41284128 .alignment = @intCast(Type.anyerror.abiAlignment(zcu).toByteUnits().?),
......@@ -5696,7 +5696,7 @@ fn airFieldParentPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
56965696 .auto, .@"extern" => parent_ty.structFieldOffset(field_index, zcu),
56975697 .@"packed" => offset: {
56985698 const parent_ptr_offset = parent_ptr_ty.ptrInfo(zcu).packed_offset.bit_offset;
5699 const field_offset = if (zcu.typeToStruct(parent_ty)) |loaded_struct| pt.structPackedFieldBitOffset(loaded_struct, field_index) else 0;
5699 const field_offset = if (zcu.typeToStruct(parent_ty)) |loaded_struct| zcu.structPackedFieldBitOffset(loaded_struct, field_index) else 0;
57005700 const field_ptr_offset = field_ptr_ty.ptrInfo(zcu).packed_offset.bit_offset;
57015701 break :offset @divExact(parent_ptr_offset + field_offset - field_ptr_offset, 8);
57025702 },
......@@ -6462,9 +6462,6 @@ fn lowerTry(
64626462 operand_is_ptr: bool,
64636463) InnerError!WValue {
64646464 const zcu = cg.pt.zcu;
6465 if (operand_is_ptr) {
6466 return cg.fail("TODO: lowerTry for pointers", .{});
6467 }
64686465
64696466 const pl_ty = err_union_ty.errorUnionPayload(zcu);
64706467 const pl_has_bits = pl_ty.hasRuntimeBitsIgnoreComptime(zcu);
......@@ -6475,7 +6472,7 @@ fn lowerTry(
64756472
64766473 // check if the error tag is set for the error union.
64776474 try cg.emitWValue(err_union);
6478 if (pl_has_bits) {
6475 if (pl_has_bits or operand_is_ptr) {
64796476 const err_offset: u32 = @intCast(errUnionErrorOffset(pl_ty, zcu));
64806477 try cg.addMemArg(.i32_load16_u, .{
64816478 .offset = err_union.offset() + err_offset,
......@@ -6497,12 +6494,12 @@ fn lowerTry(
64976494 }
64986495
64996496 // 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) {
65016498 return .none;
65026499 }
65036500
65046501 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)) {
65066503 return buildPointerOffset(cg, err_union, pl_offset, .new);
65076504 }
65086505 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(
878878 src_loc: Zcu.LazySrcLoc,
879879 func_index: InternPool.Index,
880880 air: *const Air,
881 liveness: *const Air.Liveness,
881 liveness: *const ?Air.Liveness,
882882) codegen.CodeGenError!Mir {
883883 _ = bin_file;
884884 const zcu = pt.zcu;
......@@ -894,7 +894,7 @@ pub fn generate(
894894 .gpa = gpa,
895895 .pt = pt,
896896 .air = air.*,
897 .liveness = liveness.*,
897 .liveness = liveness.*.?,
898898 .target = &mod.resolved_target.result,
899899 .mod = mod,
900900 .owner = .{ .nav_index = func.owner_nav },
......@@ -1103,11 +1103,7 @@ const FormatAirData = struct {
11031103 inst: Air.Inst.Index,
11041104};
11051105fn formatAir(data: FormatAirData, w: *std.io.Writer) Writer.Error!void {
1106 // not acceptable implementation because it ignores `w`:
1107 //data.self.air.dumpInst(data.inst, data.self.pt, data.self.liveness);
1108 _ = data;
1109 _ = w;
1110 @panic("TODO: unimplemented");
1106 data.self.air.writeInst(w, data.inst, data.self.pt, data.self.liveness);
11111107}
11121108fn fmtAir(self: *CodeGen, inst: Air.Inst.Index) std.fmt.Formatter(FormatAirData, formatAir) {
11131109 return .{ .data = .{ .self = self, .inst = inst } };
......@@ -100674,11 +100670,12 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
100674100670 const ty_pl = air_datas[@intFromEnum(inst)].ty_pl;
100675100671 const struct_field = cg.air.extraData(Air.StructField, ty_pl.payload).data;
100676100672 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(
100678100674 cg.typeOf(struct_field.struct_operand),
100679100675 ty_pl.ty.toType(),
100680100676 struct_field.field_index,
100681 ), cg);
100677 zcu,
100678 )), cg);
100682100679 try ops[0].finish(inst, &.{struct_field.struct_operand}, &ops, cg);
100683100680 },
100684100681 .struct_field_ptr_index_0,
......@@ -100688,7 +100685,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
100688100685 => |air_tag| {
100689100686 const ty_op = air_datas[@intFromEnum(inst)].ty_op;
100690100687 var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
100691 try ops[0].toOffset(cg.fieldOffset(
100688 try ops[0].toOffset(@intCast(codegen.fieldOffset(
100692100689 cg.typeOf(ty_op.operand),
100693100690 ty_op.ty.toType(),
100694100691 switch (air_tag) {
......@@ -100698,7 +100695,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
100698100695 .struct_field_ptr_index_2 => 2,
100699100696 .struct_field_ptr_index_3 => 3,
100700100697 },
100701 ), cg);
100698 zcu,
100699 )), cg);
100702100700 try ops[0].finish(inst, &.{ty_op.operand}, &ops, cg);
100703100701 },
100704100702 .struct_field_val => {
......@@ -168108,11 +168106,12 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
168108168106 const ty_pl = air_datas[@intFromEnum(inst)].ty_pl;
168109168107 const field_parent_ptr = cg.air.extraData(Air.FieldParentPtr, ty_pl.payload).data;
168110168108 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(
168112168110 ty_pl.ty.toType(),
168113168111 cg.typeOf(field_parent_ptr.field_ptr),
168114168112 field_parent_ptr.field_index,
168115 ), cg);
168113 zcu,
168114 ))), cg);
168116168115 try ops[0].finish(inst, &.{field_parent_ptr.field_ptr}, &ops, cg);
168117168116 },
168118168117 .wasm_memory_size, .wasm_memory_grow => unreachable,
......@@ -168138,7 +168137,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
168138168137 .unused,
168139168138 .unused,
168140168139 },
168141 .dst_temps = .{ .{ .cc = .b }, .unused },
168140 .dst_temps = .{ .{ .cc = .be }, .unused },
168142168141 .clobbers = .{ .eflags = true },
168143168142 .each = .{ .once = &.{
168144168143 .{ ._, ._, .lea, .tmp1p, .lea(.tmp0), ._, ._ },
......@@ -168162,7 +168161,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
168162168161 .unused,
168163168162 .unused,
168164168163 },
168165 .dst_temps = .{ .{ .cc = .b }, .unused },
168164 .dst_temps = .{ .{ .cc = .be }, .unused },
168166168165 .clobbers = .{ .eflags = true },
168167168166 .each = .{ .once = &.{
168168168167 .{ ._, ._, .lea, .tmp1p, .lea(.tmp0), ._, ._ },
......@@ -168186,7 +168185,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
168186168185 .unused,
168187168186 .unused,
168188168187 },
168189 .dst_temps = .{ .{ .cc = .b }, .unused },
168188 .dst_temps = .{ .{ .cc = .be }, .unused },
168190168189 .clobbers = .{ .eflags = true },
168191168190 .each = .{ .once = &.{
168192168191 .{ ._, ._, .lea, .tmp1p, .lea(.tmp0), ._, ._ },
......@@ -174809,18 +174808,6 @@ fn airStore(self: *CodeGen, inst: Air.Inst.Index, safety: bool) !void {
174809174808 return self.finishAir(inst, .none, .{ bin_op.lhs, bin_op.rhs, .none });
174810174809}
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
174824174811fn genUnOp(self: *CodeGen, maybe_inst: ?Air.Inst.Index, tag: Air.Inst.Tag, src_air: Air.Inst.Ref) !MCValue {
174825174812 const pt = self.pt;
174826174813 const zcu = pt.zcu;
......@@ -179309,10 +179296,13 @@ fn lowerSwitchBr(
179309179296 } else undefined;
179310179297 const table_start: u31 = @intCast(cg.mir_table.items.len);
179311179298 {
179312 const condition_index_reg = if (condition_index.isRegister())
179313 condition_index.getReg().?
179314 else
179315 try cg.copyToTmpRegister(.usize, condition_index);
179299 const condition_index_reg = condition_index_reg: {
179300 if (condition_index.isRegister()) {
179301 const condition_index_reg = condition_index.getReg().?;
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 };
179316179306 const condition_index_lock = cg.register_manager.lockReg(condition_index_reg);
179317179307 defer if (condition_index_lock) |lock| cg.register_manager.unlockReg(lock);
179318179308 try cg.truncateRegister(condition_ty, condition_index_reg);
......@@ -184575,7 +184565,7 @@ fn airAggregateInit(self: *CodeGen, inst: Air.Inst.Index) !void {
184575184565 }
184576184566 const elem_abi_size: u32 = @intCast(elem_ty.abiSize(zcu));
184577184567 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);
184579184569 const elem_byte_off: i32 = @intCast(elem_off / elem_abi_bits * elem_abi_size);
184580184570 const elem_bit_off = elem_off % elem_abi_bits;
184581184571 const elem_mcv = try self.resolveInst(elem);
......@@ -185625,21 +185615,19 @@ fn resolveCallingConventionValues(
185625185615fn fail(cg: *CodeGen, comptime format: []const u8, args: anytype) error{ OutOfMemory, CodegenFail } {
185626185616 @branchHint(.cold);
185627185617 const zcu = cg.pt.zcu;
185628 switch (cg.owner) {
185629 .nav_index => |i| return zcu.codegenFail(i, format, args),
185630 .lazy_sym => |s| return zcu.codegenFailType(s.ty, format, args),
185631 }
185632 return error.CodegenFail;
185618 return switch (cg.owner) {
185619 .nav_index => |i| zcu.codegenFail(i, format, args),
185620 .lazy_sym => |s| zcu.codegenFailType(s.ty, format, args),
185621 };
185633185622}
185634185623
185635185624fn failMsg(cg: *CodeGen, msg: *Zcu.ErrorMsg) error{ OutOfMemory, CodegenFail } {
185636185625 @branchHint(.cold);
185637185626 const zcu = cg.pt.zcu;
185638 switch (cg.owner) {
185639 .nav_index => |i| return zcu.codegenFailMsg(i, msg),
185640 .lazy_sym => |s| return zcu.codegenFailTypeMsg(s.ty, msg),
185641 }
185642 return error.CodegenFail;
185627 return switch (cg.owner) {
185628 .nav_index => |i| zcu.codegenFailMsg(i, msg),
185629 .lazy_sym => |s| zcu.codegenFailTypeMsg(s.ty, msg),
185630 };
185643185631}
185644185632
185645185633fn parseRegName(name: []const u8) ?Register {
......@@ -191932,18 +191920,15 @@ const Select = struct {
191932191920 error.InvalidInstruction => {
191933191921 const fixes = @tagName(mir_tag[0]);
191934191922 const fixes_blank = std.mem.indexOfScalar(u8, fixes, '_').?;
191935 return s.cg.fail(
191936 "invalid instruction: '{s}{s}{s} {s} {s} {s} {s}'",
191937 .{
191938 fixes[0..fixes_blank],
191939 @tagName(mir_tag[1]),
191940 fixes[fixes_blank + 1 ..],
191941 @tagName(mir_ops[0]),
191942 @tagName(mir_ops[1]),
191943 @tagName(mir_ops[2]),
191944 @tagName(mir_ops[3]),
191945 },
191946 );
191923 return s.cg.fail("invalid instruction: '{s}{s}{s} {s} {s} {s} {s}'", .{
191924 fixes[0..fixes_blank],
191925 @tagName(mir_tag[1]),
191926 fixes[fixes_blank + 1 ..],
191927 @tagName(mir_ops[0]),
191928 @tagName(mir_ops[1]),
191929 @tagName(mir_ops[2]),
191930 @tagName(mir_ops[3]),
191931 });
191947191932 },
191948191933 else => |e| return e,
191949191934 };
......@@ -194435,6 +194420,18 @@ fn select(
194435194420 while (true) for (pattern.src[0..src_temps.len], src_temps) |src_pattern, *src_temp| {
194436194421 if (try src_pattern.convert(src_temp, cg)) break;
194437194422 } 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 }
194438194435 @memcpy(s_src_temps[0..src_temps.len], src_temps);
194439194436 std.mem.swap(Temp, &s_src_temps[pattern.commute[0]], &s_src_temps[pattern.commute[1]]);
194440194437
......@@ -194453,6 +194450,7 @@ fn select(
194453194450 }
194454194451 assert(s.top == 0);
194455194452
194453 for (src_locks) |locks| for (locks) |lock| if (lock) |reg| cg.register_manager.unlockReg(reg);
194456194454 for (tmp_locks) |locks| for (locks) |lock| if (lock) |reg| cg.register_manager.unlockReg(reg);
194457194455 for (dst_locks) |locks| for (locks) |lock| if (lock) |reg| cg.register_manager.unlockReg(reg);
194458194456 caller_preserved: {
src/arch/x86_64/Emit.zig+6-5
......@@ -168,11 +168,12 @@ pub fn emitMir(emit: *Emit) Error!void {
168168 else if (emit.bin_file.cast(.macho)) |macho_file|
169169 macho_file.getZigObject().?.getOrCreateMetadataForLazySymbol(macho_file, emit.pt, lazy_sym) catch |err|
170170 return emit.fail("{s} creating lazy symbol", .{@errorName(err)})
171 else if (emit.bin_file.cast(.coff)) |coff_file| sym_index: {
172 const atom = coff_file.getOrCreateAtomForLazySymbol(emit.pt, lazy_sym) catch |err|
173 return emit.fail("{s} creating lazy symbol", .{@errorName(err)});
174 break :sym_index coff_file.getAtom(atom).getSymbolIndex().?;
175 } else if (emit.bin_file.cast(.plan9)) |p9_file|
171 else if (emit.bin_file.cast(.coff)) |coff_file|
172 if (coff_file.getOrCreateAtomForLazySymbol(emit.pt, lazy_sym)) |atom|
173 coff_file.getAtom(atom).getSymbolIndex().?
174 else |err|
175 return emit.fail("{s} creating lazy symbol", .{@errorName(err)})
176 else if (emit.bin_file.cast(.plan9)) |p9_file|
176177 p9_file.getOrCreateAtomForLazySymbol(emit.pt, lazy_sym) catch |err|
177178 return emit.fail("{s} creating lazy symbol", .{@errorName(err)})
178179 else
src/codegen.zig+48-13
......@@ -22,6 +22,8 @@ const Zir = std.zig.Zir;
2222const Alignment = InternPool.Alignment;
2323const dev = @import("dev.zig");
2424
25pub const aarch64 = @import("codegen/aarch64.zig");
26
2527pub const CodeGenError = GenerateSymbolError || error{
2628 /// Indicates the error is already stored in Zcu `failed_codegen`.
2729 CodegenFail,
......@@ -48,7 +50,7 @@ fn devFeatureForBackend(backend: std.builtin.CompilerBackend) dev.Feature {
4850fn importBackend(comptime backend: std.builtin.CompilerBackend) type {
4951 return switch (backend) {
5052 .other, .stage1 => unreachable,
51 .stage2_aarch64 => unreachable,
53 .stage2_aarch64 => aarch64,
5254 .stage2_arm => unreachable,
5355 .stage2_c => @import("codegen/c.zig"),
5456 .stage2_llvm => @import("codegen/llvm.zig"),
......@@ -71,6 +73,7 @@ pub fn legalizeFeatures(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) ?*co
7173 .stage2_c,
7274 .stage2_wasm,
7375 .stage2_x86_64,
76 .stage2_aarch64,
7477 .stage2_x86,
7578 .stage2_riscv64,
7679 .stage2_sparc64,
......@@ -82,20 +85,29 @@ pub fn legalizeFeatures(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) ?*co
8285 }
8386}
8487
88pub fn wantsLiveness(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) bool {
89 const zcu = pt.zcu;
90 const target = &zcu.navFileScope(nav_index).mod.?.resolved_target.result;
91 return switch (target_util.zigBackend(target, zcu.comp.config.use_llvm)) {
92 else => true,
93 .stage2_aarch64 => false,
94 };
95}
96
8597/// Every code generation backend has a different MIR representation. However, we want to pass
8698/// MIR from codegen to the linker *regardless* of which backend is in use. So, we use this: a
8799/// union of all MIR types. The active tag is known from the backend in use; see `AnyMir.tag`.
88100pub const AnyMir = union {
89 riscv64: @import("arch/riscv64/Mir.zig"),
90 sparc64: @import("arch/sparc64/Mir.zig"),
91 x86_64: @import("arch/x86_64/Mir.zig"),
92 wasm: @import("arch/wasm/Mir.zig"),
93 c: @import("codegen/c.zig").Mir,
101 aarch64: if (dev.env.supports(.aarch64_backend)) @import("codegen/aarch64/Mir.zig") else noreturn,
102 riscv64: if (dev.env.supports(.riscv64_backend)) @import("arch/riscv64/Mir.zig") else noreturn,
103 sparc64: if (dev.env.supports(.sparc64_backend)) @import("arch/sparc64/Mir.zig") else noreturn,
104 x86_64: if (dev.env.supports(.x86_64_backend)) @import("arch/x86_64/Mir.zig") else noreturn,
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
95108 pub inline fn tag(comptime backend: std.builtin.CompilerBackend) []const u8 {
96109 return switch (backend) {
97110 .stage2_aarch64 => "aarch64",
98 .stage2_arm => "arm",
99111 .stage2_riscv64 => "riscv64",
100112 .stage2_sparc64 => "sparc64",
101113 .stage2_x86_64 => "x86_64",
......@@ -110,7 +122,8 @@ pub const AnyMir = union {
110122 const backend = target_util.zigBackend(&zcu.root_mod.resolved_target.result, zcu.comp.config.use_llvm);
111123 switch (backend) {
112124 else => unreachable,
113 inline .stage2_riscv64,
125 inline .stage2_aarch64,
126 .stage2_riscv64,
114127 .stage2_sparc64,
115128 .stage2_x86_64,
116129 .stage2_wasm,
......@@ -131,14 +144,15 @@ pub fn generateFunction(
131144 src_loc: Zcu.LazySrcLoc,
132145 func_index: InternPool.Index,
133146 air: *const Air,
134 liveness: *const Air.Liveness,
147 liveness: *const ?Air.Liveness,
135148) CodeGenError!AnyMir {
136149 const zcu = pt.zcu;
137150 const func = zcu.funcInfo(func_index);
138151 const target = &zcu.navFileScope(func.owner_nav).mod.?.resolved_target.result;
139152 switch (target_util.zigBackend(target, false)) {
140153 else => unreachable,
141 inline .stage2_riscv64,
154 inline .stage2_aarch64,
155 .stage2_riscv64,
142156 .stage2_sparc64,
143157 .stage2_x86_64,
144158 .stage2_wasm,
......@@ -173,7 +187,8 @@ pub fn emitFunction(
173187 const target = &zcu.navFileScope(func.owner_nav).mod.?.resolved_target.result;
174188 switch (target_util.zigBackend(target, zcu.comp.config.use_llvm)) {
175189 else => unreachable,
176 inline .stage2_riscv64,
190 inline .stage2_aarch64,
191 .stage2_riscv64,
177192 .stage2_sparc64,
178193 .stage2_x86_64,
179194 => |backend| {
......@@ -420,7 +435,7 @@ pub fn generateSymbol(
420435 const int_tag_ty = ty.intTagType(zcu);
421436 try generateSymbol(bin_file, pt, src_loc, try pt.getCoerced(Value.fromInterned(enum_tag.int), int_tag_ty), code, reloc_parent);
422437 },
423 .float => |float| switch (float.storage) {
438 .float => |float| storage: switch (float.storage) {
424439 .f16 => |f16_val| writeFloat(f16, f16_val, target, endian, try code.addManyAsArray(gpa, 2)),
425440 .f32 => |f32_val| writeFloat(f32, f32_val, target, endian, try code.addManyAsArray(gpa, 4)),
426441 .f64 => |f64_val| writeFloat(f64, f64_val, target, endian, try code.addManyAsArray(gpa, 8)),
......@@ -429,7 +444,13 @@ pub fn generateSymbol(
429444 const abi_size = math.cast(usize, ty.abiSize(zcu)) orelse return error.Overflow;
430445 try code.appendNTimes(gpa, 0, abi_size - 10);
431446 },
432 .f128 => |f128_val| writeFloat(f128, f128_val, target, endian, try code.addManyAsArray(gpa, 16)),
447 .f128 => |f128_val| switch (Type.fromInterned(float.ty).floatBits(target)) {
448 else => unreachable,
449 16 => continue :storage .{ .f16 = @floatCast(f128_val) },
450 32 => continue :storage .{ .f32 = @floatCast(f128_val) },
451 64 => continue :storage .{ .f64 = @floatCast(f128_val) },
452 128 => writeFloat(f128, f128_val, target, endian, try code.addManyAsArray(gpa, 16)),
453 },
433454 },
434455 .ptr => try lowerPtr(bin_file, pt, src_loc, val.toIntern(), code, reloc_parent, 0),
435456 .slice => |slice| {
......@@ -1218,3 +1239,17 @@ pub fn errUnionErrorOffset(payload_ty: Type, zcu: *Zcu) u64 {
12181239 return 0;
12191240 }
12201241}
1242
1243pub fn fieldOffset(ptr_agg_ty: Type, ptr_field_ty: Type, field_index: u32, zcu: *Zcu) u64 {
1244 const agg_ty = ptr_agg_ty.childType(zcu);
1245 return switch (agg_ty.containerLayout(zcu)) {
1246 .auto, .@"extern" => agg_ty.structFieldOffset(field_index, zcu),
1247 .@"packed" => @divExact(@as(u64, ptr_agg_ty.ptrInfo(zcu).packed_offset.bit_offset) +
1248 (if (zcu.typeToPackedStruct(agg_ty)) |loaded_struct| zcu.structPackedFieldBitOffset(loaded_struct, field_index) else 0) -
1249 ptr_field_ty.ptrInfo(zcu).packed_offset.bit_offset, 8),
1250 };
1251}
1252
1253test {
1254 _ = aarch64;
1255}
src/codegen/aarch64.zig created+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 @@
1const assert = @import("std").debug.assert;
12const std = @import("std");
2const builtin = @import("builtin");
3const bits = @import("../../arch/aarch64/bits.zig");
4const Register = bits.Register;
53const Type = @import("../../Type.zig");
64const Zcu = @import("../../Zcu.zig");
75
......@@ -15,7 +13,7 @@ pub const Class = union(enum) {
1513
1614/// For `float_array` the second element will be the amount of floats.
1715pub fn classifyType(ty: Type, zcu: *Zcu) Class {
18 std.debug.assert(ty.hasRuntimeBitsIgnoreComptime(zcu));
16 assert(ty.hasRuntimeBitsIgnoreComptime(zcu));
1917
2018 var maybe_float_bits: ?u16 = null;
2119 switch (ty.zigTypeTag(zcu)) {
......@@ -47,11 +45,11 @@ pub fn classifyType(ty: Type, zcu: *Zcu) Class {
4745 return .byval;
4846 },
4947 .optional => {
50 std.debug.assert(ty.isPtrLikeOptional(zcu));
48 assert(ty.isPtrLikeOptional(zcu));
5149 return .byval;
5250 },
5351 .pointer => {
54 std.debug.assert(!ty.isSlice(zcu));
52 assert(!ty.isSlice(zcu));
5553 return .byval;
5654 },
5755 .error_union,
......@@ -138,13 +136,3 @@ pub fn getFloatArrayType(ty: Type, zcu: *Zcu) ?Type {
138136 else => return null,
139137 }
140138}
141
142pub const callee_preserved_regs = [_]Register{
143 .x19, .x20, .x21, .x22, .x23,
144 .x24, .x25, .x26, .x27, .x28,
145};
146
147pub const c_abi_int_param_regs = [_]Register{ .x0, .x1, .x2, .x3, .x4, .x5, .x6, .x7 };
148pub const c_abi_int_return_regs = [_]Register{ .x0, .x1, .x2, .x3, .x4, .x5, .x6, .x7 };
149
150const allocatable_registers = callee_preserved_regs;
src/codegen/aarch64/encoding.zig created+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 {
449449 if (gop.found_existing) return gop.value_ptr.*;
450450
451451 const pt = f.object.dg.pt;
452 const zcu = pt.zcu;
452453 const val = (try f.air.value(ref, pt)).?;
453454 const ty = f.typeOf(ref);
454455
455 const result: CValue = if (lowersToArray(ty, pt)) result: {
456 const result: CValue = if (lowersToArray(ty, zcu)) result: {
456457 const ch = &f.object.code_header.writer;
457458 const decl_c_value = try f.allocLocalValue(.{
458459 .ctype = try f.ctypeFromType(ty, .complete),
459 .alignas = CType.AlignAs.fromAbiAlignment(ty.abiAlignment(pt.zcu)),
460 .alignas = CType.AlignAs.fromAbiAlignment(ty.abiAlignment(zcu)),
460461 });
461462 const gpa = f.object.dg.gpa;
462463 try f.allocs.put(gpa, decl_c_value.new_local, false);
......@@ -916,7 +917,7 @@ pub const DeclGen = struct {
916917 // Ensure complete type definition is available before accessing fields.
917918 _ = try dg.ctypeFromType(parent_ptr_ty.childType(zcu), .complete);
918919
919 switch (fieldLocation(parent_ptr_ty, field.result_ptr_ty, field.field_idx, pt)) {
920 switch (fieldLocation(parent_ptr_ty, field.result_ptr_ty, field.field_idx, zcu)) {
920921 .begin => {
921922 const ptr_ctype = try dg.ctypeFromType(field.result_ptr_ty, .complete);
922923 try w.writeByte('(');
......@@ -3008,7 +3009,7 @@ pub fn generate(
30083009 src_loc: Zcu.LazySrcLoc,
30093010 func_index: InternPool.Index,
30103011 air: *const Air,
3011 liveness: *const Air.Liveness,
3012 liveness: *const ?Air.Liveness,
30123013) @import("../codegen.zig").CodeGenError!Mir {
30133014 const zcu = pt.zcu;
30143015 const gpa = zcu.gpa;
......@@ -3021,7 +3022,7 @@ pub fn generate(
30213022 var function: Function = .{
30223023 .value_map = .init(gpa),
30233024 .air = air.*,
3024 .liveness = liveness.*,
3025 .liveness = liveness.*.?,
30253026 .func_index = func_index,
30263027 .object = .{
30273028 .dg = .{
......@@ -3961,7 +3962,7 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {
39613962 ptr_info.flags.alignment.order(src_ty.abiAlignment(zcu)).compare(.gte)
39623963 else
39633964 true;
3964 const is_array = lowersToArray(src_ty, pt);
3965 const is_array = lowersToArray(src_ty, zcu);
39653966 const need_memcpy = !is_aligned or is_array;
39663967
39673968 const w = &f.object.code.writer;
......@@ -4044,7 +4045,7 @@ fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !void {
40444045 const operand = try f.resolveInst(un_op);
40454046 try reap(f, inst, &.{un_op});
40464047 var deref = is_ptr;
4047 const is_array = lowersToArray(ret_ty, pt);
4048 const is_array = lowersToArray(ret_ty, zcu);
40484049 const ret_val = if (is_array) ret_val: {
40494050 const array_local = try f.allocAlignedLocal(inst, .{
40504051 .ctype = ret_ctype,
......@@ -4228,7 +4229,7 @@ fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue {
42284229 ptr_info.flags.alignment.order(src_ty.abiAlignment(zcu)).compare(.gte)
42294230 else
42304231 true;
4231 const is_array = lowersToArray(.fromInterned(ptr_info.child), pt);
4232 const is_array = lowersToArray(.fromInterned(ptr_info.child), zcu);
42324233 const need_memcpy = !is_aligned or is_array;
42334234
42344235 const src_val = try f.resolveInst(bin_op.rhs);
......@@ -4873,7 +4874,7 @@ fn airCall(
48734874 }
48744875
48754876 const result = result: {
4876 if (result_local == .none or !lowersToArray(ret_ty, pt))
4877 if (result_local == .none or !lowersToArray(ret_ty, zcu))
48774878 break :result result_local;
48784879
48794880 const array_local = try f.allocLocal(inst, ret_ty);
......@@ -5971,13 +5972,12 @@ fn fieldLocation(
59715972 container_ptr_ty: Type,
59725973 field_ptr_ty: Type,
59735974 field_index: u32,
5974 pt: Zcu.PerThread,
5975 zcu: *Zcu,
59755976) union(enum) {
59765977 begin: void,
59775978 field: CValue,
59785979 byte_offset: u64,
59795980} {
5980 const zcu = pt.zcu;
59815981 const ip = &zcu.intern_pool;
59825982 const container_ty: Type = .fromInterned(ip.indexToKey(container_ptr_ty.toIntern()).ptr_type.child);
59835983 switch (ip.indexToKey(container_ty.toIntern())) {
......@@ -5994,7 +5994,7 @@ fn fieldLocation(
59945994 else
59955995 .{ .field = field_index } },
59965996 .@"packed" => if (field_ptr_ty.ptrInfo(zcu).packed_offset.host_size == 0)
5997 .{ .byte_offset = @divExact(pt.structPackedFieldBitOffset(loaded_struct, field_index) +
5997 .{ .byte_offset = @divExact(zcu.structPackedFieldBitOffset(loaded_struct, field_index) +
59985998 container_ptr_ty.ptrInfo(zcu).packed_offset.bit_offset, 8) }
59995999 else
60006000 .begin,
......@@ -6076,7 +6076,7 @@ fn airFieldParentPtr(f: *Function, inst: Air.Inst.Index) !CValue {
60766076 try f.renderType(w, container_ptr_ty);
60776077 try w.writeByte(')');
60786078
6079 switch (fieldLocation(container_ptr_ty, field_ptr_ty, extra.field_index, pt)) {
6079 switch (fieldLocation(container_ptr_ty, field_ptr_ty, extra.field_index, zcu)) {
60806080 .begin => try f.writeCValue(w, field_ptr_val, .Other),
60816081 .field => |field| {
60826082 const u8_ptr_ty = try pt.adjustPtrTypeChild(field_ptr_ty, .u8);
......@@ -6131,7 +6131,7 @@ fn fieldPtr(
61316131 try f.renderType(w, field_ptr_ty);
61326132 try w.writeByte(')');
61336133
6134 switch (fieldLocation(container_ptr_ty, field_ptr_ty, field_index, pt)) {
6134 switch (fieldLocation(container_ptr_ty, field_ptr_ty, field_index, zcu)) {
61356135 .begin => try f.writeCValue(w, container_ptr_val, .Other),
61366136 .field => |field| {
61376137 try w.writeByte('&');
......@@ -6189,7 +6189,7 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
61896189
61906190 const bit_offset_ty = try pt.intType(.unsigned, Type.smallestUnsignedBits(int_info.bits - 1));
61916191
6192 const bit_offset = pt.structPackedFieldBitOffset(loaded_struct, extra.field_index);
6192 const bit_offset = zcu.structPackedFieldBitOffset(loaded_struct, extra.field_index);
61936193
61946194 const field_int_signedness = if (inst_ty.isAbiInt(zcu))
61956195 inst_ty.intInfo(zcu).signedness
......@@ -8573,8 +8573,7 @@ const Vectorize = struct {
85738573 }
85748574};
85758575
8576fn lowersToArray(ty: Type, pt: Zcu.PerThread) bool {
8577 const zcu = pt.zcu;
8576fn lowersToArray(ty: Type, zcu: *Zcu) bool {
85788577 return switch (ty.zigTypeTag(zcu)) {
85798578 .array, .vector => return true,
85808579 else => return ty.isAbiInt(zcu) and toCIntBits(@as(u32, @intCast(ty.bitSize(zcu)))) == null,
src/codegen/llvm.zig+9-8
......@@ -20,6 +20,7 @@ const Package = @import("../Package.zig");
2020const Air = @import("../Air.zig");
2121const Value = @import("../Value.zig");
2222const Type = @import("../Type.zig");
23const codegen = @import("../codegen.zig");
2324const x86_64_abi = @import("../arch/x86_64/abi.zig");
2425const wasm_c_abi = @import("wasm/abi.zig");
2526const aarch64_c_abi = @import("aarch64/abi.zig");
......@@ -1131,7 +1132,7 @@ pub const Object = struct {
11311132 pt: Zcu.PerThread,
11321133 func_index: InternPool.Index,
11331134 air: *const Air,
1134 liveness: *const Air.Liveness,
1135 liveness: *const ?Air.Liveness,
11351136 ) !void {
11361137 const zcu = pt.zcu;
11371138 const comp = zcu.comp;
......@@ -1489,7 +1490,7 @@ pub const Object = struct {
14891490 var fg: FuncGen = .{
14901491 .gpa = gpa,
14911492 .air = air.*,
1492 .liveness = liveness.*,
1493 .liveness = liveness.*.?,
14931494 .ng = &ng,
14941495 .wip = wip,
14951496 .is_naked = fn_info.cc == .naked,
......@@ -4210,7 +4211,7 @@ pub const Object = struct {
42104211 .eu_payload => |eu_ptr| try o.lowerPtr(
42114212 pt,
42124213 eu_ptr,
4213 offset + @import("../codegen.zig").errUnionPayloadOffset(
4214 offset + codegen.errUnionPayloadOffset(
42144215 Value.fromInterned(eu_ptr).typeOf(zcu).childType(zcu),
42154216 zcu,
42164217 ),
......@@ -6050,10 +6051,10 @@ pub const FuncGen = struct {
60506051 const target_blocks = dispatch_info.case_blocks[0..target_blocks_len];
60516052
60526053 // Make sure to cast the index to a usize so it's not treated as negative!
6053 const table_index = try self.wip.cast(
6054 .zext,
6054 const table_index = try self.wip.conv(
6055 .unsigned,
60556056 try self.wip.bin(.@"sub nuw", cond, jmp_table.min.toValue(), ""),
6056 try o.lowerType(pt, Type.usize),
6057 try o.lowerType(pt, .usize),
60576058 "",
60586059 );
60596060 const target_ptr_ptr = try self.wip.gep(
......@@ -6969,7 +6970,7 @@ pub const FuncGen = struct {
69696970 .@"struct" => switch (struct_ty.containerLayout(zcu)) {
69706971 .@"packed" => {
69716972 const struct_type = zcu.typeToStruct(struct_ty).?;
6972 const bit_offset = pt.structPackedFieldBitOffset(struct_type, field_index);
6973 const bit_offset = zcu.structPackedFieldBitOffset(struct_type, field_index);
69736974 const containing_int = struct_llvm_val;
69746975 const shift_amt =
69756976 try o.builder.intValue(containing_int.typeOfWip(&self.wip), bit_offset);
......@@ -11364,7 +11365,7 @@ pub const FuncGen = struct {
1136411365
1136511366 // We have a pointer to a packed struct field that happens to be byte-aligned.
1136611367 // Offset our operand pointer by the correct number of bytes.
11367 const byte_offset = @divExact(pt.structPackedFieldBitOffset(struct_type, field_index) + struct_ptr_ty_info.packed_offset.bit_offset, 8);
11368 const byte_offset = @divExact(zcu.structPackedFieldBitOffset(struct_type, field_index) + struct_ptr_ty_info.packed_offset.bit_offset, 8);
1136811369 if (byte_offset == 0) return struct_ptr;
1136911370 const usize_ty = try o.lowerType(pt, Type.usize);
1137011371 const llvm_index = try o.builder.intValue(usize_ty, byte_offset);
src/codegen/spirv.zig+3-3
......@@ -251,11 +251,11 @@ pub const Object = struct {
251251 pt: Zcu.PerThread,
252252 func_index: InternPool.Index,
253253 air: *const Air,
254 liveness: *const Air.Liveness,
254 liveness: *const ?Air.Liveness,
255255 ) !void {
256256 const nav = pt.zcu.funcInfo(func_index).owner_nav;
257257 // TODO: Separate types for generating decls and functions?
258 try self.genNav(pt, nav, air.*, liveness.*, true);
258 try self.genNav(pt, nav, air.*, liveness.*.?, true);
259259 }
260260
261261 pub fn updateNav(
......@@ -5134,7 +5134,7 @@ const NavGen = struct {
51345134 .@"struct" => switch (object_ty.containerLayout(zcu)) {
51355135 .@"packed" => {
51365136 const struct_ty = zcu.typeToPackedStruct(object_ty).?;
5137 const bit_offset = pt.structPackedFieldBitOffset(struct_ty, field_index);
5137 const bit_offset = zcu.structPackedFieldBitOffset(struct_ty, field_index);
51385138 const bit_offset_id = try self.constInt(.u16, bit_offset);
51395139 const signedness = if (field_ty.isInt(zcu)) field_ty.intInfo(zcu).signedness else .unsigned;
51405140 const field_bit_size: u16 = @intCast(field_ty.bitSize(zcu));
src/dev.zig+27-14
......@@ -25,13 +25,13 @@ pub const Env = enum {
2525 /// - `zig build-* -fno-emit-bin`
2626 sema,
2727
28 /// - sema
29 /// - `zig build-* -fincremental -fno-llvm -fno-lld -target aarch64-linux --listen=-`
30 @"aarch64-linux",
31
2832 /// - `zig build-* -ofmt=c`
2933 cbe,
3034
31 /// - sema
32 /// - `zig build-* -fincremental -fno-llvm -fno-lld -target x86_64-linux --listen=-`
33 @"x86_64-linux",
34
3535 /// - sema
3636 /// - `zig build-* -fincremental -fno-llvm -fno-lld -target powerpc(64)(le)-linux --listen=-`
3737 @"powerpc-linux",
......@@ -48,6 +48,10 @@ pub const Env = enum {
4848 /// - `zig build-* -fno-llvm -fno-lld -target wasm32-* --listen=-`
4949 wasm,
5050
51 /// - sema
52 /// - `zig build-* -fincremental -fno-llvm -fno-lld -target x86_64-linux --listen=-`
53 @"x86_64-linux",
54
5155 pub inline fn supports(comptime dev_env: Env, comptime feature: Feature) bool {
5256 return switch (dev_env) {
5357 .full => true,
......@@ -153,23 +157,22 @@ pub const Env = enum {
153157 => true,
154158 else => Env.ast_gen.supports(feature),
155159 },
156 .cbe => switch (feature) {
157 .legalize,
158 .c_backend,
159 .c_linker,
160 => true,
161 else => Env.sema.supports(feature),
162 },
163 .@"x86_64-linux" => switch (feature) {
160 .@"aarch64-linux" => switch (feature) {
164161 .build_command,
165162 .stdio_listen,
166163 .incremental,
167 .legalize,
168 .x86_64_backend,
164 .aarch64_backend,
169165 .elf_linker,
170166 => true,
171167 else => Env.sema.supports(feature),
172168 },
169 .cbe => switch (feature) {
170 .legalize,
171 .c_backend,
172 .c_linker,
173 => true,
174 else => Env.sema.supports(feature),
175 },
173176 .@"powerpc-linux" => switch (feature) {
174177 .build_command,
175178 .stdio_listen,
......@@ -199,6 +202,16 @@ pub const Env = enum {
199202 => true,
200203 else => Env.sema.supports(feature),
201204 },
205 .@"x86_64-linux" => switch (feature) {
206 .build_command,
207 .stdio_listen,
208 .incremental,
209 .legalize,
210 .x86_64_backend,
211 .elf_linker,
212 => true,
213 else => Env.sema.supports(feature),
214 },
202215 };
203216 }
204217
src/fmt.zig+2-2
......@@ -348,10 +348,10 @@ fn fmtPathFile(
348348 try fmt.stdout_writer.interface.print("{s}\n", .{file_path});
349349 fmt.any_error = true;
350350 } 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 = &.{} });
352352 defer af.deinit();
353353
354 try af.file.writeAll(fmt.out_buffer.getWritten());
354 try af.file_writer.interface.writeAll(fmt.out_buffer.getWritten());
355355 try af.finish();
356356 try fmt.stdout_writer.interface.print("{s}\n", .{file_path});
357357 }
src/link.zig+1
......@@ -23,6 +23,7 @@ const dev = @import("dev.zig");
2323const target_util = @import("target.zig");
2424const codegen = @import("codegen.zig");
2525
26pub const aarch64 = @import("link/aarch64.zig");
2627pub const LdScript = @import("link/LdScript.zig");
2728pub const Queue = @import("link/Queue.zig");
2829
src/link/Coff.zig+25-51
......@@ -1335,9 +1335,13 @@ fn updateNavCode(
13351335
13361336 log.debug("updateNavCode {f} 0x{x}", .{ nav.fqn.fmt(ip), nav_index });
13371337
1338 const target = &zcu.navFileScope(nav_index).mod.?.resolved_target.result;
1339 const required_alignment = switch (pt.navAlignment(nav_index)) {
1340 .none => target_util.defaultFunctionAlignment(target),
1338 const mod = zcu.navFileScope(nav_index).mod.?;
1339 const target = &mod.resolved_target.result;
1340 const required_alignment = switch (nav.status.fully_resolved.alignment) {
1341 .none => switch (mod.optimize_mode) {
1342 .Debug, .ReleaseSafe, .ReleaseFast => target_util.defaultFunctionAlignment(target),
1343 .ReleaseSmall => target_util.minFunctionAlignment(target),
1344 },
13411345 else => |a| a.maxStrict(target_util.minFunctionAlignment(target)),
13421346 };
13431347
......@@ -2832,58 +2836,33 @@ pub const Relocation = struct {
28322836 };
28332837
28342838 fn resolveAarch64(reloc: Relocation, ctx: Context) void {
2839 const Instruction = aarch64_util.encoding.Instruction;
28352840 var buffer = ctx.code[reloc.offset..];
28362841 switch (reloc.type) {
28372842 .got_page, .import_page, .page => {
28382843 const source_page = @as(i32, @intCast(ctx.source_vaddr >> 12));
28392844 const target_page = @as(i32, @intCast(ctx.target_vaddr >> 12));
2840 const pages = @as(u21, @bitCast(@as(i21, @intCast(target_page - source_page))));
2841 var inst = aarch64_util.Instruction{
2842 .pc_relative_address = mem.bytesToValue(@FieldType(
2843 aarch64_util.Instruction,
2844 @tagName(aarch64_util.Instruction.pc_relative_address),
2845 ), buffer[0..4]),
2846 };
2847 inst.pc_relative_address.immhi = @as(u19, @truncate(pages >> 2));
2848 inst.pc_relative_address.immlo = @as(u2, @truncate(pages));
2849 mem.writeInt(u32, buffer[0..4], inst.toU32(), .little);
2845 const pages: i21 = @intCast(target_page - source_page);
2846 var inst: Instruction = .read(buffer[0..Instruction.size]);
2847 inst.data_processing_immediate.pc_relative_addressing.group.immhi = @intCast(pages >> 2);
2848 inst.data_processing_immediate.pc_relative_addressing.group.immlo = @truncate(@as(u21, @bitCast(pages)));
2849 inst.write(buffer[0..Instruction.size]);
28502850 },
28512851 .got_pageoff, .import_pageoff, .pageoff => {
28522852 assert(!reloc.pcrel);
28532853
2854 const narrowed = @as(u12, @truncate(@as(u64, @intCast(ctx.target_vaddr))));
2855 if (isArithmeticOp(buffer[0..4])) {
2856 var inst = aarch64_util.Instruction{
2857 .add_subtract_immediate = mem.bytesToValue(@FieldType(
2858 aarch64_util.Instruction,
2859 @tagName(aarch64_util.Instruction.add_subtract_immediate),
2860 ), buffer[0..4]),
2861 };
2862 inst.add_subtract_immediate.imm12 = narrowed;
2863 mem.writeInt(u32, buffer[0..4], inst.toU32(), .little);
2864 } else {
2865 var inst = aarch64_util.Instruction{
2866 .load_store_register = mem.bytesToValue(@FieldType(
2867 aarch64_util.Instruction,
2868 @tagName(aarch64_util.Instruction.load_store_register),
2869 ), buffer[0..4]),
2870 };
2871 const offset: u12 = blk: {
2872 if (inst.load_store_register.size == 0) {
2873 if (inst.load_store_register.v == 1) {
2874 // 128-bit SIMD is scaled by 16.
2875 break :blk @divExact(narrowed, 16);
2876 }
2877 // Otherwise, 8-bit SIMD or ldrb.
2878 break :blk narrowed;
2879 } else {
2880 const denom: u4 = math.powi(u4, 2, inst.load_store_register.size) catch unreachable;
2881 break :blk @divExact(narrowed, denom);
2882 }
2883 };
2884 inst.load_store_register.offset = offset;
2885 mem.writeInt(u32, buffer[0..4], inst.toU32(), .little);
2854 const narrowed: u12 = @truncate(@as(u64, @intCast(ctx.target_vaddr)));
2855 var inst: Instruction = .read(buffer[0..Instruction.size]);
2856 switch (inst.decode()) {
2857 else => unreachable,
2858 .data_processing_immediate => inst.data_processing_immediate.add_subtract_immediate.group.imm12 = narrowed,
2859 .load_store => |load_store| inst.load_store.register_unsigned_immediate.group.imm12 =
2860 switch (load_store.register_unsigned_immediate.decode()) {
2861 .integer => |integer| @shrExact(narrowed, @intFromEnum(integer.group.size)),
2862 .vector => |vector| @shrExact(narrowed, @intFromEnum(vector.group.opc1.decode(vector.group.size))),
2863 },
28862864 }
2865 inst.write(buffer[0..Instruction.size]);
28872866 },
28882867 .direct => {
28892868 assert(!reloc.pcrel);
......@@ -2934,11 +2913,6 @@ pub const Relocation = struct {
29342913 },
29352914 }
29362915 }
2937
2938 fn isArithmeticOp(inst: *const [4]u8) bool {
2939 const group_decode = @as(u5, @truncate(inst[3]));
2940 return ((group_decode >> 2) == 4);
2941 }
29422916};
29432917
29442918pub fn addRelocation(coff: *Coff, atom_index: Atom.Index, reloc: Relocation) !void {
......@@ -3112,7 +3086,7 @@ const Path = std.Build.Cache.Path;
31123086const Directory = std.Build.Cache.Directory;
31133087const Cache = std.Build.Cache;
31143088
3115const aarch64_util = @import("../arch/aarch64/bits.zig");
3089const aarch64_util = link.aarch64;
31163090const allocPrint = std.fmt.allocPrint;
31173091const codegen = @import("../codegen.zig");
31183092const link = @import("../link.zig");
src/link/Dwarf.zig+7-1
......@@ -2487,7 +2487,13 @@ fn initWipNavInner(
24872487 try wip_nav.strp(nav.fqn.toSlice(ip));
24882488 const ty: Type = nav_val.typeOf(zcu);
24892489 const addr: Loc = .{ .addr_reloc = sym_index };
2490 const loc: Loc = if (decl.is_threadlocal) .{ .form_tls_address = &addr } else addr;
2490 const loc: Loc = if (decl.is_threadlocal) loc: {
2491 const target = zcu.comp.root_mod.resolved_target.result;
2492 break :loc switch (target.cpu.arch) {
2493 .x86_64 => .{ .form_tls_address = &addr },
2494 else => .empty,
2495 };
2496 } else addr;
24912497 switch (decl.kind) {
24922498 .unnamed_test, .@"test", .decltest, .@"comptime" => unreachable,
24932499 .@"const" => {
src/link/Elf/Atom.zig+27-43
......@@ -1627,7 +1627,7 @@ const aarch64 = struct {
16271627 const S_ = th.targetAddress(target_index, elf_file);
16281628 break :blk math.cast(i28, S_ + A - P) orelse return error.Overflow;
16291629 };
1630 aarch64_util.writeBranchImm(disp, code);
1630 util.writeBranchImm(disp, code);
16311631 },
16321632
16331633 .PREL32 => {
......@@ -1640,15 +1640,18 @@ const aarch64 = struct {
16401640 mem.writeInt(u64, code_buffer[r_offset..][0..8], @bitCast(value), .little);
16411641 },
16421642
1643 .ADR_PREL_LO21 => {
1644 const value = math.cast(i21, S + A - P) orelse return error.Overflow;
1645 util.writeAdrInst(value, code);
1646 },
1647
16431648 .ADR_PREL_PG_HI21 => {
16441649 // TODO: check for relaxation of ADRP+ADD
1645 const pages = @as(u21, @bitCast(try aarch64_util.calcNumberOfPages(P, S + A)));
1646 aarch64_util.writeAdrpInst(pages, code);
1650 util.writeAdrInst(try util.calcNumberOfPages(P, S + A), code);
16471651 },
16481652
16491653 .ADR_GOT_PAGE => if (target.flags.has_got) {
1650 const pages = @as(u21, @bitCast(try aarch64_util.calcNumberOfPages(P, G + GOT + A)));
1651 aarch64_util.writeAdrpInst(pages, code);
1654 util.writeAdrInst(try util.calcNumberOfPages(P, G + GOT + A), code);
16521655 } else {
16531656 // TODO: relax
16541657 var err = try diags.addErrorWithNotes(1);
......@@ -1663,12 +1666,12 @@ const aarch64 = struct {
16631666 .LD64_GOT_LO12_NC => {
16641667 assert(target.flags.has_got);
16651668 const taddr = @as(u64, @intCast(G + GOT + A));
1666 aarch64_util.writeLoadStoreRegInst(@divExact(@as(u12, @truncate(taddr)), 8), code);
1669 util.writeLoadStoreRegInst(@divExact(@as(u12, @truncate(taddr)), 8), code);
16671670 },
16681671
16691672 .ADD_ABS_LO12_NC => {
16701673 const taddr = @as(u64, @intCast(S + A));
1671 aarch64_util.writeAddImmInst(@truncate(taddr), code);
1674 util.writeAddImmInst(@truncate(taddr), code);
16721675 },
16731676
16741677 .LDST8_ABS_LO12_NC,
......@@ -1687,57 +1690,54 @@ const aarch64 = struct {
16871690 .LDST128_ABS_LO12_NC => @divExact(@as(u12, @truncate(taddr)), 16),
16881691 else => unreachable,
16891692 };
1690 aarch64_util.writeLoadStoreRegInst(off, code);
1693 util.writeLoadStoreRegInst(off, code);
16911694 },
16921695
16931696 .TLSLE_ADD_TPREL_HI12 => {
16941697 const value = math.cast(i12, (S + A - TP) >> 12) orelse
16951698 return error.Overflow;
1696 aarch64_util.writeAddImmInst(@bitCast(value), code);
1699 util.writeAddImmInst(@bitCast(value), code);
16971700 },
16981701
16991702 .TLSLE_ADD_TPREL_LO12_NC => {
17001703 const value: i12 = @truncate(S + A - TP);
1701 aarch64_util.writeAddImmInst(@bitCast(value), code);
1704 util.writeAddImmInst(@bitCast(value), code);
17021705 },
17031706
17041707 .TLSIE_ADR_GOTTPREL_PAGE21 => {
17051708 const S_ = target.gotTpAddress(elf_file);
17061709 relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A });
1707 const pages: u21 = @bitCast(try aarch64_util.calcNumberOfPages(P, S_ + A));
1708 aarch64_util.writeAdrpInst(pages, code);
1710 util.writeAdrInst(try util.calcNumberOfPages(P, S_ + A), code);
17091711 },
17101712
17111713 .TLSIE_LD64_GOTTPREL_LO12_NC => {
17121714 const S_ = target.gotTpAddress(elf_file);
17131715 relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A });
17141716 const off: u12 = try math.divExact(u12, @truncate(@as(u64, @bitCast(S_ + A))), 8);
1715 aarch64_util.writeLoadStoreRegInst(off, code);
1717 util.writeLoadStoreRegInst(off, code);
17161718 },
17171719
17181720 .TLSGD_ADR_PAGE21 => {
17191721 const S_ = target.tlsGdAddress(elf_file);
17201722 relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A });
1721 const pages: u21 = @bitCast(try aarch64_util.calcNumberOfPages(P, S_ + A));
1722 aarch64_util.writeAdrpInst(pages, code);
1723 util.writeAdrInst(try util.calcNumberOfPages(P, S_ + A), code);
17231724 },
17241725
17251726 .TLSGD_ADD_LO12_NC => {
17261727 const S_ = target.tlsGdAddress(elf_file);
17271728 relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A });
17281729 const off: u12 = @truncate(@as(u64, @bitCast(S_ + A)));
1729 aarch64_util.writeAddImmInst(off, code);
1730 util.writeAddImmInst(off, code);
17301731 },
17311732
17321733 .TLSDESC_ADR_PAGE21 => {
17331734 if (target.flags.has_tlsdesc) {
17341735 const S_ = target.tlsDescAddress(elf_file);
17351736 relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A });
1736 const pages: u21 = @bitCast(try aarch64_util.calcNumberOfPages(P, S_ + A));
1737 aarch64_util.writeAdrpInst(pages, code);
1737 util.writeAdrInst(try util.calcNumberOfPages(P, S_ + A), code);
17381738 } else {
17391739 relocs_log.debug(" relaxing adrp => nop", .{});
1740 mem.writeInt(u32, code, Instruction.nop().toU32(), .little);
1740 util.encoding.Instruction.nop().write(code);
17411741 }
17421742 },
17431743
......@@ -1746,10 +1746,10 @@ const aarch64 = struct {
17461746 const S_ = target.tlsDescAddress(elf_file);
17471747 relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A });
17481748 const off: u12 = try math.divExact(u12, @truncate(@as(u64, @bitCast(S_ + A))), 8);
1749 aarch64_util.writeLoadStoreRegInst(off, code);
1749 util.writeLoadStoreRegInst(off, code);
17501750 } else {
17511751 relocs_log.debug(" relaxing ldr => nop", .{});
1752 mem.writeInt(u32, code, Instruction.nop().toU32(), .little);
1752 util.encoding.Instruction.nop().write(code);
17531753 }
17541754 },
17551755
......@@ -1758,32 +1758,18 @@ const aarch64 = struct {
17581758 const S_ = target.tlsDescAddress(elf_file);
17591759 relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A });
17601760 const off: u12 = @truncate(@as(u64, @bitCast(S_ + A)));
1761 aarch64_util.writeAddImmInst(off, code);
1761 util.writeAddImmInst(off, code);
17621762 } else {
1763 const old_inst: Instruction = .{
1764 .add_subtract_immediate = mem.bytesToValue(@FieldType(
1765 Instruction,
1766 @tagName(Instruction.add_subtract_immediate),
1767 ), code),
1768 };
1769 const rd: Register = @enumFromInt(old_inst.add_subtract_immediate.rd);
1770 relocs_log.debug(" relaxing add({s}) => movz(x0, {x})", .{ @tagName(rd), S + A - TP });
1763 relocs_log.debug(" relaxing add => movz(x0, {x})", .{S + A - TP});
17711764 const value: u16 = @bitCast(math.cast(i16, (S + A - TP) >> 16) orelse return error.Overflow);
1772 mem.writeInt(u32, code, Instruction.movz(.x0, value, 16).toU32(), .little);
1765 util.encoding.Instruction.movz(.x0, value, .{ .lsl = .@"16" }).write(code);
17731766 }
17741767 },
17751768
17761769 .TLSDESC_CALL => if (!target.flags.has_tlsdesc) {
1777 const old_inst: Instruction = .{
1778 .unconditional_branch_register = mem.bytesToValue(@FieldType(
1779 Instruction,
1780 @tagName(Instruction.unconditional_branch_register),
1781 ), code),
1782 };
1783 const rn: Register = @enumFromInt(old_inst.unconditional_branch_register.rn);
1784 relocs_log.debug(" relaxing br({s}) => movk(x0, {x})", .{ @tagName(rn), S + A - TP });
1770 relocs_log.debug(" relaxing br => movk(x0, {x})", .{S + A - TP});
17851771 const value: u16 = @bitCast(@as(i16, @truncate(S + A - TP)));
1786 mem.writeInt(u32, code, Instruction.movk(.x0, value, 0).toU32(), .little);
1772 util.encoding.Instruction.movk(.x0, value, .{}).write(code);
17871773 },
17881774
17891775 else => try atom.reportUnhandledRelocError(rel, elf_file),
......@@ -1819,9 +1805,7 @@ const aarch64 = struct {
18191805 }
18201806 }
18211807
1822 const aarch64_util = @import("../aarch64.zig");
1823 const Instruction = aarch64_util.Instruction;
1824 const Register = aarch64_util.Register;
1808 const util = @import("../aarch64.zig");
18251809};
18261810
18271811const riscv = struct {
src/link/Elf/Thunk.zig+9-6
......@@ -95,18 +95,21 @@ const aarch64 = struct {
9595 const sym = elf_file.symbol(ref).?;
9696 const saddr = thunk.address(elf_file) + @as(i64, @intCast(i * trampoline_size));
9797 const taddr = sym.address(.{}, elf_file);
98 const pages = try util.calcNumberOfPages(saddr, taddr);
99 try writer.writeInt(u32, Instruction.adrp(.x16, pages).toU32(), .little);
100 const off: u12 = @truncate(@as(u64, @bitCast(taddr)));
101 try writer.writeInt(u32, Instruction.add(.x16, .x16, off, false).toU32(), .little);
102 try writer.writeInt(u32, Instruction.br(.x16).toU32(), .little);
98 try writer.writeInt(u32, @bitCast(
99 util.encoding.Instruction.adrp(.x16, try util.calcNumberOfPages(saddr, taddr) << 12),
100 ), .little);
101 try writer.writeInt(u32, @bitCast(util.encoding.Instruction.add(
102 .x16,
103 .x16,
104 .{ .immediate = @truncate(@as(u64, @bitCast(taddr))) },
105 )), .little);
106 try writer.writeInt(u32, @bitCast(util.encoding.Instruction.br(.x16)), .little);
103107 }
104108 }
105109
106110 const trampoline_size = 3 * @sizeOf(u32);
107111
108112 const util = @import("../aarch64.zig");
109 const Instruction = util.Instruction;
110113};
111114
112115const assert = std.debug.assert;
src/link/Elf/ZigObject.zig+7-3
......@@ -1270,9 +1270,13 @@ fn updateNavCode(
12701270
12711271 log.debug("updateNavCode {f}({d})", .{ nav.fqn.fmt(ip), nav_index });
12721272
1273 const target = &zcu.navFileScope(nav_index).mod.?.resolved_target.result;
1274 const required_alignment = switch (pt.navAlignment(nav_index)) {
1275 .none => target_util.defaultFunctionAlignment(target),
1273 const mod = zcu.navFileScope(nav_index).mod.?;
1274 const target = &mod.resolved_target.result;
1275 const required_alignment = switch (nav.status.fully_resolved.alignment) {
1276 .none => switch (mod.optimize_mode) {
1277 .Debug, .ReleaseSafe, .ReleaseFast => target_util.defaultFunctionAlignment(target),
1278 .ReleaseSmall => target_util.minFunctionAlignment(target),
1279 },
12761280 else => |a| a.maxStrict(target_util.minFunctionAlignment(target)),
12771281 };
12781282
src/link/Elf/relocation.zig+18-6
......@@ -94,14 +94,18 @@ pub fn encode(comptime kind: Kind, cpu_arch: std.Target.Cpu.Arch) u32 {
9494pub const dwarf = struct {
9595 pub fn crossSectionRelocType(format: DW.Format, cpu_arch: std.Target.Cpu.Arch) u32 {
9696 return switch (cpu_arch) {
97 .x86_64 => @intFromEnum(switch (format) {
98 .@"32" => elf.R_X86_64.@"32",
97 .x86_64 => @intFromEnum(@as(elf.R_X86_64, switch (format) {
98 .@"32" => .@"32",
9999 .@"64" => .@"64",
100 }),
101 .riscv64 => @intFromEnum(switch (format) {
102 .@"32" => elf.R_RISCV.@"32",
100 })),
101 .aarch64 => @intFromEnum(@as(elf.R_AARCH64, switch (format) {
102 .@"32" => .ABS32,
103 .@"64" => .ABS64,
104 })),
105 .riscv64 => @intFromEnum(@as(elf.R_RISCV, switch (format) {
106 .@"32" => .@"32",
103107 .@"64" => .@"64",
104 }),
108 })),
105109 else => @panic("TODO unhandled cpu arch"),
106110 };
107111 }
......@@ -121,6 +125,14 @@ pub const dwarf = struct {
121125 },
122126 .debug_frame => .PC32,
123127 })),
128 .aarch64 => @intFromEnum(@as(elf.R_AARCH64, switch (source_section) {
129 else => switch (address_size) {
130 .@"32" => .ABS32,
131 .@"64" => .ABS64,
132 else => unreachable,
133 },
134 .debug_frame => .PREL32,
135 })),
124136 .riscv64 => @intFromEnum(@as(elf.R_RISCV, switch (source_section) {
125137 else => switch (address_size) {
126138 .@"32" => .@"32",
src/link/Elf/synthetic_sections.zig+30-45
......@@ -810,54 +810,43 @@ pub const PltSection = struct {
810810 const got_plt_addr: i64 = @intCast(shdrs[elf_file.section_indexes.got_plt.?].sh_addr);
811811 // TODO: relax if possible
812812 // .got.plt[2]
813 const pages = try aarch64_util.calcNumberOfPages(plt_addr + 4, got_plt_addr + 16);
814 const ldr_off = try math.divExact(u12, @truncate(@as(u64, @bitCast(got_plt_addr + 16))), 8);
813 const pages = try util.calcNumberOfPages(plt_addr + 4, got_plt_addr + 16);
814 const ldr_off: u12 = @truncate(@as(u64, @bitCast(got_plt_addr + 16)));
815815 const add_off: u12 = @truncate(@as(u64, @bitCast(got_plt_addr + 16)));
816816
817 const preamble = &[_]Instruction{
818 Instruction.stp(
819 .x16,
820 .x30,
821 Register.sp,
822 Instruction.LoadStorePairOffset.pre_index(-16),
823 ),
824 Instruction.adrp(.x16, pages),
825 Instruction.ldr(.x17, .x16, Instruction.LoadStoreOffset.imm(ldr_off)),
826 Instruction.add(.x16, .x16, add_off, false),
827 Instruction.br(.x17),
828 Instruction.nop(),
829 Instruction.nop(),
830 Instruction.nop(),
817 const preamble = [_]util.encoding.Instruction{
818 .stp(.x16, .x30, .{ .pre_index = .{ .base = .sp, .index = -16 } }),
819 .adrp(.x16, pages << 12),
820 .ldr(.x17, .{ .unsigned_offset = .{ .base = .x16, .offset = ldr_off } }),
821 .add(.x16, .x16, .{ .immediate = add_off }),
822 .br(.x17),
823 .nop(),
824 .nop(),
825 .nop(),
831826 };
832827 comptime assert(preamble.len == 8);
833 for (preamble) |inst| {
834 try writer.writeInt(u32, inst.toU32(), .little);
835 }
828 for (preamble) |inst| try writer.writeInt(util.encoding.Instruction.Backing, @bitCast(inst), .little);
836829 }
837830
838831 for (plt.symbols.items) |ref| {
839832 const sym = elf_file.symbol(ref).?;
840833 const target_addr = sym.gotPltAddress(elf_file);
841834 const source_addr = sym.pltAddress(elf_file);
842 const pages = try aarch64_util.calcNumberOfPages(source_addr, target_addr);
843 const ldr_off = try math.divExact(u12, @truncate(@as(u64, @bitCast(target_addr))), 8);
835 const pages = try util.calcNumberOfPages(source_addr, target_addr);
836 const ldr_off: u12 = @truncate(@as(u64, @bitCast(target_addr)));
844837 const add_off: u12 = @truncate(@as(u64, @bitCast(target_addr)));
845 const insts = &[_]Instruction{
846 Instruction.adrp(.x16, pages),
847 Instruction.ldr(.x17, .x16, Instruction.LoadStoreOffset.imm(ldr_off)),
848 Instruction.add(.x16, .x16, add_off, false),
849 Instruction.br(.x17),
838 const insts = [_]util.encoding.Instruction{
839 .adrp(.x16, pages << 12),
840 .ldr(.x17, .{ .unsigned_offset = .{ .base = .x16, .offset = ldr_off } }),
841 .add(.x16, .x16, .{ .immediate = add_off }),
842 .br(.x17),
850843 };
851844 comptime assert(insts.len == 4);
852 for (insts) |inst| {
853 try writer.writeInt(u32, inst.toU32(), .little);
854 }
845 for (insts) |inst| try writer.writeInt(util.encoding.Instruction.Backing, @bitCast(inst), .little);
855846 }
856847 }
857848
858 const aarch64_util = @import("../aarch64.zig");
859 const Instruction = aarch64_util.Instruction;
860 const Register = aarch64_util.Register;
849 const util = @import("../aarch64.zig");
861850 };
862851};
863852
......@@ -979,24 +968,20 @@ pub const PltGotSection = struct {
979968 const sym = elf_file.symbol(ref).?;
980969 const target_addr = sym.gotAddress(elf_file);
981970 const source_addr = sym.pltGotAddress(elf_file);
982 const pages = try aarch64_util.calcNumberOfPages(source_addr, target_addr);
983 const off = try math.divExact(u12, @truncate(@as(u64, @bitCast(target_addr))), 8);
984 const insts = &[_]Instruction{
985 Instruction.adrp(.x16, pages),
986 Instruction.ldr(.x17, .x16, Instruction.LoadStoreOffset.imm(off)),
987 Instruction.br(.x17),
988 Instruction.nop(),
971 const pages = try util.calcNumberOfPages(source_addr, target_addr);
972 const off: u12 = @truncate(@as(u64, @bitCast(target_addr)));
973 const insts = [_]util.encoding.Instruction{
974 .adrp(.x16, pages << 12),
975 .ldr(.x17, .{ .unsigned_offset = .{ .base = .x16, .offset = off } }),
976 .br(.x17),
977 .nop(),
989978 };
990979 comptime assert(insts.len == 4);
991 for (insts) |inst| {
992 try writer.writeInt(u32, inst.toU32(), .little);
993 }
980 for (insts) |inst| try writer.writeInt(util.encoding.Instruction.Backing, @bitCast(inst), .little);
994981 }
995982 }
996983
997 const aarch64_util = @import("../aarch64.zig");
998 const Instruction = aarch64_util.Instruction;
999 const Register = aarch64_util.Register;
984 const util = @import("../aarch64.zig");
1000985 };
1001986};
1002987
src/link/MachO.zig+2-2
......@@ -328,6 +328,7 @@ pub fn deinit(self: *MachO) void {
328328 self.unwind_info.deinit(gpa);
329329 self.data_in_code.deinit(gpa);
330330
331 for (self.thunks.items) |*thunk| thunk.deinit(gpa);
331332 self.thunks.deinit(gpa);
332333}
333334
......@@ -612,7 +613,6 @@ pub fn flush(
612613 };
613614 const emit = self.base.emit;
614615 invalidateKernelCache(emit.root_dir.handle, emit.sub_path) catch |err| switch (err) {
615 error.OutOfMemory => return error.OutOfMemory,
616616 else => |e| return diags.fail("failed to invalidate kernel cache: {s}", .{@errorName(e)}),
617617 };
618618 }
......@@ -5374,7 +5374,7 @@ const mem = std.mem;
53745374const meta = std.meta;
53755375const Writer = std.io.Writer;
53765376
5377const aarch64 = @import("../arch/aarch64/bits.zig");
5377const aarch64 = codegen.aarch64.encoding;
53785378const bind = @import("MachO/dyld_info/bind.zig");
53795379const calcUuid = @import("MachO/uuid.zig").calcUuid;
53805380const codegen = @import("../codegen.zig");
src/link/MachO/Atom.zig+29-71
......@@ -780,8 +780,7 @@ fn resolveRelocInner(
780780 };
781781 break :target math.cast(u64, target) orelse return error.Overflow;
782782 };
783 const pages = @as(u21, @bitCast(try aarch64.calcNumberOfPages(@intCast(source), @intCast(target))));
784 aarch64.writeAdrpInst(pages, code[rel_offset..][0..4]);
783 aarch64.writeAdrInst(try aarch64.calcNumberOfPages(@intCast(source), @intCast(target)), code[rel_offset..][0..aarch64.encoding.Instruction.size]);
785784 },
786785
787786 .pageoff => {
......@@ -789,26 +788,18 @@ fn resolveRelocInner(
789788 assert(rel.meta.length == 2);
790789 assert(!rel.meta.pcrel);
791790 const target = math.cast(u64, S + A) orelse return error.Overflow;
792 const inst_code = code[rel_offset..][0..4];
793 if (aarch64.isArithmeticOp(inst_code)) {
794 aarch64.writeAddImmInst(@truncate(target), inst_code);
795 } else {
796 var inst = aarch64.Instruction{
797 .load_store_register = mem.bytesToValue(@FieldType(
798 aarch64.Instruction,
799 @tagName(aarch64.Instruction.load_store_register),
800 ), inst_code),
801 };
802 inst.load_store_register.offset = switch (inst.load_store_register.size) {
803 0 => if (inst.load_store_register.v == 1)
804 try divExact(self, rel, @truncate(target), 16, macho_file)
805 else
806 @truncate(target),
807 1 => try divExact(self, rel, @truncate(target), 2, macho_file),
808 2 => try divExact(self, rel, @truncate(target), 4, macho_file),
809 3 => try divExact(self, rel, @truncate(target), 8, macho_file),
810 };
811 try writer.writeInt(u32, inst.toU32(), .little);
791 const inst_code = code[rel_offset..][0..aarch64.encoding.Instruction.size];
792 var inst: aarch64.encoding.Instruction = .read(inst_code);
793 switch (inst.decode()) {
794 else => unreachable,
795 .data_processing_immediate => aarch64.writeAddImmInst(@truncate(target), inst_code),
796 .load_store => |load_store| {
797 inst.load_store.register_unsigned_immediate.group.imm12 = switch (load_store.register_unsigned_immediate.decode()) {
798 .integer => |integer| try divExact(self, rel, @truncate(target), @as(u4, 1) << @intFromEnum(integer.group.size), macho_file),
799 .vector => |vector| try divExact(self, rel, @truncate(target), @as(u5, 1) << @intFromEnum(vector.group.opc1.decode(vector.group.size)), macho_file),
800 };
801 try writer.writeInt(u32, @bitCast(inst), .little);
802 },
812803 }
813804 },
814805
......@@ -834,59 +825,26 @@ fn resolveRelocInner(
834825 break :target math.cast(u64, target) orelse return error.Overflow;
835826 };
836827
837 const RegInfo = struct {
838 rd: u5,
839 rn: u5,
840 size: u2,
841 };
842
843828 const inst_code = code[rel_offset..][0..4];
844 const reg_info: RegInfo = blk: {
845 if (aarch64.isArithmeticOp(inst_code)) {
846 const inst = mem.bytesToValue(@FieldType(
847 aarch64.Instruction,
848 @tagName(aarch64.Instruction.add_subtract_immediate),
849 ), inst_code);
850 break :blk .{
851 .rd = inst.rd,
852 .rn = inst.rn,
853 .size = inst.sf,
854 };
855 } else {
856 const inst = mem.bytesToValue(@FieldType(
857 aarch64.Instruction,
858 @tagName(aarch64.Instruction.load_store_register),
859 ), inst_code);
860 break :blk .{
861 .rd = inst.rt,
862 .rn = inst.rn,
863 .size = inst.size,
864 };
865 }
866 };
867
868 var inst = if (sym.getSectionFlags().tlv_ptr) aarch64.Instruction{
869 .load_store_register = .{
870 .rt = reg_info.rd,
871 .rn = reg_info.rn,
872 .offset = try divExact(self, rel, @truncate(target), 8, macho_file),
873 .opc = 0b01,
874 .op1 = 0b01,
875 .v = 0,
876 .size = reg_info.size,
829 const rd, const rn = switch (aarch64.encoding.Instruction.read(inst_code).decode()) {
830 else => unreachable,
831 .data_processing_immediate => |decoded| .{
832 decoded.add_subtract_immediate.group.Rd.decodeInteger(.doubleword, .{ .sp = true }),
833 decoded.add_subtract_immediate.group.Rn.decodeInteger(.doubleword, .{ .sp = true }),
877834 },
878 } else aarch64.Instruction{
879 .add_subtract_immediate = .{
880 .rd = reg_info.rd,
881 .rn = reg_info.rn,
882 .imm12 = @truncate(target),
883 .sh = 0,
884 .s = 0,
885 .op = 0,
886 .sf = @as(u1, @truncate(reg_info.size)),
835 .load_store => |decoded| .{
836 decoded.register_unsigned_immediate.integer.group.Rt.decodeInteger(.doubleword, .{}),
837 decoded.register_unsigned_immediate.group.Rn.decodeInteger(.doubleword, .{ .sp = true }),
887838 },
888839 };
889 try writer.writeInt(u32, inst.toU32(), .little);
840
841 try writer.writeInt(u32, @bitCast(@as(
842 aarch64.encoding.Instruction,
843 if (sym.getSectionFlags().tlv_ptr) .ldr(rd, .{ .unsigned_offset = .{
844 .base = rn,
845 .offset = try divExact(self, rel, @truncate(target), 8, macho_file) * 8,
846 } }) else .add(rd, rn, .{ .immediate = @truncate(target) }),
847 )), .little);
890848 },
891849 }
892850}
src/link/MachO/Thunk.zig+6-4
......@@ -21,15 +21,17 @@ pub fn getTargetAddress(thunk: Thunk, ref: MachO.Ref, macho_file: *MachO) u64 {
2121}
2222
2323pub fn write(thunk: Thunk, macho_file: *MachO, writer: anytype) !void {
24 const Instruction = aarch64.encoding.Instruction;
2425 for (thunk.symbols.keys(), 0..) |ref, i| {
2526 const sym = ref.getSymbol(macho_file).?;
2627 const saddr = thunk.getAddress(macho_file) + i * trampoline_size;
2728 const taddr = sym.getAddress(.{}, macho_file);
2829 const pages = try aarch64.calcNumberOfPages(@intCast(saddr), @intCast(taddr));
29 try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little);
30 const off: u12 = @truncate(taddr);
31 try writer.writeInt(u32, aarch64.Instruction.add(.x16, .x16, off, false).toU32(), .little);
32 try writer.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little);
30 try writer.writeInt(u32, @bitCast(Instruction.adrp(.x16, pages << 12)), .little);
31 try writer.writeInt(u32, @bitCast(
32 Instruction.add(.x16, .x16, .{ .immediate = @truncate(taddr) }),
33 ), .little);
34 try writer.writeInt(u32, @bitCast(Instruction.br(.x16)), .little);
3335 }
3436}
3537
src/link/MachO/ZigObject.zig+7-3
......@@ -945,9 +945,13 @@ fn updateNavCode(
945945
946946 log.debug("updateNavCode {f} 0x{x}", .{ nav.fqn.fmt(ip), nav_index });
947947
948 const target = &zcu.navFileScope(nav_index).mod.?.resolved_target.result;
949 const required_alignment = switch (pt.navAlignment(nav_index)) {
950 .none => target_util.defaultFunctionAlignment(target),
948 const mod = zcu.navFileScope(nav_index).mod.?;
949 const target = &mod.resolved_target.result;
950 const required_alignment = switch (nav.status.fully_resolved.alignment) {
951 .none => switch (mod.optimize_mode) {
952 .Debug, .ReleaseSafe, .ReleaseFast => target_util.defaultFunctionAlignment(target),
953 .ReleaseSmall => target_util.minFunctionAlignment(target),
954 },
951955 else => |a| a.maxStrict(target_util.minFunctionAlignment(target)),
952956 };
953957
src/link/MachO/synthetic.zig+43-52
......@@ -105,16 +105,15 @@ pub const StubsSection = struct {
105105 try writer.writeInt(i32, @intCast(target - source - 2 - 4), .little);
106106 },
107107 .aarch64 => {
108 const Instruction = aarch64.encoding.Instruction;
108109 // TODO relax if possible
109110 const pages = try aarch64.calcNumberOfPages(@intCast(source), @intCast(target));
110 try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little);
111 const off = try math.divExact(u12, @truncate(target), 8);
112 try writer.writeInt(
113 u32,
114 aarch64.Instruction.ldr(.x16, .x16, aarch64.Instruction.LoadStoreOffset.imm(off)).toU32(),
115 .little,
116 );
117 try writer.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little);
111 try writer.writeInt(u32, @bitCast(Instruction.adrp(.x16, pages << 12)), .little);
112 try writer.writeInt(u32, @bitCast(Instruction.ldr(
113 .x16,
114 .{ .unsigned_offset = .{ .base = .x16, .offset = @as(u12, @truncate(target)) } },
115 )), .little);
116 try writer.writeInt(u32, @bitCast(Instruction.br(.x16)), .little);
118117 },
119118 else => unreachable,
120119 }
......@@ -201,18 +200,16 @@ pub const StubsHelperSection = struct {
201200 try writer.writeInt(i32, @intCast(target - source - 6 - 4), .little);
202201 },
203202 .aarch64 => {
204 const literal = blk: {
205 const div_res = try std.math.divExact(u64, entry_size - @sizeOf(u32), 4);
206 break :blk std.math.cast(u18, div_res) orelse return error.Overflow;
207 };
208 try writer.writeInt(u32, aarch64.Instruction.ldrLiteral(
209 .w16,
210 literal,
211 ).toU32(), .little);
203 const Instruction = aarch64.encoding.Instruction;
204 if (entry_size % Instruction.size != 0) return error.UnexpectedRemainder;
205 try writer.writeInt(u32, @bitCast(
206 Instruction.ldr(.w16, .{ .literal = std.math.cast(i21, entry_size - Instruction.size) orelse
207 return error.Overflow }),
208 ), .little);
212209 const disp = math.cast(i28, @as(i64, @intCast(target)) - @as(i64, @intCast(source + 4))) orelse
213210 return error.Overflow;
214 try writer.writeInt(u32, aarch64.Instruction.b(disp).toU32(), .little);
215 try writer.writeAll(&.{ 0x0, 0x0, 0x0, 0x0 });
211 try writer.writeInt(u32, @bitCast(Instruction.b(disp)), .little);
212 try writer.writeInt(u32, @bitCast(Instruction.udf(0x0)), .little);
216213 },
217214 else => unreachable,
218215 }
......@@ -242,31 +239,28 @@ pub const StubsHelperSection = struct {
242239 try writer.writeByte(0x90);
243240 },
244241 .aarch64 => {
242 const Instruction = aarch64.encoding.Instruction;
245243 {
246244 // TODO relax if possible
247245 const pages = try aarch64.calcNumberOfPages(@intCast(sect.addr), @intCast(dyld_private_addr));
248 try writer.writeInt(u32, aarch64.Instruction.adrp(.x17, pages).toU32(), .little);
249 const off: u12 = @truncate(dyld_private_addr);
250 try writer.writeInt(u32, aarch64.Instruction.add(.x17, .x17, off, false).toU32(), .little);
246 try writer.writeInt(Instruction.Backing, @bitCast(Instruction.adrp(.x17, pages << 12)), .little);
247 try writer.writeInt(Instruction.Backing, @bitCast(
248 Instruction.add(.x17, .x17, .{ .immediate = @as(u12, @truncate(dyld_private_addr)) }),
249 ), .little);
251250 }
252 try writer.writeInt(u32, aarch64.Instruction.stp(
253 .x16,
254 .x17,
255 aarch64.Register.sp,
256 aarch64.Instruction.LoadStorePairOffset.pre_index(-16),
257 ).toU32(), .little);
251 try writer.writeInt(Instruction.Backing, @bitCast(
252 Instruction.stp(.x16, .x17, .{ .pre_index = .{ .base = .sp, .index = -16 } }),
253 ), .little);
258254 {
259255 // TODO relax if possible
260256 const pages = try aarch64.calcNumberOfPages(@intCast(sect.addr + 12), @intCast(dyld_stub_binder_addr));
261 try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little);
262 const off = try math.divExact(u12, @truncate(dyld_stub_binder_addr), 8);
263 try writer.writeInt(u32, aarch64.Instruction.ldr(
264 .x16,
257 try writer.writeInt(Instruction.Backing, @bitCast(Instruction.adrp(.x16, pages << 12)), .little);
258 try writer.writeInt(Instruction.Backing, @bitCast(Instruction.ldr(
265259 .x16,
266 aarch64.Instruction.LoadStoreOffset.imm(off),
267 ).toU32(), .little);
260 .{ .unsigned_offset = .{ .base = .x16, .offset = @as(u12, @truncate(dyld_stub_binder_addr)) } },
261 )), .little);
268262 }
269 try writer.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little);
263 try writer.writeInt(Instruction.Backing, @bitCast(Instruction.br(.x16)), .little);
270264 },
271265 else => unreachable,
272266 }
......@@ -426,35 +420,32 @@ pub const ObjcStubsSection = struct {
426420 }
427421 },
428422 .aarch64 => {
423 const Instruction = aarch64.encoding.Instruction;
429424 {
430425 const target = sym.getObjcSelrefsAddress(macho_file);
431426 const source = addr;
432427 const pages = try aarch64.calcNumberOfPages(@intCast(source), @intCast(target));
433 try writer.writeInt(u32, aarch64.Instruction.adrp(.x1, pages).toU32(), .little);
434 const off = try math.divExact(u12, @truncate(target), 8);
435 try writer.writeInt(
436 u32,
437 aarch64.Instruction.ldr(.x1, .x1, aarch64.Instruction.LoadStoreOffset.imm(off)).toU32(),
438 .little,
439 );
428 try writer.writeInt(u32, @bitCast(Instruction.adrp(.x1, pages << 12)), .little);
429 try writer.writeInt(u32, @bitCast(Instruction.ldr(
430 .x1,
431 .{ .unsigned_offset = .{ .base = .x1, .offset = @as(u12, @truncate(target)) } },
432 )), .little);
440433 }
441434 {
442435 const target_sym = obj.getObjcMsgSendRef(macho_file).?.getSymbol(macho_file).?;
443436 const target = target_sym.getGotAddress(macho_file);
444437 const source = addr + 2 * @sizeOf(u32);
445438 const pages = try aarch64.calcNumberOfPages(@intCast(source), @intCast(target));
446 try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little);
447 const off = try math.divExact(u12, @truncate(target), 8);
448 try writer.writeInt(
449 u32,
450 aarch64.Instruction.ldr(.x16, .x16, aarch64.Instruction.LoadStoreOffset.imm(off)).toU32(),
451 .little,
452 );
439 try writer.writeInt(u32, @bitCast(Instruction.adrp(.x16, pages << 12)), .little);
440 try writer.writeInt(u32, @bitCast(Instruction.ldr(
441 .x16,
442 .{ .unsigned_offset = .{ .base = .x16, .offset = @as(u12, @truncate(target)) } },
443 )), .little);
453444 }
454 try writer.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little);
455 try writer.writeInt(u32, aarch64.Instruction.brk(1).toU32(), .little);
456 try writer.writeInt(u32, aarch64.Instruction.brk(1).toU32(), .little);
457 try writer.writeInt(u32, aarch64.Instruction.brk(1).toU32(), .little);
445 try writer.writeInt(u32, @bitCast(Instruction.br(.x16)), .little);
446 try writer.writeInt(u32, @bitCast(Instruction.brk(0x1)), .little);
447 try writer.writeInt(u32, @bitCast(Instruction.brk(0x1)), .little);
448 try writer.writeInt(u32, @bitCast(Instruction.brk(0x1)), .little);
458449 },
459450 else => unreachable,
460451 }
src/link/aarch64.zig+17-47
......@@ -1,66 +1,36 @@
1pub inline fn isArithmeticOp(inst: *const [4]u8) bool {
2 const group_decode = @as(u5, @truncate(inst[3]));
3 return ((group_decode >> 2) == 4);
4}
1pub const encoding = @import("../codegen.zig").aarch64.encoding;
52
63pub fn writeAddImmInst(value: u12, code: *[4]u8) void {
7 var inst = Instruction{
8 .add_subtract_immediate = mem.bytesToValue(@FieldType(
9 Instruction,
10 @tagName(Instruction.add_subtract_immediate),
11 ), code),
12 };
13 inst.add_subtract_immediate.imm12 = value;
14 mem.writeInt(u32, code, inst.toU32(), .little);
4 var inst: encoding.Instruction = .read(code);
5 inst.data_processing_immediate.add_subtract_immediate.group.imm12 = value;
6 inst.write(code);
157}
168
179pub fn writeLoadStoreRegInst(value: u12, code: *[4]u8) void {
18 var inst: Instruction = .{
19 .load_store_register = mem.bytesToValue(@FieldType(
20 Instruction,
21 @tagName(Instruction.load_store_register),
22 ), code),
23 };
24 inst.load_store_register.offset = value;
25 mem.writeInt(u32, code, inst.toU32(), .little);
10 var inst: encoding.Instruction = .read(code);
11 inst.load_store.register_unsigned_immediate.group.imm12 = value;
12 inst.write(code);
2613}
2714
28pub fn calcNumberOfPages(saddr: i64, taddr: i64) error{Overflow}!i21 {
29 const spage = math.cast(i32, saddr >> 12) orelse return error.Overflow;
30 const tpage = math.cast(i32, taddr >> 12) orelse return error.Overflow;
31 const pages = math.cast(i21, tpage - spage) orelse return error.Overflow;
32 return pages;
15pub fn calcNumberOfPages(saddr: i64, taddr: i64) error{Overflow}!i33 {
16 return math.cast(i21, (taddr >> 12) - (saddr >> 12)) orelse error.Overflow;
3317}
3418
35pub fn writeAdrpInst(pages: u21, code: *[4]u8) void {
36 var inst = Instruction{
37 .pc_relative_address = mem.bytesToValue(@FieldType(
38 Instruction,
39 @tagName(Instruction.pc_relative_address),
40 ), code),
41 };
42 inst.pc_relative_address.immhi = @as(u19, @truncate(pages >> 2));
43 inst.pc_relative_address.immlo = @as(u2, @truncate(pages));
44 mem.writeInt(u32, code, inst.toU32(), .little);
19pub fn writeAdrInst(imm: i33, code: *[4]u8) void {
20 var inst: encoding.Instruction = .read(code);
21 inst.data_processing_immediate.pc_relative_addressing.group.immhi = @intCast(imm >> 2);
22 inst.data_processing_immediate.pc_relative_addressing.group.immlo = @bitCast(@as(i2, @truncate(imm)));
23 inst.write(code);
4524}
4625
4726pub fn writeBranchImm(disp: i28, code: *[4]u8) void {
48 var inst = Instruction{
49 .unconditional_branch_immediate = mem.bytesToValue(@FieldType(
50 Instruction,
51 @tagName(Instruction.unconditional_branch_immediate),
52 ), code),
53 };
54 inst.unconditional_branch_immediate.imm26 = @as(u26, @truncate(@as(u28, @bitCast(disp >> 2))));
55 mem.writeInt(u32, code, inst.toU32(), .little);
27 var inst: encoding.Instruction = .read(code);
28 inst.branch_exception_generating_system.unconditional_branch_immediate.group.imm26 = @intCast(@shrExact(disp, 2));
29 inst.write(code);
5630}
5731
5832const assert = std.debug.assert;
59const bits = @import("../arch/aarch64/bits.zig");
6033const builtin = @import("builtin");
6134const math = std.math;
6235const mem = std.mem;
6336const std = @import("std");
64
65pub const Instruction = bits.Instruction;
66pub const Register = bits.Register;
src/main.zig+96-55
......@@ -37,6 +37,7 @@ const dev = @import("dev.zig");
3737
3838test {
3939 _ = Package;
40 _ = @import("codegen.zig");
4041}
4142
4243const thread_stack_size = 60 << 20;
......@@ -4624,7 +4625,9 @@ fn cmdTranslateC(
46244625 fatal("unable to open cached translated zig file '{s}{s}{s}': {s}", .{ path, fs.path.sep_str, out_zig_path, @errorName(err) });
46254626 };
46264627 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);
46284631 return cleanExit();
46294632 }
46304633}
......@@ -4645,14 +4648,14 @@ const usage_init =
46454648fn cmdInit(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
46464649 dev.check(.init_command);
46474650
4648 var strip = false;
4651 var template: enum { example, minimal } = .example;
46494652 {
46504653 var i: usize = 0;
46514654 while (i < args.len) : (i += 1) {
46524655 const arg = args[i];
46534656 if (mem.startsWith(u8, arg, "-")) {
4654 if (mem.eql(u8, arg, "-s") or mem.eql(u8, arg, "--strip")) {
4655 strip = true;
4657 if (mem.eql(u8, arg, "-m") or mem.eql(u8, arg, "--minimal")) {
4658 template = .minimal;
46564659 } else if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) {
46574660 try fs.File.stdout().writeAll(usage_init);
46584661 return cleanExit();
......@@ -4665,40 +4668,79 @@ fn cmdInit(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
46654668 }
46664669 }
46674670
4668 var templates = findTemplates(gpa, arena, strip);
4669 defer templates.deinit();
4670
46714671 const cwd_path = try introspect.getResolvedCwd(arena);
46724672 const cwd_basename = fs.path.basename(cwd_path);
46734673 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
46844675 const fingerprint: Package.Fingerprint = .generate(sanitized_root_name);
46854676
4686 for (template_paths) |template_path| {
4687 if (templates.write(arena, fs.cwd(), sanitized_root_name, template_path, fingerprint)) |_| {
4688 std.log.info("created {s}", .{template_path});
4689 ok_count += 1;
4690 } else |err| switch (err) {
4691 error.PathAlreadyExists => std.log.info("preserving already existing file: {s}", .{
4692 template_path,
4693 }),
4694 else => std.log.err("unable to write {s}: {s}\n", .{ template_path, @errorName(err) }),
4695 }
4696 }
4677 switch (template) {
4678 .example => {
4679 var templates = findTemplates(gpa, arena);
4680 defer templates.deinit();
4681
4682 const s = fs.path.sep_str;
4683 const template_paths = [_][]const u8{
4684 Package.build_zig_basename,
4685 Package.Manifest.basename,
4686 "src" ++ s ++ "main.zig",
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) {
4699 std.log.info("see `zig build --help` for a menu of options", .{});
4703 if (ok_count == template_paths.len) {
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 },
47004743 }
4701 return cleanExit();
47024744}
47034745
47044746fn sanitizeExampleName(arena: Allocator, bytes: []const u8) error{OutOfMemory}![]const u8 {
......@@ -7226,13 +7268,20 @@ fn loadManifest(
72267268 0,
72277269 ) catch |err| switch (err) {
72287270 error.FileNotFound => {
7229 const fingerprint: Package.Fingerprint = .generate(options.root_name);
7230 var templates = findTemplates(gpa, arena, true);
7231 defer templates.deinit();
7232 templates.write(arena, options.dir, options.root_name, Package.Manifest.basename, fingerprint) catch |e| {
7233 fatal("unable to write {s}: {s}", .{
7234 Package.Manifest.basename, @errorName(e),
7235 });
7271 writeSimpleTemplateFile(Package.Manifest.basename,
7272 \\.{{
7273 \\ .name = .{s},
7274 \\ .version = "{s}",
7275 \\ .paths = .{{""}},
7276 \\ .fingerprint = 0x{x},
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) });
72367285 };
72377286 continue;
72387287 },
......@@ -7273,7 +7322,6 @@ const Templates = struct {
72737322 zig_lib_directory: Cache.Directory,
72747323 dir: fs.Dir,
72757324 buffer: std.ArrayList(u8),
7276 strip: bool,
72777325
72787326 fn deinit(templates: *Templates) void {
72797327 templates.zig_lib_directory.handle.close();
......@@ -7302,23 +7350,9 @@ const Templates = struct {
73027350 };
73037351 templates.buffer.clearRetainingCapacity();
73047352 try templates.buffer.ensureUnusedCapacity(contents.len);
7305 var new_line = templates.strip;
73067353 var i: usize = 0;
73077354 while (i < contents.len) {
7308 if (new_line) {
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] == '.') {
7355 if (contents[i] == '_' or contents[i] == '.') {
73227356 // Both '_' and '.' are allowed because depending on the context
73237357 // one prefix will be valid, while the other might not.
73247358 if (std.mem.startsWith(u8, contents[i + 1 ..], "NAME")) {
......@@ -7347,8 +7381,16 @@ const Templates = struct {
73477381 });
73487382 }
73497383};
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 {
73527394 const cwd_path = introspect.getResolvedCwd(arena) catch |err| {
73537395 fatal("unable to get cwd: {s}", .{@errorName(err)});
73547396 };
......@@ -7372,7 +7414,6 @@ fn findTemplates(gpa: Allocator, arena: Allocator, strip: bool) Templates {
73727414 .zig_lib_directory = zig_lib_directory,
73737415 .dir = template_dir,
73747416 .buffer = std.ArrayList(u8).init(gpa),
7375 .strip = strip,
73767417 };
73777418}
73787419
src/target.zig+24-6
......@@ -248,9 +248,13 @@ pub fn selfHostedBackendIsAsRobustAsLlvm(target: *const std.Target) bool {
248248 return false;
249249}
250250
251pub fn supportsStackProbing(target: *const std.Target) bool {
252 return target.os.tag != .windows and target.os.tag != .uefi and
253 (target.cpu.arch == .x86 or target.cpu.arch == .x86_64);
251pub fn supportsStackProbing(target: *const std.Target, backend: std.builtin.CompilerBackend) bool {
252 return switch (backend) {
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 };
254258}
255259
256260pub 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
359363 else => {},
360364 }
361365 return switch (zigBackend(target, use_llvm)) {
366 .stage2_aarch64 => true,
362367 .stage2_llvm => true,
363368 .stage2_x86_64 => switch (target.ofmt) {
364369 .elf, .macho => true,
......@@ -368,13 +373,22 @@ pub fn canBuildLibCompilerRt(target: *const std.Target, use_llvm: bool, have_llv
368373 };
369374}
370375
371pub fn canBuildLibUbsanRt(target: *const std.Target) bool {
376pub fn canBuildLibUbsanRt(target: *const std.Target, use_llvm: bool, have_llvm: bool) bool {
372377 switch (target.cpu.arch) {
373378 .spirv32, .spirv64 => return false,
374379 // Remove this once https://github.com/ziglang/zig/issues/23715 is fixed
375380 .nvptx, .nvptx64 => return false,
376 else => return true,
381 else => {},
377382 }
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 };
378392}
379393
380394pub fn hasRedZone(target: *const std.Target) bool {
......@@ -405,6 +419,8 @@ pub fn libcFullLinkFlags(target: *const std.Target) []const []const u8 {
405419 .android, .androideabi, .ohos, .ohoseabi => &.{ "-lm", "-lc", "-ldl" },
406420 else => &.{ "-lm", "-lpthread", "-lc", "-ldl", "-lrt", "-lutil" },
407421 },
422 // On SerenityOS libc includes libm, libpthread, libdl, and libssp.
423 .serenity => &.{"-lc"},
408424 else => &.{},
409425 };
410426 return result;
......@@ -767,6 +783,7 @@ pub fn supportsTailCall(target: *const std.Target, backend: std.builtin.Compiler
767783
768784pub fn supportsThreads(target: *const std.Target, backend: std.builtin.CompilerBackend) bool {
769785 return switch (backend) {
786 .stage2_aarch64 => false,
770787 .stage2_powerpc => true,
771788 .stage2_x86_64 => target.ofmt == .macho or target.ofmt == .elf,
772789 else => true,
......@@ -844,6 +861,7 @@ pub fn zigBackend(target: *const std.Target, use_llvm: bool) std.builtin.Compile
844861pub inline fn backendSupportsFeature(backend: std.builtin.CompilerBackend, comptime feature: Feature) bool {
845862 return switch (feature) {
846863 .panic_fn => switch (backend) {
864 .stage2_aarch64,
847865 .stage2_c,
848866 .stage2_llvm,
849867 .stage2_x86_64,
......@@ -864,7 +882,7 @@ pub inline fn backendSupportsFeature(backend: std.builtin.CompilerBackend, compt
864882 else => false,
865883 },
866884 .field_reordering => switch (backend) {
867 .stage2_c, .stage2_llvm, .stage2_x86_64 => true,
885 .stage2_aarch64, .stage2_c, .stage2_llvm, .stage2_x86_64 => true,
868886 else => false,
869887 },
870888 .separate_thread => switch (backend) {
stage1/wasm2c.c+1-1
......@@ -316,10 +316,10 @@ int main(int argc, char **argv) {
316316 "}\n"
317317 "\n"
318318 "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"
320319 " uint32_t r = *p;\n"
321320 " uint32_t new_p = r + n;\n"
322321 " if (new_p > UINT32_C(0xFFFF)) return UINT32_C(0xFFFFFFFF);\n"
322 " uint8_t *new_m = *m;\n"
323323 " uint32_t new_c = *c;\n"
324324 " if (new_c < new_p) {\n"
325325 " 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 {
123123 }
124124
125125 if (builtin.zig_backend != .stage2_arm and
126 builtin.zig_backend != .stage2_aarch64 and
127126 builtin.zig_backend != .stage2_spirv)
128127 {
129128 _ = @import("behavior/export_keyword.zig");
......@@ -141,7 +140,8 @@ test {
141140}
142141
143142// This bug only repros in the root file
144test "deference @embedFile() of a file full of zero bytes" {
143test "dereference @embedFile() of a file full of zero bytes" {
144 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
145145 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
146146
147147 const contents = @embedFile("behavior/zero.bin").*;
test/behavior/abs.zig+3-7
......@@ -3,7 +3,6 @@ const std = @import("std");
33const expect = std.testing.expect;
44
55test "@abs integers" {
6 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
76 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
87 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
98 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -50,7 +49,6 @@ fn testAbsIntegers() !void {
5049}
5150
5251test "@abs unsigned integers" {
53 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
5452 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
5553 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
5654
......@@ -90,7 +88,6 @@ fn testAbsUnsignedIntegers() !void {
9088}
9189
9290test "@abs big int <= 128 bits" {
93 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
9491 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
9592 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
9693 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
......@@ -153,7 +150,6 @@ fn testAbsUnsignedBigInt() !void {
153150}
154151
155152test "@abs floats" {
156 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
157153 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
158154 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
159155
......@@ -207,9 +203,9 @@ fn testAbsFloats(comptime T: type) !void {
207203}
208204
209205test "@abs int vectors" {
206 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
210207 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
211208 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
212 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
213209 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
214210 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
215211 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -275,8 +271,8 @@ fn testAbsIntVectors(comptime len: comptime_int) !void {
275271}
276272
277273test "@abs unsigned int vectors" {
274 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
278275 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
279 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
280276 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
281277 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
282278 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -334,8 +330,8 @@ fn testAbsUnsignedIntVectors(comptime len: comptime_int) !void {
334330}
335331
336332test "@abs float vectors" {
333 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
337334 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
338 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
339335 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
340336 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
341337 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
test/behavior/align.zig+1-19
......@@ -16,7 +16,6 @@ test "global variable alignment" {
1616}
1717
1818test "large alignment of local constant" {
19 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2019 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
2120 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // flaky
2221
......@@ -25,7 +24,6 @@ test "large alignment of local constant" {
2524}
2625
2726test "slicing array of length 1 can not assume runtime index is always zero" {
28 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2927 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
3028 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // flaky
3129
......@@ -74,7 +72,6 @@ test "alignment of struct with pointer has same alignment as usize" {
7472
7573test "alignment and size of structs with 128-bit fields" {
7674 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
77 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
7875 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
7976
8077 const A = struct {
......@@ -160,7 +157,6 @@ test "alignment and size of structs with 128-bit fields" {
160157}
161158
162159test "implicitly decreasing slice alignment" {
163 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
164160 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
165161 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
166162
......@@ -173,7 +169,6 @@ fn addUnalignedSlice(a: []align(1) const u32, b: []align(1) const u32) u32 {
173169}
174170
175171test "specifying alignment allows pointer cast" {
176 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
177172 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
178173 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
179174
......@@ -186,7 +181,6 @@ fn testBytesAlign(b: u8) !void {
186181}
187182
188183test "@alignCast slices" {
189 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
190184 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
191185 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
192186 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -205,7 +199,6 @@ fn sliceExpects4(slice: []align(4) u32) void {
205199
206200test "return error union with 128-bit integer" {
207201 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
208 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
209202 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
210203 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
211204 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -218,7 +211,6 @@ fn give() anyerror!u128 {
218211
219212test "page aligned array on stack" {
220213 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
221 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
222214 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
223215 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
224216 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -238,7 +230,6 @@ test "page aligned array on stack" {
238230}
239231
240232test "function alignment" {
241 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
242233 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
243234 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
244235 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -268,7 +259,6 @@ test "function alignment" {
268259}
269260
270261test "implicitly decreasing fn alignment" {
271 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
272262 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
273263 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
274264 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -292,7 +282,6 @@ fn alignedBig() align(16) i32 {
292282}
293283
294284test "@alignCast functions" {
295 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
296285 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
297286 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
298287 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -376,7 +365,6 @@ const DefaultAligned = struct {
376365
377366test "read 128-bit field from default aligned struct in stack memory" {
378367 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
379 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
380368 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
381369 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
382370 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -396,7 +384,6 @@ var default_aligned_global = DefaultAligned{
396384
397385test "read 128-bit field from default aligned struct in global memory" {
398386 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
399 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
400387 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
401388 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
402389 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -405,8 +392,8 @@ test "read 128-bit field from default aligned struct in global memory" {
405392}
406393
407394test "struct field explicit alignment" {
408 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
409395 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
396 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
410397 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
411398 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // flaky
412399 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
......@@ -426,7 +413,6 @@ test "struct field explicit alignment" {
426413}
427414
428415test "align(N) on functions" {
429 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
430416 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
431417 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
432418 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -455,7 +441,6 @@ test "comptime alloc alignment" {
455441 // TODO: it's impossible to test this in Zig today, since comptime vars do not have runtime addresses.
456442 if (true) return error.SkipZigTest;
457443 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
458 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
459444 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
460445 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // flaky
461446
......@@ -468,7 +453,6 @@ test "comptime alloc alignment" {
468453}
469454
470455test "@alignCast null" {
471 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
472456 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
473457 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
474458
......@@ -484,7 +468,6 @@ test "alignment of slice element" {
484468}
485469
486470test "sub-aligned pointer field access" {
487 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
488471 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
489472 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
490473 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -538,7 +521,6 @@ test "alignment of zero-bit types is respected" {
538521
539522test "zero-bit fields in extern struct pad fields appropriately" {
540523 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
541 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
542524 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
543525 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
544526 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
test/behavior/array.zig+5-37
......@@ -19,7 +19,6 @@ test "array to slice" {
1919}
2020
2121test "arrays" {
22 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2322 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
2423 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2524
......@@ -47,7 +46,6 @@ fn getArrayLen(a: []const u32) usize {
4746}
4847
4948test "array concat with undefined" {
50 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
5149 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
5250 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
5351
......@@ -73,7 +71,6 @@ test "array concat with undefined" {
7371test "array concat with tuple" {
7472 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
7573 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
76 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
7774 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
7875
7976 const array: [2]u8 = .{ 1, 2 };
......@@ -89,7 +86,6 @@ test "array concat with tuple" {
8986
9087test "array init with concat" {
9188 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
92 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
9389
9490 const a = 'a';
9591 var i: [4]u8 = [2]u8{ a, 'b' } ++ [2]u8{ 'c', 'd' };
......@@ -98,7 +94,6 @@ test "array init with concat" {
9894
9995test "array init with mult" {
10096 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
101 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
10297 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10398
10499 const a = 'a';
......@@ -110,7 +105,6 @@ test "array init with mult" {
110105}
111106
112107test "array literal with explicit type" {
113 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
114108 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
115109
116110 const hex_mult: [4]u16 = .{ 4096, 256, 16, 1 };
......@@ -138,7 +132,6 @@ const ArrayDotLenConstExpr = struct {
138132const some_array = [_]u8{ 0, 1, 2, 3 };
139133
140134test "array literal with specified size" {
141 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
142135 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
143136 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
144137
......@@ -162,7 +155,6 @@ test "array len field" {
162155
163156test "array with sentinels" {
164157 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
165 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
166158 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
167159
168160 const S = struct {
......@@ -200,7 +192,6 @@ test "void arrays" {
200192
201193test "nested arrays of strings" {
202194 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
203 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
204195 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
205196 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
206197
......@@ -215,7 +206,6 @@ test "nested arrays of strings" {
215206}
216207
217208test "nested arrays of integers" {
218 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
219209 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
220210
221211 const array_of_numbers = [_][2]u8{
......@@ -230,7 +220,6 @@ test "nested arrays of integers" {
230220}
231221
232222test "implicit comptime in array type size" {
233 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
234223 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
235224
236225 var arr: [plusOne(10)]bool = undefined;
......@@ -243,7 +232,6 @@ fn plusOne(x: u32) u32 {
243232}
244233
245234test "single-item pointer to array indexing and slicing" {
246 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
247235 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
248236 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
249237
......@@ -285,7 +273,6 @@ test "implicit cast zero sized array ptr to slice" {
285273}
286274
287275test "anonymous list literal syntax" {
288 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
289276 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
290277 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
291278
......@@ -308,7 +295,6 @@ const Sub = struct { b: u8 };
308295const Str = struct { a: []Sub };
309296test "set global var array via slice embedded in struct" {
310297 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
311 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
312298 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
313299
314300 var s = Str{ .a = s_array[0..] };
......@@ -323,7 +309,6 @@ test "set global var array via slice embedded in struct" {
323309}
324310
325311test "read/write through global variable array of struct fields initialized via array mult" {
326 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
327312 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
328313 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
329314
......@@ -345,7 +330,6 @@ test "read/write through global variable array of struct fields initialized via
345330
346331test "implicit cast single-item pointer" {
347332 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
348 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
349333 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
350334
351335 try testImplicitCastSingleItemPtr();
......@@ -364,7 +348,6 @@ fn testArrayByValAtComptime(b: [2]u8) u8 {
364348}
365349
366350test "comptime evaluating function that takes array by value" {
367 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
368351 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
369352
370353 const arr = [_]u8{ 1, 2 };
......@@ -376,7 +359,6 @@ test "comptime evaluating function that takes array by value" {
376359
377360test "runtime initialize array elem and then implicit cast to slice" {
378361 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
379 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
380362 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
381363
382364 var two: i32 = 2;
......@@ -387,7 +369,6 @@ test "runtime initialize array elem and then implicit cast to slice" {
387369
388370test "array literal as argument to function" {
389371 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
390 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
391372 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
392373
393374 const S = struct {
......@@ -414,8 +395,8 @@ test "array literal as argument to function" {
414395}
415396
416397test "double nested array to const slice cast in array literal" {
417 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
418398 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
399 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
419400 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
420401 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
421402
......@@ -476,7 +457,6 @@ test "double nested array to const slice cast in array literal" {
476457}
477458
478459test "anonymous literal in array" {
479 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
480460 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
481461 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
482462
......@@ -502,7 +482,6 @@ test "anonymous literal in array" {
502482}
503483
504484test "access the null element of a null terminated array" {
505 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
506485 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
507486
508487 const S = struct {
......@@ -520,7 +499,6 @@ test "access the null element of a null terminated array" {
520499}
521500
522501test "type deduction for array subscript expression" {
523 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
524502 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
525503 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
526504
......@@ -540,7 +518,6 @@ test "type deduction for array subscript expression" {
540518
541519test "sentinel element count towards the ABI size calculation" {
542520 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
543 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
544521 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
545522 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
546523
......@@ -564,7 +541,7 @@ test "sentinel element count towards the ABI size calculation" {
564541}
565542
566543test "zero-sized array with recursive type definition" {
567 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
544 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
568545 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
569546 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
570547
......@@ -587,8 +564,8 @@ test "zero-sized array with recursive type definition" {
587564}
588565
589566test "type coercion of anon struct literal to array" {
567 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
590568 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
591 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
592569 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
593570 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
594571
......@@ -628,7 +605,6 @@ test "array with comptime-only element type" {
628605}
629606
630607test "tuple to array handles sentinel" {
631 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
632608 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
633609 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
634610
......@@ -641,7 +617,6 @@ test "tuple to array handles sentinel" {
641617
642618test "array init of container level array variable" {
643619 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
644 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
645620 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
646621 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
647622
......@@ -675,8 +650,8 @@ test "runtime initialized sentinel-terminated array literal" {
675650}
676651
677652test "array of array agregate init" {
653 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
678654 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
679 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
680655 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
681656
682657 var a = [1]u32{11} ** 10;
......@@ -725,7 +700,6 @@ test "array init with no result location has result type" {
725700}
726701
727702test "slicing array of zero-sized values" {
728 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
729703 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
730704 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
731705 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -890,7 +864,6 @@ test "tuple initialized through reference to anonymous array init provides resul
890864
891865test "copied array element doesn't alias source" {
892866 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
893 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
894867 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
895868
896869 var x: [10][10]u32 = undefined;
......@@ -945,7 +918,6 @@ test "array initialized with array with sentinel" {
945918}
946919
947920test "store array of array of structs at comptime" {
948 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
949921 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
950922 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
951923
......@@ -970,7 +942,6 @@ test "store array of array of structs at comptime" {
970942}
971943
972944test "accessing multidimensional global array at comptime" {
973 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
974945 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
975946 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
976947
......@@ -986,8 +957,8 @@ test "accessing multidimensional global array at comptime" {
986957}
987958
988959test "union that needs padding bytes inside an array" {
989 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
990960 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
961 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
991962 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
992963 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
993964
......@@ -1023,7 +994,6 @@ test "runtime index of array of zero-bit values" {
1023994}
1024995
1025996test "@splat array" {
1026 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1027997 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1028998 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1029999
......@@ -1046,7 +1016,6 @@ test "@splat array" {
10461016
10471017test "@splat array with sentinel" {
10481018 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1049 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
10501019 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
10511020 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10521021
......@@ -1070,7 +1039,6 @@ test "@splat array with sentinel" {
10701039
10711040test "@splat zero-length array" {
10721041 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1073 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
10741042 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
10751043 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10761044
test/behavior/asm.zig+2-7
......@@ -7,7 +7,6 @@ const is_x86_64_linux = builtin.cpu.arch == .x86_64 and builtin.os.tag == .linux
77
88comptime {
99 if (builtin.zig_backend != .stage2_arm and
10 builtin.zig_backend != .stage2_aarch64 and
1110 !(builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) and // MSVC doesn't support inline assembly
1211 is_x86_64_linux)
1312 {
......@@ -30,7 +29,6 @@ test "module level assembly" {
3029 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
3130 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
3231 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
33 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
3432 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
3533
3634 if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) return error.SkipZigTest; // MSVC doesn't support inline assembly
......@@ -41,9 +39,9 @@ test "module level assembly" {
4139}
4240
4341test "output constraint modifiers" {
42 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
4443 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
4544 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
46 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
4745 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
4846 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
4947 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -63,9 +61,9 @@ test "output constraint modifiers" {
6361}
6462
6563test "alternative constraints" {
64 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
6665 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
6766 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
68 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
6967 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
7068 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
7169 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -83,7 +81,6 @@ test "alternative constraints" {
8381test "sized integer/float in asm input" {
8482 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
8583 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
86 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
8784 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
8885 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
8986 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -127,7 +124,6 @@ test "sized integer/float in asm input" {
127124test "struct/array/union types as input values" {
128125 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
129126 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
130 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
131127 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
132128 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
133129
......@@ -167,7 +163,6 @@ test "rw constraint (x86_64)" {
167163
168164test "asm modifiers (AArch64)" {
169165 if (!builtin.target.cpu.arch.isAARCH64()) return error.SkipZigTest;
170 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
171166
172167 if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) return error.SkipZigTest; // MSVC doesn't support inline assembly
173168
test/behavior/atomics.zig+12-13
......@@ -12,7 +12,7 @@ const supports_128_bit_atomics = switch (builtin.cpu.arch) {
1212};
1313
1414test "cmpxchg" {
15 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
15 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1616 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1717 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1818 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -39,7 +39,7 @@ fn testCmpxchg() !void {
3939}
4040
4141test "atomicrmw and atomicload" {
42 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
42 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
4343 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
4444 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
4545 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -68,7 +68,7 @@ fn testAtomicLoad(ptr: *u8) !void {
6868}
6969
7070test "cmpxchg with ptr" {
71 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
71 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
7272 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
7373 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
7474 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -94,7 +94,7 @@ test "cmpxchg with ptr" {
9494}
9595
9696test "cmpxchg with ignored result" {
97 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
97 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
9898 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
9999 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
100100 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -110,8 +110,8 @@ test "128-bit cmpxchg" {
110110 // TODO: this must appear first
111111 if (!supports_128_bit_atomics) return error.SkipZigTest;
112112
113 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
113114 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
114 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
115115 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
116116 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
117117
......@@ -139,7 +139,7 @@ fn test_u128_cmpxchg() !void {
139139var a_global_variable = @as(u32, 1234);
140140
141141test "cmpxchg on a global variable" {
142 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
142 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
143143 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
144144 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
145145 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -149,7 +149,7 @@ test "cmpxchg on a global variable" {
149149}
150150
151151test "atomic load and rmw with enum" {
152 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
152 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
153153 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
154154 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
155155 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -167,7 +167,7 @@ test "atomic load and rmw with enum" {
167167}
168168
169169test "atomic store" {
170 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
170 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
171171 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
172172 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
173173 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -185,7 +185,7 @@ fn testAtomicStore() !void {
185185}
186186
187187test "atomicrmw with floats" {
188 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
188 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
189189 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
190190 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
191191 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -211,7 +211,7 @@ fn testAtomicRmwFloat() !void {
211211}
212212
213213test "atomicrmw with ints" {
214 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
214 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
215215 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
216216 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
217217 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -290,7 +290,7 @@ test "atomicrmw with 128-bit ints" {
290290 // TODO: this must appear first
291291 if (!supports_128_bit_atomics) return error.SkipZigTest;
292292
293 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
293 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
294294
295295 try testAtomicRmwInt128(.signed);
296296 try testAtomicRmwInt128(.unsigned);
......@@ -359,7 +359,7 @@ fn testAtomicRmwInt128(comptime signedness: std.builtin.Signedness) !void {
359359}
360360
361361test "atomics with different types" {
362 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
362 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
363363 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
364364 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
365365 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -409,7 +409,6 @@ fn testAtomicsWithPackedStruct(comptime T: type, a: T, b: T) !void {
409409}
410410
411411test "return @atomicStore, using it as a void value" {
412 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
413412 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
414413 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
415414 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
test/behavior/basic.zig+1-21
......@@ -39,7 +39,6 @@ test "truncate to non-power-of-two integers" {
3939}
4040
4141test "truncate to non-power-of-two integers from 128-bit" {
42 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
4342 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
4443 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
4544 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -422,7 +421,6 @@ fn copy(src: *const u64, dst: *u64) void {
422421}
423422
424423test "call result of if else expression" {
425 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
426424 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
427425 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
428426 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -448,7 +446,6 @@ fn hereIsAnOpaqueType(ptr: *OpaqueA) *OpaqueA {
448446}
449447
450448test "take address of parameter" {
451 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
452449 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
453450 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
454451
......@@ -474,7 +471,6 @@ fn testPointerToVoidReturnType2() *const void {
474471}
475472
476473test "array 2D const double ptr" {
477 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
478474 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
479475 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
480476 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -487,7 +483,6 @@ test "array 2D const double ptr" {
487483}
488484
489485test "array 2D const double ptr with offset" {
490 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
491486 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
492487 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
493488 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -500,7 +495,6 @@ test "array 2D const double ptr with offset" {
500495}
501496
502497test "array 3D const double ptr with offset" {
503 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
504498 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
505499 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
506500 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -536,7 +530,6 @@ fn nine() u8 {
536530}
537531
538532test "struct inside function" {
539 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
540533 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
541534
542535 try testStructInFn();
......@@ -588,7 +581,6 @@ test "global variable assignment with optional unwrapping with var initialized t
588581var global_foo: *i32 = undefined;
589582
590583test "peer result location with typed parent, runtime condition, comptime prongs" {
591 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
592584 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
593585
594586 const S = struct {
......@@ -719,7 +711,6 @@ test "global constant is loaded with a runtime-known index" {
719711}
720712
721713test "multiline string literal is null terminated" {
722 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
723714 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
724715
725716 const s1 =
......@@ -732,7 +723,6 @@ test "multiline string literal is null terminated" {
732723}
733724
734725test "string escapes" {
735 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
736726 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
737727 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
738728 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -764,7 +754,6 @@ fn ptrEql(a: *const []const u8, b: *const []const u8) bool {
764754}
765755
766756test "string concatenation" {
767 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
768757 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
769758 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
770759
......@@ -787,7 +776,6 @@ test "string concatenation" {
787776}
788777
789778test "result location is optional inside error union" {
790 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
791779 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
792780 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
793781
......@@ -803,7 +791,6 @@ fn maybe(x: bool) anyerror!?u32 {
803791}
804792
805793test "auto created variables have correct alignment" {
806 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
807794 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
808795 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
809796
......@@ -821,7 +808,6 @@ test "auto created variables have correct alignment" {
821808
822809test "extern variable with non-pointer opaque type" {
823810 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
824 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
825811 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
826812 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
827813 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
......@@ -866,7 +852,6 @@ test "if expression type coercion" {
866852}
867853
868854test "discarding the result of various expressions" {
869 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
870855 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
871856 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
872857
......@@ -908,7 +893,6 @@ test "labeled block implicitly ends in a break" {
908893}
909894
910895test "catch in block has correct result location" {
911 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
912896 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
913897
914898 const S = struct {
......@@ -964,7 +948,6 @@ test "vector initialized with array init syntax has proper type" {
964948}
965949
966950test "weird array and tuple initializations" {
967 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
968951 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
969952 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" {
1010993 // https://github.com/ziglang/zig/issues/12208
1011994 return error.SkipZigTest;
1012995 }
1013 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1014996
1015997 const S = struct {
1016998 fn call(
......@@ -1128,7 +1110,6 @@ test "returning an opaque type from a function" {
11281110}
11291111
11301112test "orelse coercion as function argument" {
1131 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
11321113 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11331114
11341115 const Loc = struct { start: i32 = -1 };
......@@ -1378,7 +1359,6 @@ test "copy array of self-referential struct" {
13781359
13791360test "break out of block based on comptime known values" {
13801361 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1381 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
13821362 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
13831363
13841364 const S = struct {
......@@ -1412,8 +1392,8 @@ test "break out of block based on comptime known values" {
14121392}
14131393
14141394test "allocation and looping over 3-byte integer" {
1395 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
14151396 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1416 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
14171397 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
14181398 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
14191399 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
test/behavior/bit_shifting.zig+2-1
......@@ -112,7 +112,7 @@ test "comptime shift safety check" {
112112}
113113
114114test "Saturating Shift Left where lhs is of a computed type" {
115 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
115 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
116116 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
117117 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
118118 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -161,6 +161,7 @@ comptime {
161161}
162162
163163test "Saturating Shift Left" {
164 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
164165 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
165166 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
166167 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
test/behavior/bitcast.zig+9-12
......@@ -20,7 +20,6 @@ test "@bitCast iX -> uX (32, 64)" {
2020}
2121
2222test "@bitCast iX -> uX (8, 16, 128)" {
23 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2423 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
2524 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2625 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -35,8 +34,8 @@ test "@bitCast iX -> uX (8, 16, 128)" {
3534}
3635
3736test "@bitCast iX -> uX exotic integers" {
38 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
3937 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
38 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
4039 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
4140 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
4241 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -80,8 +79,8 @@ fn conv_uN(comptime N: usize, x: std.meta.Int(.unsigned, N)) std.meta.Int(.signe
8079}
8180
8281test "bitcast uX to bytes" {
83 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
8482 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
83 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
8584 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
8685 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
8786 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -296,9 +295,9 @@ test "triple level result location with bitcast sandwich passed as tuple element
296295}
297296
298297test "@bitCast packed struct of floats" {
298 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
299299 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
300300 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
301 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
302301 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
303302 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
304303 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -334,9 +333,9 @@ test "@bitCast packed struct of floats" {
334333}
335334
336335test "comptime @bitCast packed struct to int and back" {
336 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
337337 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
338338 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
339 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
340339 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
341340 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
342341 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -379,7 +378,6 @@ test "comptime bitcast with fields following f80" {
379378 }
380379
381380 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
382 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
383381 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
384382 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
385383
......@@ -393,7 +391,7 @@ test "comptime bitcast with fields following f80" {
393391}
394392
395393test "bitcast vector to integer and back" {
396 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
394 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
397395 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
398396 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
399397 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
......@@ -420,7 +418,6 @@ fn bitCastWrapper128(x: f128) u128 {
420418 return @as(u128, @bitCast(x));
421419}
422420test "bitcast nan float does not modify signaling bit" {
423 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
424421 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
425422 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
426423 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -473,7 +470,7 @@ test "bitcast nan float does not modify signaling bit" {
473470}
474471
475472test "@bitCast of packed struct of bools all true" {
476 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
473 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
477474 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
478475 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
479476 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
......@@ -494,7 +491,7 @@ test "@bitCast of packed struct of bools all true" {
494491}
495492
496493test "@bitCast of packed struct of bools all false" {
497 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
494 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
498495 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
499496 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
500497 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
......@@ -514,7 +511,7 @@ test "@bitCast of packed struct of bools all false" {
514511}
515512
516513test "@bitCast of packed struct containing pointer" {
517 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
514 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
518515 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
519516 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
520517 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
......@@ -544,7 +541,7 @@ test "@bitCast of packed struct containing pointer" {
544541}
545542
546543test "@bitCast of extern struct containing pointer" {
547 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
544 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
548545 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
549546 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
550547 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
test/behavior/bitreverse.zig+4-4
......@@ -8,8 +8,8 @@ test "@bitReverse large exotic integer" {
88}
99
1010test "@bitReverse" {
11 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1211 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
12 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1313 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1414 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1515 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -121,9 +121,9 @@ fn vector8() !void {
121121}
122122
123123test "bitReverse vectors u8" {
124 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
124125 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
125126 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
126 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
127127 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
128128 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
129129 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -141,9 +141,9 @@ fn vector16() !void {
141141}
142142
143143test "bitReverse vectors u16" {
144 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
144145 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
145146 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
146 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
147147 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
148148 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
149149 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -161,9 +161,9 @@ fn vector24() !void {
161161}
162162
163163test "bitReverse vectors u24" {
164 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
164165 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
165166 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
166 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
167167 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
168168 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
169169 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
test/behavior/builtin_functions_returning_void_or_noreturn.zig-1
......@@ -7,7 +7,6 @@ var x: u8 = 1;
77// This excludes builtin functions that return void or noreturn that cannot be tested.
88test {
99 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
10 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1110 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1211 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1312 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
test/behavior/byteswap.zig+32-43
......@@ -3,40 +3,8 @@ const builtin = @import("builtin");
33const expect = std.testing.expect;
44
55test "@byteSwap integers" {
6 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
7
8 if (builtin.zig_backend == .stage2_wasm) {
9 // TODO: Remove when self-hosted wasm supports more types for byteswap
10 const ByteSwapIntTest = struct {
11 fn run() !void {
12 try t(u8, 0x12, 0x12);
13 try t(u16, 0x1234, 0x3412);
14 try t(u24, 0x123456, 0x563412);
15 try t(i24, @as(i24, @bitCast(@as(u24, 0xf23456))), 0x5634f2);
16 try t(i24, 0x1234f6, @as(i24, @bitCast(@as(u24, 0xf63412))));
17 try t(u32, 0x12345678, 0x78563412);
18 try t(i32, @as(i32, @bitCast(@as(u32, 0xf2345678))), 0x785634f2);
19 try t(i32, 0x123456f8, @as(i32, @bitCast(@as(u32, 0xf8563412))));
20 try t(u64, 0x123456789abcdef1, 0xf1debc9a78563412);
21
22 try t(u0, @as(u0, 0), 0);
23 try t(i8, @as(i8, -50), -50);
24 try t(i16, @as(i16, @bitCast(@as(u16, 0x1234))), @as(i16, @bitCast(@as(u16, 0x3412))));
25 try t(i24, @as(i24, @bitCast(@as(u24, 0x123456))), @as(i24, @bitCast(@as(u24, 0x563412))));
26 try t(i32, @as(i32, @bitCast(@as(u32, 0x12345678))), @as(i32, @bitCast(@as(u32, 0x78563412))));
27 try t(i64, @as(i64, @bitCast(@as(u64, 0x123456789abcdef1))), @as(i64, @bitCast(@as(u64, 0xf1debc9a78563412))));
28 }
29 fn t(comptime I: type, input: I, expected_output: I) !void {
30 try std.testing.expect(expected_output == @byteSwap(input));
31 }
32 };
33 try comptime ByteSwapIntTest.run();
34 try ByteSwapIntTest.run();
35 return;
36 }
37
386 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
39 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
7 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
408 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
419 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
4210
......@@ -51,23 +19,44 @@ test "@byteSwap integers" {
5119 try t(u32, 0x12345678, 0x78563412);
5220 try t(i32, @as(i32, @bitCast(@as(u32, 0xf2345678))), 0x785634f2);
5321 try t(i32, 0x123456f8, @as(i32, @bitCast(@as(u32, 0xf8563412))));
54 try t(u40, 0x123456789a, 0x9a78563412);
55 try t(i48, 0x123456789abc, @as(i48, @bitCast(@as(u48, 0xbc9a78563412))));
56 try t(u56, 0x123456789abcde, 0xdebc9a78563412);
5722 try t(u64, 0x123456789abcdef1, 0xf1debc9a78563412);
58 try t(u88, 0x123456789abcdef1112131, 0x312111f1debc9a78563412);
59 try t(u96, 0x123456789abcdef111213141, 0x41312111f1debc9a78563412);
60 try t(u128, 0x123456789abcdef11121314151617181, 0x8171615141312111f1debc9a78563412);
6123
6224 try t(u0, @as(u0, 0), 0);
6325 try t(i8, @as(i8, -50), -50);
6426 try t(i16, @as(i16, @bitCast(@as(u16, 0x1234))), @as(i16, @bitCast(@as(u16, 0x3412))));
6527 try t(i24, @as(i24, @bitCast(@as(u24, 0x123456))), @as(i24, @bitCast(@as(u24, 0x563412))));
6628 try t(i32, @as(i32, @bitCast(@as(u32, 0x12345678))), @as(i32, @bitCast(@as(u32, 0x78563412))));
29 try t(i64, @as(i64, @bitCast(@as(u64, 0x123456789abcdef1))), @as(i64, @bitCast(@as(u64, 0xf1debc9a78563412))));
30 }
31 fn t(comptime I: type, input: I, expected_output: I) !void {
32 try std.testing.expect(expected_output == @byteSwap(input));
33 }
34 };
35 try comptime ByteSwapIntTest.run();
36 try ByteSwapIntTest.run();
37}
38
39test "@byteSwap exotic integers" {
40 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
41 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
42 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
43 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
44 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
45 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
46
47 const ByteSwapIntTest = struct {
48 fn run() !void {
49 try t(u0, 0, 0);
50 try t(u40, 0x123456789a, 0x9a78563412);
51 try t(i48, 0x123456789abc, @as(i48, @bitCast(@as(u48, 0xbc9a78563412))));
52 try t(u56, 0x123456789abcde, 0xdebc9a78563412);
53 try t(u88, 0x123456789abcdef1112131, 0x312111f1debc9a78563412);
54 try t(u96, 0x123456789abcdef111213141, 0x41312111f1debc9a78563412);
55 try t(u128, 0x123456789abcdef11121314151617181, 0x8171615141312111f1debc9a78563412);
56
6757 try t(u40, @as(i40, @bitCast(@as(u40, 0x123456789a))), @as(u40, 0x9a78563412));
6858 try t(i48, @as(i48, @bitCast(@as(u48, 0x123456789abc))), @as(i48, @bitCast(@as(u48, 0xbc9a78563412))));
6959 try t(i56, @as(i56, @bitCast(@as(u56, 0x123456789abcde))), @as(i56, @bitCast(@as(u56, 0xdebc9a78563412))));
70 try t(i64, @as(i64, @bitCast(@as(u64, 0x123456789abcdef1))), @as(i64, @bitCast(@as(u64, 0xf1debc9a78563412))));
7160 try t(i88, @as(i88, @bitCast(@as(u88, 0x123456789abcdef1112131))), @as(i88, @bitCast(@as(u88, 0x312111f1debc9a78563412))));
7261 try t(i96, @as(i96, @bitCast(@as(u96, 0x123456789abcdef111213141))), @as(i96, @bitCast(@as(u96, 0x41312111f1debc9a78563412))));
7362 try t(
......@@ -93,9 +82,9 @@ fn vector8() !void {
9382}
9483
9584test "@byteSwap vectors u8" {
85 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
9686 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
9787 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
98 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
9988 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10089 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
10190 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -113,9 +102,9 @@ fn vector16() !void {
113102}
114103
115104test "@byteSwap vectors u16" {
105 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
116106 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
117107 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
118 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
119108 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
120109 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
121110 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -133,9 +122,9 @@ fn vector24() !void {
133122}
134123
135124test "@byteSwap vectors u24" {
125 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
136126 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
137127 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
138 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
139128 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
140129 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
141130 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
test/behavior/call.zig+6-13
......@@ -20,8 +20,8 @@ test "super basic invocations" {
2020}
2121
2222test "basic invocations" {
23 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2324 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
24 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2525 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2626 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2727 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -60,7 +60,6 @@ test "basic invocations" {
6060}
6161
6262test "tuple parameters" {
63 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
6463 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
6564 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
6665 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -95,7 +94,6 @@ test "tuple parameters" {
9594
9695test "result location of function call argument through runtime condition and struct init" {
9796 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
98 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
9997 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10098
10199 const E = enum { a, b };
......@@ -115,6 +113,7 @@ test "result location of function call argument through runtime condition and st
115113}
116114
117115test "function call with 40 arguments" {
116 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
118117 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
119118 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
120119
......@@ -270,7 +269,7 @@ test "arguments to comptime parameters generated in comptime blocks" {
270269}
271270
272271test "forced tail call" {
273 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
272 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
274273 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
275274 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
276275 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
......@@ -305,7 +304,7 @@ test "forced tail call" {
305304}
306305
307306test "inline call preserves tail call" {
308 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
307 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
309308 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
310309 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
311310 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
......@@ -342,7 +341,6 @@ test "inline call preserves tail call" {
342341}
343342
344343test "inline call doesn't re-evaluate non generic struct" {
345 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
346344 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
347345 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
348346
......@@ -409,7 +407,6 @@ test "recursive inline call with comptime known argument" {
409407}
410408
411409test "inline while with @call" {
412 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
413410 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
414411
415412 const S = struct {
......@@ -439,7 +436,6 @@ test "method call as parameter type" {
439436}
440437
441438test "non-anytype generic parameters provide result type" {
442 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
443439 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
444440 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
445441
......@@ -468,7 +464,6 @@ test "non-anytype generic parameters provide result type" {
468464}
469465
470466test "argument to generic function has correct result type" {
471 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
472467 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
473468 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
474469
......@@ -521,7 +516,6 @@ test "call function in comptime field" {
521516
522517test "call function pointer in comptime field" {
523518 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
524 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
525519 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
526520 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
527521
......@@ -573,7 +567,6 @@ test "value returned from comptime function is comptime known" {
573567}
574568
575569test "registers get overwritten when ignoring return" {
576 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
577570 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
578571 if (builtin.cpu.arch != .x86_64 or builtin.os.tag != .linux) return error.SkipZigTest;
579572
......@@ -619,7 +612,6 @@ test "call with union with zero sized field is not memorized incorrectly" {
619612}
620613
621614test "function call with cast to anyopaque pointer" {
622 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
623615 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
624616 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
625617 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -637,6 +629,7 @@ test "function call with cast to anyopaque pointer" {
637629}
638630
639631test "arguments pointed to on stack into tailcall" {
632 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
640633 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
641634 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
642635 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -708,7 +701,7 @@ test "arguments pointed to on stack into tailcall" {
708701}
709702
710703test "tail call function pointer" {
711 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
704 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
712705 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
713706 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
714707 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
test/behavior/cast.zig+18-100
......@@ -21,7 +21,6 @@ test "integer literal to pointer cast" {
2121}
2222
2323test "peer type resolution: ?T and T" {
24 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2524 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
2625 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2726
......@@ -100,7 +99,6 @@ test "comptime_int @floatFromInt" {
10099}
101100
102101test "@floatFromInt" {
103 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
104102 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
105103 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
106104 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -121,7 +119,6 @@ test "@floatFromInt" {
121119}
122120
123121test "@floatFromInt(f80)" {
124 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
125122 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
126123 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
127124 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -157,7 +154,6 @@ test "@floatFromInt(f80)" {
157154}
158155
159156test "@intFromFloat" {
160 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
161157 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
162158 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
163159 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -181,7 +177,6 @@ fn expectIntFromFloat(comptime F: type, f: F, comptime I: type, i: I) !void {
181177}
182178
183179test "implicitly cast indirect pointer to maybe-indirect pointer" {
184 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
185180 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
186181 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
187182
......@@ -241,7 +236,6 @@ test "@floatCast comptime_int and comptime_float" {
241236}
242237
243238test "coerce undefined to optional" {
244 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
245239 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
246240 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
247241
......@@ -262,7 +256,6 @@ fn MakeType(comptime T: type) type {
262256}
263257
264258test "implicit cast from *[N]T to [*c]T" {
265 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
266259 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
267260 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
268261
......@@ -299,7 +292,6 @@ test "@intCast to u0 and use the result" {
299292}
300293
301294test "peer result null and comptime_int" {
302 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
303295 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
304296 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
305297
......@@ -324,7 +316,6 @@ test "peer result null and comptime_int" {
324316}
325317
326318test "*const ?[*]const T to [*c]const [*c]const T" {
327 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
328319 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
329320 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
330321 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -338,7 +329,6 @@ test "*const ?[*]const T to [*c]const [*c]const T" {
338329}
339330
340331test "array coercion to undefined at runtime" {
341 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
342332 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
343333 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
344334
......@@ -368,7 +358,6 @@ fn implicitIntLitToOptional() void {
368358}
369359
370360test "return u8 coercing into ?u32 return type" {
371 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
372361 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
373362 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
374363
......@@ -390,7 +379,6 @@ test "cast from ?[*]T to ??[*]T" {
390379}
391380
392381test "peer type unsigned int to signed" {
393 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
394382 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
395383
396384 var w: u31 = 5;
......@@ -403,7 +391,6 @@ test "peer type unsigned int to signed" {
403391}
404392
405393test "expected [*c]const u8, found [*:0]const u8" {
406 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
407394 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
408395 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
409396
......@@ -415,7 +402,6 @@ test "expected [*c]const u8, found [*:0]const u8" {
415402}
416403
417404test "explicit cast from integer to error type" {
418 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
419405 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
420406 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
421407 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -431,7 +417,6 @@ fn testCastIntToErr(err: anyerror) !void {
431417}
432418
433419test "peer resolve array and const slice" {
434 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
435420 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
436421 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
437422 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -447,7 +432,6 @@ fn testPeerResolveArrayConstSlice(b: bool) !void {
447432}
448433
449434test "implicitly cast from T to anyerror!?T" {
450 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
451435 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
452436 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
453437
......@@ -473,7 +457,6 @@ fn castToOptionalTypeError(z: i32) !void {
473457}
474458
475459test "implicitly cast from [0]T to anyerror![]T" {
476 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
477460 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
478461
479462 try testCastZeroArrayToErrSliceMut();
......@@ -489,7 +472,6 @@ fn gimmeErrOrSlice() anyerror![]u8 {
489472}
490473
491474test "peer type resolution: [0]u8, []const u8, and anyerror![]u8" {
492 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
493475 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
494476 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
495477 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -522,7 +504,6 @@ fn peerTypeEmptyArrayAndSliceAndError(a: bool, slice: []u8) anyerror![]u8 {
522504}
523505
524506test "implicit cast from *const [N]T to []const T" {
525 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
526507 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
527508 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
528509
......@@ -548,7 +529,6 @@ fn testCastConstArrayRefToConstSlice() !void {
548529}
549530
550531test "peer type resolution: error and [N]T" {
551 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
552532 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
553533 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
554534
......@@ -573,7 +553,6 @@ fn testPeerErrorAndArray2(x: u8) anyerror![]const u8 {
573553}
574554
575555test "single-item pointer of array to slice to unknown length pointer" {
576 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
577556 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
578557 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
579558
......@@ -603,7 +582,6 @@ fn testCastPtrOfArrayToSliceAndPtr() !void {
603582}
604583
605584test "cast *[1][*]const u8 to [*]const ?[*]const u8" {
606 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
607585 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
608586 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
609587
......@@ -613,8 +591,8 @@ test "cast *[1][*]const u8 to [*]const ?[*]const u8" {
613591}
614592
615593test "@intCast on vector" {
594 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
616595 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
617 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
618596 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
619597 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
620598 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -651,7 +629,6 @@ test "@intCast on vector" {
651629}
652630
653631test "@floatCast cast down" {
654 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
655632 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
656633 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
657634 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -670,7 +647,6 @@ test "@floatCast cast down" {
670647}
671648
672649test "peer type resolution: unreachable, error set, unreachable" {
673 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
674650 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
675651
676652 const Error = error{
......@@ -704,7 +680,6 @@ test "peer cast: error set any anyerror" {
704680}
705681
706682test "peer type resolution: error set supersets" {
707 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
708683 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
709684 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
710685 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -735,7 +710,6 @@ test "peer type resolution: error set supersets" {
735710
736711test "peer type resolution: disjoint error sets" {
737712 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
738 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
739713 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
740714 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
741715
......@@ -765,7 +739,6 @@ test "peer type resolution: disjoint error sets" {
765739
766740test "peer type resolution: error union and error set" {
767741 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
768 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
769742 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
770743 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
771744
......@@ -799,7 +772,6 @@ test "peer type resolution: error union and error set" {
799772
800773test "peer type resolution: error union after non-error" {
801774 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
802 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
803775 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
804776 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
805777
......@@ -833,7 +805,6 @@ test "peer type resolution: error union after non-error" {
833805
834806test "peer cast *[0]T to E![]const T" {
835807 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
836 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
837808 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
838809 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
839810
......@@ -849,7 +820,6 @@ test "peer cast *[0]T to E![]const T" {
849820
850821test "peer cast *[0]T to []const T" {
851822 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
852 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
853823 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
854824 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
855825
......@@ -872,7 +842,6 @@ test "peer cast *[N]T to [*]T" {
872842}
873843
874844test "peer resolution of string literals" {
875 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
876845 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
877846 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
878847 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -895,7 +864,6 @@ test "peer resolution of string literals" {
895864}
896865
897866test "peer cast [:x]T to []T" {
898 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
899867 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
900868 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
901869
......@@ -912,7 +880,6 @@ test "peer cast [:x]T to []T" {
912880}
913881
914882test "peer cast [N:x]T to [N]T" {
915 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
916883 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
917884 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
918885
......@@ -929,7 +896,6 @@ test "peer cast [N:x]T to [N]T" {
929896}
930897
931898test "peer cast *[N:x]T to *[N]T" {
932 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
933899 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
934900 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
935901
......@@ -945,7 +911,6 @@ test "peer cast *[N:x]T to *[N]T" {
945911}
946912
947913test "peer cast [*:x]T to [*]T" {
948 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
949914 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
950915 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
951916 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -966,7 +931,6 @@ test "peer cast [*:x]T to [*]T" {
966931}
967932
968933test "peer cast [:x]T to [*:x]T" {
969 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
970934 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
971935 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
972936 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -988,7 +952,6 @@ test "peer cast [:x]T to [*:x]T" {
988952}
989953
990954test "peer type resolution implicit cast to return type" {
991 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
992955 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
993956 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
994957
......@@ -1009,7 +972,6 @@ test "peer type resolution implicit cast to return type" {
1009972}
1010973
1011974test "peer type resolution implicit cast to variable type" {
1012 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1013975 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1014976 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1015977
......@@ -1035,7 +997,6 @@ test "variable initialization uses result locations properly with regards to the
1035997}
1036998
1037999test "cast between C pointer with different but compatible types" {
1038 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10391000 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10401001 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
10411002
......@@ -1053,7 +1014,6 @@ test "cast between C pointer with different but compatible types" {
10531014}
10541015
10551016test "peer type resolve string lit with sentinel-terminated mutable slice" {
1056 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10571017 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10581018 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
10591019
......@@ -1104,7 +1064,6 @@ test "comptime float casts" {
11041064}
11051065
11061066test "pointer reinterpret const float to int" {
1107 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
11081067 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11091068
11101069 // The hex representation is 0x3fe3333333333303.
......@@ -1119,7 +1078,6 @@ test "pointer reinterpret const float to int" {
11191078}
11201079
11211080test "implicit cast from [*]T to ?*anyopaque" {
1122 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
11231081 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11241082 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11251083 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1184,7 +1142,6 @@ test "cast function with an opaque parameter" {
11841142}
11851143
11861144test "implicit ptr to *anyopaque" {
1187 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
11881145 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11891146 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11901147 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1199,7 +1156,6 @@ test "implicit ptr to *anyopaque" {
11991156}
12001157
12011158test "return null from fn () anyerror!?&T" {
1202 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
12031159 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
12041160 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
12051161
......@@ -1216,7 +1172,6 @@ fn returnNullLitFromOptionalTypeErrorRef() anyerror!?*A {
12161172}
12171173
12181174test "peer type resolution: [0]u8 and []const u8" {
1219 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
12201175 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
12211176 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
12221177 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1237,7 +1192,6 @@ fn peerTypeEmptyArrayAndSlice(a: bool, slice: []const u8) []const u8 {
12371192}
12381193
12391194test "implicitly cast from [N]T to ?[]const T" {
1240 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
12411195 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
12421196 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
12431197 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1251,7 +1205,6 @@ fn castToOptionalSlice() ?[]const u8 {
12511205}
12521206
12531207test "cast u128 to f128 and back" {
1254 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
12551208 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
12561209 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
12571210 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1274,7 +1227,6 @@ fn cast128Float(x: u128) f128 {
12741227}
12751228
12761229test "implicit cast from *[N]T to ?[*]T" {
1277 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
12781230 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
12791231 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
12801232 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1291,7 +1243,6 @@ test "implicit cast from *[N]T to ?[*]T" {
12911243}
12921244
12931245test "implicit cast from *T to ?*anyopaque" {
1294 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
12951246 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
12961247 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
12971248 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1306,7 +1257,6 @@ fn incrementVoidPtrValue(value: ?*anyopaque) void {
13061257}
13071258
13081259test "implicit cast *[0]T to E![]const u8" {
1309 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
13101260 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
13111261
13121262 var x = @as(anyerror![]const u8, &[0]u8{});
......@@ -1330,7 +1280,6 @@ test "cast from array reference to fn: runtime fn ptr" {
13301280}
13311281
13321282test "*const [N]null u8 to ?[]const u8" {
1333 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
13341283 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
13351284 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
13361285 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1367,7 +1316,6 @@ test "cast between [*c]T and ?[*:0]T on fn parameter" {
13671316
13681317var global_struct: struct { f0: usize } = undefined;
13691318test "assignment to optional pointer result loc" {
1370 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
13711319 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
13721320 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
13731321 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1386,7 +1334,6 @@ test "cast between *[N]void and []void" {
13861334}
13871335
13881336test "peer resolve arrays of different size to const slice" {
1389 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
13901337 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
13911338 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
13921339
......@@ -1400,7 +1347,6 @@ fn boolToStr(b: bool) []const u8 {
14001347}
14011348
14021349test "cast f16 to wider types" {
1403 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
14041350 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
14051351 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
14061352 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1421,7 +1367,6 @@ test "cast f16 to wider types" {
14211367}
14221368
14231369test "cast f128 to narrower types" {
1424 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
14251370 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
14261371 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
14271372 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1441,7 +1386,6 @@ test "cast f128 to narrower types" {
14411386}
14421387
14431388test "peer type resolution: unreachable, null, slice" {
1444 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
14451389 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
14461390 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
14471391 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1460,7 +1404,6 @@ test "peer type resolution: unreachable, null, slice" {
14601404}
14611405
14621406test "cast i8 fn call peers to i32 result" {
1463 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
14641407 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
14651408
14661409 const S = struct {
......@@ -1482,7 +1425,6 @@ test "cast i8 fn call peers to i32 result" {
14821425}
14831426
14841427test "cast compatible optional types" {
1485 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
14861428 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
14871429 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
14881430 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1494,7 +1436,6 @@ test "cast compatible optional types" {
14941436}
14951437
14961438test "coerce undefined single-item pointer of array to error union of slice" {
1497 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
14981439 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
14991440
15001441 const a = @as([*]u8, undefined)[0..0];
......@@ -1513,7 +1454,6 @@ test "pointer to empty struct literal to mutable slice" {
15131454}
15141455
15151456test "coerce between pointers of compatible differently-named floats" {
1516 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
15171457 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
15181458 if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows and !builtin.link_libc) return error.SkipZigTest;
15191459 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -1548,7 +1488,6 @@ test "peer type resolution of const and non-const pointer to array" {
15481488}
15491489
15501490test "intFromFloat to zero-bit int" {
1551 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
15521491 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
15531492 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
15541493
......@@ -1573,8 +1512,6 @@ test "cast typed undefined to int" {
15731512}
15741513
15751514// test "implicit cast from [:0]T to [*c]T" {
1576// if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1577
15781515// var a: [:0]const u8 = "foo";
15791516// _ = &a;
15801517// const b: [*c]const u8 = a;
......@@ -1584,7 +1521,6 @@ test "cast typed undefined to int" {
15841521// }
15851522
15861523test "bitcast packed struct with u0" {
1587 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
15881524 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
15891525
15901526 const S = packed struct(u2) { a: u0, b: u2 };
......@@ -1691,7 +1627,6 @@ test "coercion from single-item pointer to @as to slice" {
16911627}
16921628
16931629test "peer type resolution: const sentinel slice and mutable non-sentinel slice" {
1694 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
16951630 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
16961631 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
16971632 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1721,7 +1656,6 @@ test "peer type resolution: const sentinel slice and mutable non-sentinel slice"
17211656}
17221657
17231658test "peer type resolution: float and comptime-known fixed-width integer" {
1724 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
17251659 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
17261660 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
17271661
......@@ -1743,7 +1677,7 @@ test "peer type resolution: float and comptime-known fixed-width integer" {
17431677}
17441678
17451679test "peer type resolution: same array type with sentinel" {
1746 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1680 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
17471681 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
17481682 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
17491683 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1766,7 +1700,6 @@ test "peer type resolution: same array type with sentinel" {
17661700}
17671701
17681702test "peer type resolution: array with sentinel and array without sentinel" {
1769 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
17701703 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
17711704 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
17721705 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1789,7 +1722,7 @@ test "peer type resolution: array with sentinel and array without sentinel" {
17891722}
17901723
17911724test "peer type resolution: array and vector with same child type" {
1792 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1725 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
17931726 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
17941727 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
17951728 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1813,7 +1746,7 @@ test "peer type resolution: array and vector with same child type" {
18131746}
18141747
18151748test "peer type resolution: array with smaller child type and vector with larger child type" {
1816 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1749 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
18171750 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
18181751 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
18191752 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -1837,7 +1770,7 @@ test "peer type resolution: array with smaller child type and vector with larger
18371770}
18381771
18391772test "peer type resolution: error union and optional of same type" {
1840 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1773 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
18411774 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
18421775 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
18431776 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1861,7 +1794,6 @@ test "peer type resolution: error union and optional of same type" {
18611794}
18621795
18631796test "peer type resolution: C pointer and @TypeOf(null)" {
1864 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
18651797 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
18661798 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
18671799 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1884,7 +1816,6 @@ test "peer type resolution: C pointer and @TypeOf(null)" {
18841816}
18851817
18861818test "peer type resolution: three-way resolution combines error set and optional" {
1887 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
18881819 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
18891820 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
18901821 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
19271858}
19281859
19291860test "peer type resolution: vector and optional vector" {
1930 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1861 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
19311862 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
19321863 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
19331864 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -1952,7 +1883,6 @@ test "peer type resolution: vector and optional vector" {
19521883}
19531884
19541885test "peer type resolution: optional fixed-width int and comptime_int" {
1955 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
19561886 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
19571887 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" {
19741904}
19751905
19761906test "peer type resolution: array and tuple" {
1977 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1907 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
19781908 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
19791909 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
19801910 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1998,7 +1928,7 @@ test "peer type resolution: array and tuple" {
19981928}
19991929
20001930test "peer type resolution: vector and tuple" {
2001 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1931 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
20021932 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
20031933 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
20041934 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -2022,7 +1952,7 @@ test "peer type resolution: vector and tuple" {
20221952}
20231953
20241954test "peer type resolution: vector and array and tuple" {
2025 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1955 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
20261956 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
20271957 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
20281958 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -2066,7 +1996,6 @@ test "peer type resolution: vector and array and tuple" {
20661996}
20671997
20681998test "peer type resolution: empty tuple pointer and slice" {
2069 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
20701999 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
20712000 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
20722001 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -2088,7 +2017,6 @@ test "peer type resolution: empty tuple pointer and slice" {
20882017}
20892018
20902019test "peer type resolution: tuple pointer and slice" {
2091 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
20922020 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
20932021 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
20942022 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -2110,7 +2038,6 @@ test "peer type resolution: tuple pointer and slice" {
21102038}
21112039
21122040test "peer type resolution: tuple pointer and optional slice" {
2113 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
21142041 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
21152042 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
21162043 // Miscompilation on Intel's OpenCL CPU runtime.
......@@ -2133,7 +2060,6 @@ test "peer type resolution: tuple pointer and optional slice" {
21332060}
21342061
21352062test "peer type resolution: many compatible pointers" {
2136 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
21372063 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
21382064 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
21392065 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -2200,7 +2126,6 @@ test "peer type resolution: many compatible pointers" {
22002126}
22012127
22022128test "peer type resolution: tuples with comptime fields" {
2203 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
22042129 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
22052130 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
22062131 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
......@@ -2232,7 +2157,6 @@ test "peer type resolution: tuples with comptime fields" {
22322157}
22332158
22342159test "peer type resolution: C pointer and many pointer" {
2235 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
22362160 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
22372161 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
22382162 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -2256,7 +2180,6 @@ test "peer type resolution: C pointer and many pointer" {
22562180}
22572181
22582182test "peer type resolution: pointer attributes are combined correctly" {
2259 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
22602183 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
22612184 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
22622185 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -2338,7 +2261,7 @@ test "peer type resolution: pointer attributes are combined correctly" {
23382261}
23392262
23402263test "peer type resolution: arrays of compatible types" {
2341 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2264 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
23422265 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
23432266 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
23442267 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -2356,7 +2279,6 @@ test "peer type resolution: arrays of compatible types" {
23562279}
23572280
23582281test "cast builtins can wrap result in optional" {
2359 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
23602282 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
23612283 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
23622284 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -2394,7 +2316,6 @@ test "cast builtins can wrap result in optional" {
23942316}
23952317
23962318test "cast builtins can wrap result in error union" {
2397 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
23982319 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
23992320 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
24002321
......@@ -2432,7 +2353,6 @@ test "cast builtins can wrap result in error union" {
24322353}
24332354
24342355test "cast builtins can wrap result in error union and optional" {
2435 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
24362356 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
24372357 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
24382358 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -2471,8 +2391,8 @@ test "cast builtins can wrap result in error union and optional" {
24712391}
24722392
24732393test "@floatCast on vector" {
2394 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
24742395 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
2475 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
24762396 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
24772397 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
24782398 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -2512,8 +2432,8 @@ test "@floatCast on vector" {
25122432}
25132433
25142434test "@ptrFromInt on vector" {
2435 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
25152436 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
2516 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
25172437 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
25182438 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
25192439 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -2537,8 +2457,8 @@ test "@ptrFromInt on vector" {
25372457}
25382458
25392459test "@intFromPtr on vector" {
2460 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
25402461 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
2541 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
25422462 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
25432463 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
25442464 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -2562,8 +2482,8 @@ test "@intFromPtr on vector" {
25622482}
25632483
25642484test "@floatFromInt on vector" {
2485 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
25652486 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
2566 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
25672487 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
25682488 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
25692489 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -2582,8 +2502,8 @@ test "@floatFromInt on vector" {
25822502}
25832503
25842504test "@intFromFloat on vector" {
2505 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
25852506 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
2586 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
25872507 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
25882508 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
25892509 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -2602,8 +2522,8 @@ test "@intFromFloat on vector" {
26022522}
26032523
26042524test "@intFromBool on vector" {
2525 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
26052526 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
2606 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
26072527 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
26082528 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
26092529 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -2639,7 +2559,6 @@ test "15-bit int to float" {
26392559}
26402560
26412561test "@as does not corrupt values with incompatible representations" {
2642 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
26432562 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
26442563 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
26452564
......@@ -2654,7 +2573,6 @@ test "@as does not corrupt values with incompatible representations" {
26542573}
26552574
26562575test "result information is preserved through many nested structures" {
2657 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
26582576 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
26592577 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
26602578 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -2679,7 +2597,7 @@ test "result information is preserved through many nested structures" {
26792597}
26802598
26812599test "@intCast vector of signed integer" {
2682 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2600 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
26832601 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
26842602 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
26852603 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -2703,7 +2621,6 @@ test "result type is preserved into comptime block" {
27032621}
27042622
27052623test "bitcast vector" {
2706 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
27072624 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
27082625
27092626 const u8x32 = @Vector(32, u8);
......@@ -2766,6 +2683,7 @@ test "@intFromFloat boundary cases" {
27662683}
27672684
27682685test "@intFromFloat vector boundary cases" {
2686 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
27692687 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
27702688 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
27712689 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
test/behavior/cast_int.zig+4-3
......@@ -5,7 +5,6 @@ const expectEqual = std.testing.expectEqual;
55const maxInt = std.math.maxInt;
66
77test "@intCast i32 to u7" {
8 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
98 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
109 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1110 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -19,7 +18,6 @@ test "@intCast i32 to u7" {
1918}
2019
2120test "coerce i8 to i32 and @intCast back" {
22 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2321 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2422 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2523
......@@ -36,6 +34,7 @@ test "coerce i8 to i32 and @intCast back" {
3634
3735test "coerce non byte-sized integers accross 32bits boundary" {
3836 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
37
3938 {
4039 var v: u21 = 6417;
4140 _ = &v;
......@@ -164,8 +163,9 @@ const Piece = packed struct {
164163 }
165164};
166165
166// Originally reported at https://github.com/ziglang/zig/issues/14200
167167test "load non byte-sized optional value" {
168 // Originally reported at https://github.com/ziglang/zig/issues/14200
168 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
169169 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
170170 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
171171
......@@ -181,6 +181,7 @@ test "load non byte-sized optional value" {
181181}
182182
183183test "load non byte-sized value in struct" {
184 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
184185 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
185186 if (builtin.cpu.arch.endian() != .little) return error.SkipZigTest; // packed struct TODO
186187 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
test/behavior/comptime_memory.zig-2
......@@ -66,7 +66,6 @@ fn bigToNativeEndian(comptime T: type, v: T) T {
6666 return if (endian == .big) v else @byteSwap(v);
6767}
6868test "type pun endianness" {
69 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
7069 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
7170
7271 comptime {
......@@ -360,7 +359,6 @@ test "offset field ptr by enclosing array element size" {
360359}
361360
362361test "accessing reinterpreted memory of parent object" {
363 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
364362 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
365363
366364 const S = extern struct {
test/behavior/const_slice_child.zig-1
......@@ -7,7 +7,6 @@ const expect = testing.expect;
77var argv: [*]const [*]const u8 = undefined;
88
99test "const slice child" {
10 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1110 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1211 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1312 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
test/behavior/decl_literals.zig-1
......@@ -35,7 +35,6 @@ test "decl literal with pointer" {
3535test "call decl literal with optional" {
3636 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
3737 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
38 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
3938 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
4039
4140 const S = struct {
test/behavior/defer.zig+2-6
......@@ -32,7 +32,6 @@ test "defer and labeled break" {
3232}
3333
3434test "errdefer does not apply to fn inside fn" {
35 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
3635 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
3736
3837 if (testNestedFnErrDefer()) |_| @panic("expected error") else |e| try expect(e == error.Bad);
......@@ -51,7 +50,6 @@ fn testNestedFnErrDefer() anyerror!void {
5150
5251test "return variable while defer expression in scope to modify it" {
5352 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
54 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
5553 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
5654
5755 const S = struct {
......@@ -91,7 +89,6 @@ fn runSomeErrorDefers(x: bool) !bool {
9189}
9290
9391test "mixing normal and error defers" {
94 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
9592 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
9693 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
9794
......@@ -110,7 +107,7 @@ test "mixing normal and error defers" {
110107}
111108
112109test "errdefer with payload" {
113 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
110 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
114111 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
115112 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
116113 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -132,8 +129,8 @@ test "errdefer with payload" {
132129}
133130
134131test "reference to errdefer payload" {
132 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
135133 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
136 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
137134 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
138135 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
139136 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -157,7 +154,6 @@ test "reference to errdefer payload" {
157154}
158155
159156test "simple else prong doesn't emit an error for unreachable else prong" {
160 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
161157 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
162158 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
163159
test/behavior/enum.zig+10-19
......@@ -25,7 +25,6 @@ fn testEnumFromIntEval(x: i32) !void {
2525const EnumFromIntNumber = enum { Zero, One, Two, Three, Four };
2626
2727test "int to enum" {
28 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2928 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
3029
3130 try testEnumFromIntEval(3);
......@@ -608,7 +607,6 @@ fn testEnumWithSpecifiedTagValues(x: MultipleChoice) !void {
608607}
609608
610609test "enum with specified tag values" {
611 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
612610 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
613611
614612 try testEnumWithSpecifiedTagValues(MultipleChoice.C);
......@@ -616,7 +614,6 @@ test "enum with specified tag values" {
616614}
617615
618616test "non-exhaustive enum" {
619 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
620617 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
621618
622619 const S = struct {
......@@ -680,7 +677,6 @@ test "empty non-exhaustive enum" {
680677}
681678
682679test "single field non-exhaustive enum" {
683 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
684680 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
685681
686682 const S = struct {
......@@ -744,7 +740,6 @@ test "cast integer literal to enum" {
744740}
745741
746742test "enum with specified and unspecified tag values" {
747 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
748743 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
749744
750745 try testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2.D);
......@@ -904,8 +899,8 @@ test "enum value allocation" {
904899}
905900
906901test "enum literal casting to tagged union" {
907 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
908902 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
903 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
909904 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
910905
911906 const Arch = union(enum) {
......@@ -931,7 +926,6 @@ test "enum literal casting to tagged union" {
931926const Bar = enum { A, B, C, D };
932927
933928test "enum literal casting to error union with payload enum" {
934 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
935929 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
936930
937931 var bar: error{B}!Bar = undefined;
......@@ -941,8 +935,8 @@ test "enum literal casting to error union with payload enum" {
941935}
942936
943937test "constant enum initialization with differing sizes" {
944 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
945938 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
939 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
946940 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
947941 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
948942 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -985,8 +979,8 @@ fn test3_2(f: Test3Foo) !void {
985979}
986980
987981test "@tagName" {
988 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
989982 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
983 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
990984 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
991985 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
992986 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1002,8 +996,8 @@ fn testEnumTagNameBare(n: anytype) []const u8 {
1002996const BareNumber = enum { One, Two, Three };
1003997
1004998test "@tagName non-exhaustive enum" {
1005 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1006999 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1000 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
10071001 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10081002 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
10091003 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1014,8 +1008,8 @@ test "@tagName non-exhaustive enum" {
10141008const NonExhaustive = enum(u8) { A, B, _ };
10151009
10161010test "@tagName is null-terminated" {
1017 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
10181011 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1012 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
10191013 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10201014 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
10211015 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1030,8 +1024,8 @@ test "@tagName is null-terminated" {
10301024}
10311025
10321026test "tag name with assigned enum values" {
1033 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
10341027 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1028 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
10351029 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10361030 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
10371031 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1046,7 +1040,6 @@ test "tag name with assigned enum values" {
10461040}
10471041
10481042test "@tagName on enum literals" {
1049 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
10501043 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10511044 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
10521045
......@@ -1055,8 +1048,8 @@ test "@tagName on enum literals" {
10551048}
10561049
10571050test "tag name with signed enum values" {
1058 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
10591051 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1052 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
10601053 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10611054 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
10621055 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1073,8 +1066,8 @@ test "tag name with signed enum values" {
10731066}
10741067
10751068test "@tagName in callconv(.c) function" {
1076 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
10771069 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1070 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
10781071 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
10791072 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
10801073 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1091,7 +1084,6 @@ fn testEnumTagNameCallconvC() callconv(.c) [*:0]const u8 {
10911084
10921085test "enum literal casting to optional" {
10931086 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1094 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
10951087 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10961088
10971089 var bar: ?Bar = undefined;
......@@ -1117,8 +1109,8 @@ const bit_field_1 = BitFieldOfEnums{
11171109};
11181110
11191111test "bit field access with enum fields" {
1120 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
11211112 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1113 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
11221114 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11231115 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
11241116 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
......@@ -1158,8 +1150,8 @@ test "enum literal in array literal" {
11581150}
11591151
11601152test "tag name functions are unique" {
1161 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
11621153 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1154 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
11631155 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11641156 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
11651157 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1179,7 +1171,6 @@ test "tag name functions are unique" {
11791171}
11801172
11811173test "size of enum with only one tag which has explicit integer tag type" {
1182 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
11831174 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11841175
11851176 const E = enum(u8) { nope = 10 };
test/behavior/error.zig+3-22
......@@ -402,7 +402,6 @@ fn intLiteral(str: []const u8) !?i64 {
402402
403403test "nested error union function call in optional unwrap" {
404404 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
405 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
406405 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
407406
408407 const S = struct {
......@@ -448,7 +447,6 @@ test "nested error union function call in optional unwrap" {
448447}
449448
450449test "return function call to error set from error union function" {
451 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
452450 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
453451
454452 const S = struct {
......@@ -465,7 +463,6 @@ test "return function call to error set from error union function" {
465463}
466464
467465test "optional error set is the same size as error set" {
468 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
469466 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
470467 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" {
481478}
482479
483480test "nested catch" {
484 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
485481 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
486482
487483 const S = struct {
......@@ -530,7 +526,7 @@ test "function pointer with return type that is error union with payload which i
530526}
531527
532528test "return result loc as peer result loc in inferred error set function" {
533 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
529 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
534530 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
535531 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" {
562558
563559test "error payload type is correctly resolved" {
564560 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
565 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
566561 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
567562
568563 const MyIntWrapper = struct {
......@@ -591,7 +586,6 @@ test "error union comptime caching" {
591586
592587test "@errorName" {
593588 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
594 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
595589 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
596590 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
597591 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -606,7 +600,6 @@ fn gimmeItBroke() anyerror {
606600
607601test "@errorName sentinel length matches slice length" {
608602 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
609 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
610603 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
611604 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
612605 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -701,7 +694,6 @@ test "coerce error set to the current inferred error set" {
701694
702695test "error union payload is properly aligned" {
703696 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
704 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
705697 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
706698 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
707699 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -719,7 +711,6 @@ test "error union payload is properly aligned" {
719711}
720712
721713test "ret_ptr doesn't cause own inferred error set to be resolved" {
722 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
723714 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
724715
725716 const S = struct {
......@@ -760,7 +751,6 @@ test "simple else prong allowed even when all errors handled" {
760751}
761752
762753test "pointer to error union payload" {
763 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
764754 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
765755 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
766756 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -794,7 +784,6 @@ const NoReturn = struct {
794784};
795785
796786test "error union of noreturn used with if" {
797 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
798787 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
799788 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
800789 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -809,7 +798,6 @@ test "error union of noreturn used with if" {
809798}
810799
811800test "error union of noreturn used with try" {
812 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
813801 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
814802 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
815803 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -821,7 +809,6 @@ test "error union of noreturn used with try" {
821809}
822810
823811test "error union of noreturn used with catch" {
824 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
825812 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
826813 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
827814 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -833,7 +820,6 @@ test "error union of noreturn used with catch" {
833820}
834821
835822test "alignment of wrapping an error union payload" {
836 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
837823 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
838824 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
839825 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -887,7 +873,6 @@ test "catch within a function that calls no errorable functions" {
887873}
888874
889875test "error from comptime string" {
890 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
891876 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
892877 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
893878 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -913,7 +898,6 @@ test "field access of anyerror results in smaller error set" {
913898}
914899
915900test "optional error union return type" {
916 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
917901 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
918902
919903 const S = struct {
......@@ -928,7 +912,6 @@ test "optional error union return type" {
928912
929913test "optional error set return type" {
930914 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
931 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
932915
933916 const E = error{ A, B };
934917 const S = struct {
......@@ -953,7 +936,6 @@ test "optional error set function parameter" {
953936
954937test "returning an error union containing a type with no runtime bits" {
955938 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
956 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
957939 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
958940
959941 const ZeroByteType = struct {
......@@ -969,7 +951,7 @@ test "returning an error union containing a type with no runtime bits" {
969951}
970952
971953test "try used in recursive function with inferred error set" {
972 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
954 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
973955 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
974956 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
975957
......@@ -1010,7 +992,6 @@ test "generic inline function returns inferred error set" {
1010992}
1011993
1012994test "function called at runtime is properly analyzed for inferred error set" {
1013 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1014995 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1015996 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1016997
......@@ -1065,8 +1046,8 @@ test "@errorCast from error union to error union" {
10651046}
10661047
10671048test "result location initialization of error union with OPV payload" {
1049 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
10681050 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1069 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10701051 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10711052 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
10721053 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
test/behavior/eval.zig+2-34
......@@ -18,7 +18,6 @@ fn unwrapAndAddOne(blah: ?i32) i32 {
1818}
1919const should_be_1235 = unwrapAndAddOne(1234);
2020test "static add one" {
21 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2221 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2322 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2423
......@@ -71,7 +70,6 @@ fn constExprEvalOnSingleExprBlocksFn(x: i32, b: bool) i32 {
7170}
7271
7372test "constant expressions" {
74 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
7573 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
7674
7775 var array: [array_size]u8 = undefined;
......@@ -93,7 +91,6 @@ fn letsTryToCompareBools(a: bool, b: bool) bool {
9391 return max(bool, a, b);
9492}
9593test "inlined block and runtime block phi" {
96 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
9794 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
9895
9996 try expect(letsTryToCompareBools(true, true));
......@@ -140,7 +137,6 @@ test "pointer to type" {
140137}
141138
142139test "a type constructed in a global expression" {
143 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
144140 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
145141 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
146142 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -236,7 +232,6 @@ const vertices = [_]Vertex{
236232};
237233
238234test "statically initialized list" {
239 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
240235 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
241236
242237 try expect(static_point_list[0].x == 1);
......@@ -342,7 +337,6 @@ fn doesAlotT(comptime T: type, value: usize) T {
342337}
343338
344339test "@setEvalBranchQuota at same scope as generic function call" {
345 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
346340 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
347341
348342 try expect(doesAlotT(u32, 2) == 2);
......@@ -394,7 +388,6 @@ test "return 0 from function that has u0 return type" {
394388}
395389
396390test "statically initialized struct" {
397 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
398391 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
399392
400393 st_init_str_foo.x += 1;
......@@ -444,7 +437,6 @@ fn copyWithPartialInline(s: []u32, b: []u8) void {
444437
445438test "binary math operator in partially inlined function" {
446439 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
447 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
448440 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
449441 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
450442
......@@ -462,7 +454,6 @@ test "binary math operator in partially inlined function" {
462454}
463455
464456test "comptime shl" {
465 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
466457 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
467458 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
468459 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -491,6 +482,7 @@ test "comptime bitwise operators" {
491482}
492483
493484test "comptime shlWithOverflow" {
485 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
494486 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
495487 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
496488
......@@ -503,7 +495,6 @@ test "comptime shlWithOverflow" {
503495}
504496
505497test "const ptr to variable data changes at runtime" {
506 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
507498 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
508499 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
509500
......@@ -521,7 +512,6 @@ const foo_ref = &foo_contents;
521512
522513test "runtime 128 bit integer division" {
523514 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
524 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
525515 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
526516 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
527517 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -536,7 +526,6 @@ test "runtime 128 bit integer division" {
536526}
537527
538528test "@tagName of @typeInfo" {
539 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
540529 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
541530 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
542531
......@@ -545,7 +534,6 @@ test "@tagName of @typeInfo" {
545534}
546535
547536test "static eval list init" {
548 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
549537 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
550538 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
551539
......@@ -578,7 +566,6 @@ test "inlined loop has array literal with elided runtime scope on first iteratio
578566}
579567
580568test "ptr to local array argument at comptime" {
581 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
582569 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
583570
584571 comptime {
......@@ -741,7 +728,6 @@ test "*align(1) u16 is the same as *align(1:0:2) u16" {
741728
742729test "array concatenation of function calls" {
743730 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
744 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
745731 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
746732 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
747733
......@@ -751,7 +737,6 @@ test "array concatenation of function calls" {
751737
752738test "array multiplication of function calls" {
753739 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
754 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
755740 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
756741 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
757742
......@@ -769,7 +754,6 @@ fn scalar(x: u32) u32 {
769754
770755test "array concatenation peer resolves element types - value" {
771756 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
772 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
773757 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
774758
775759 var a = [2]u3{ 1, 7 };
......@@ -786,7 +770,6 @@ test "array concatenation peer resolves element types - value" {
786770
787771test "array concatenation peer resolves element types - pointer" {
788772 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
789 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
790773 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
791774 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
792775
......@@ -803,7 +786,6 @@ test "array concatenation peer resolves element types - pointer" {
803786
804787test "array concatenation sets the sentinel - value" {
805788 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
806 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
807789 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
808790 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
809791 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -823,7 +805,6 @@ test "array concatenation sets the sentinel - value" {
823805}
824806
825807test "array concatenation sets the sentinel - pointer" {
826 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
827808 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
828809 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
829810 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -843,7 +824,6 @@ test "array concatenation sets the sentinel - pointer" {
843824
844825test "array multiplication sets the sentinel - value" {
845826 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
846 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
847827 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
848828 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
849829 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -862,7 +842,6 @@ test "array multiplication sets the sentinel - value" {
862842
863843test "array multiplication sets the sentinel - pointer" {
864844 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
865 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
866845 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
867846 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
868847 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -889,7 +868,6 @@ test "comptime assign int to optional int" {
889868
890869test "two comptime calls with array default initialized to undefined" {
891870 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
892 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
893871 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
894872
895873 const S = struct {
......@@ -976,7 +954,6 @@ test "const local with comptime init through array init" {
976954}
977955
978956test "closure capture type of runtime-known parameter" {
979 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
980957 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
981958
982959 const S = struct {
......@@ -992,7 +969,6 @@ test "closure capture type of runtime-known parameter" {
992969}
993970
994971test "closure capture type of runtime-known var" {
995 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
996972 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
997973
998974 var x: u32 = 1234;
......@@ -1035,7 +1011,6 @@ test "comptime break passing through runtime condition converted to runtime brea
10351011}
10361012
10371013test "comptime break to outer loop passing through runtime condition converted to runtime break" {
1038 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10391014 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10401015 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10411016
......@@ -1088,7 +1063,6 @@ test "comptime break operand passing through runtime condition converted to runt
10881063}
10891064
10901065test "comptime break operand passing through runtime switch converted to runtime break" {
1091 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10921066 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10931067
10941068 const S = struct {
......@@ -1108,7 +1082,6 @@ test "comptime break operand passing through runtime switch converted to runtime
11081082}
11091083
11101084test "no dependency loop for alignment of self struct" {
1111 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
11121085 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11131086 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
11141087 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1147,7 +1120,6 @@ test "no dependency loop for alignment of self struct" {
11471120}
11481121
11491122test "no dependency loop for alignment of self bare union" {
1150 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
11511123 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11521124 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
11531125 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1186,7 +1158,6 @@ test "no dependency loop for alignment of self bare union" {
11861158}
11871159
11881160test "no dependency loop for alignment of self tagged union" {
1189 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
11901161 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11911162 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
11921163 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1230,7 +1201,6 @@ test "equality of pointers to comptime const" {
12301201}
12311202
12321203test "storing an array of type in a field" {
1233 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
12341204 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
12351205 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
12361206 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1260,7 +1230,6 @@ test "storing an array of type in a field" {
12601230}
12611231
12621232test "pass pointer to field of comptime-only type as a runtime parameter" {
1263 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
12641233 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
12651234 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
12661235
......@@ -1387,7 +1356,6 @@ test "lazy sizeof union tag size in compare" {
13871356}
13881357
13891358test "lazy value is resolved as slice operand" {
1390 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
13911359 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
13921360 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
13931361 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1568,7 +1536,7 @@ test "x or true is comptime-known true" {
15681536}
15691537
15701538test "non-optional and optional array elements concatenated" {
1571 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1539 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
15721540 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
15731541 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
15741542
test/behavior/export_builtin.zig-4
......@@ -4,7 +4,6 @@ const expect = std.testing.expect;
44
55test "exporting enum value" {
66 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
7 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
87
98 if (builtin.cpu.arch.isWasm()) {
109 // https://github.com/ziglang/zig/issues/4866
......@@ -23,7 +22,6 @@ test "exporting enum value" {
2322
2423test "exporting with internal linkage" {
2524 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
26 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2725
2826 const S = struct {
2927 fn foo() callconv(.c) void {}
......@@ -36,7 +34,6 @@ test "exporting with internal linkage" {
3634
3735test "exporting using namespace access" {
3836 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
39 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
4037
4138 if (builtin.cpu.arch.isWasm()) {
4239 // https://github.com/ziglang/zig/issues/4866
......@@ -57,7 +54,6 @@ test "exporting using namespace access" {
5754
5855test "exporting comptime-known value" {
5956 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
60 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
6157 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
6258 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
6359
test/behavior/field_parent_ptr.zig+3
......@@ -2,6 +2,7 @@ const expect = @import("std").testing.expect;
22const builtin = @import("builtin");
33
44test "@fieldParentPtr struct" {
5 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
56 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
67 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
78
......@@ -1339,6 +1340,7 @@ test "@fieldParentPtr packed struct last zero-bit field" {
13391340}
13401341
13411342test "@fieldParentPtr tagged union" {
1343 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
13421344 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
13431345 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
13441346
......@@ -1475,6 +1477,7 @@ test "@fieldParentPtr tagged union" {
14751477}
14761478
14771479test "@fieldParentPtr untagged union" {
1480 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
14781481 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
14791482 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
14801483
test/behavior/floatop.zig+18-68
......@@ -143,7 +143,6 @@ test "cmp f64" {
143143}
144144
145145test "cmp f128" {
146 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
147146 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
148147 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
149148 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -154,7 +153,6 @@ test "cmp f128" {
154153}
155154
156155test "cmp f80/c_longdouble" {
157 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
158156 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
159157 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
160158 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
......@@ -223,6 +221,7 @@ fn testCmp(comptime T: type) !void {
223221}
224222
225223test "vector cmp f16" {
224 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
226225 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
227226 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
228227 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
......@@ -236,6 +235,7 @@ test "vector cmp f16" {
236235}
237236
238237test "vector cmp f32" {
238 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
239239 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
240240 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
241241 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -249,6 +249,7 @@ test "vector cmp f32" {
249249}
250250
251251test "vector cmp f64" {
252 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
252253 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
253254 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
254255 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -261,8 +262,8 @@ test "vector cmp f64" {
261262}
262263
263264test "vector cmp f128" {
265 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
264266 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
265 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
266267 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
267268 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
268269 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -276,6 +277,7 @@ test "vector cmp f128" {
276277}
277278
278279test "vector cmp f80/c_longdouble" {
280 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
279281 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .hexagon) return error.SkipZigTest;
280282 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .powerpc64le) return error.SkipZigTest;
281283 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -324,7 +326,6 @@ fn testCmpVector(comptime T: type) !void {
324326
325327test "different sized float comparisons" {
326328 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
327 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
328329 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
329330 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
330331
......@@ -371,7 +372,6 @@ test "negative f128 intFromFloat at compile-time" {
371372
372373test "@sqrt f16" {
373374 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
374 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
375375 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
376376 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
377377 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -382,7 +382,6 @@ test "@sqrt f16" {
382382
383383test "@sqrt f32/f64" {
384384 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
385 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
386385 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
387386 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
388387
......@@ -394,7 +393,6 @@ test "@sqrt f32/f64" {
394393
395394test "@sqrt f80/f128/c_longdouble" {
396395 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
397 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
398396 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
399397 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
400398 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -481,9 +479,9 @@ fn testSqrt(comptime T: type) !void {
481479}
482480
483481test "@sqrt with vectors" {
482 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
484483 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
485484 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
486 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
487485 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
488486 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
489487
......@@ -503,7 +501,6 @@ fn testSqrtWithVectors() !void {
503501
504502test "@sin f16" {
505503 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
506 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
507504 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
508505 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
509506 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -514,7 +511,6 @@ test "@sin f16" {
514511
515512test "@sin f32/f64" {
516513 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
517 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
518514 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
519515 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
520516 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -527,7 +523,6 @@ test "@sin f32/f64" {
527523
528524test "@sin f80/f128/c_longdouble" {
529525 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
530 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
531526 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
532527 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
533528 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -554,9 +549,9 @@ fn testSin(comptime T: type) !void {
554549}
555550
556551test "@sin with vectors" {
552 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
557553 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
558554 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
559 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
560555 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
561556 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
562557
......@@ -576,7 +571,6 @@ fn testSinWithVectors() !void {
576571
577572test "@cos f16" {
578573 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
579 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
580574 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
581575 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
582576 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -587,7 +581,6 @@ test "@cos f16" {
587581
588582test "@cos f32/f64" {
589583 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
590 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
591584 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
592585 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
593586 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -600,7 +593,6 @@ test "@cos f32/f64" {
600593
601594test "@cos f80/f128/c_longdouble" {
602595 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
603 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
604596 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
605597 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
606598 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -627,9 +619,9 @@ fn testCos(comptime T: type) !void {
627619}
628620
629621test "@cos with vectors" {
622 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
630623 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
631624 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
632 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
633625 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
634626 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
635627
......@@ -649,7 +641,6 @@ fn testCosWithVectors() !void {
649641
650642test "@tan f16" {
651643 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
652 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
653644 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
654645 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
655646 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -660,7 +651,6 @@ test "@tan f16" {
660651
661652test "@tan f32/f64" {
662653 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
663 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
664654 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
665655 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
666656 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -673,7 +663,6 @@ test "@tan f32/f64" {
673663
674664test "@tan f80/f128/c_longdouble" {
675665 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
676 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
677666 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
678667 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
679668 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -700,9 +689,9 @@ fn testTan(comptime T: type) !void {
700689}
701690
702691test "@tan with vectors" {
692 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
703693 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
704694 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
705 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
706695 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
707696 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
708697
......@@ -722,7 +711,6 @@ fn testTanWithVectors() !void {
722711
723712test "@exp f16" {
724713 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
725 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
726714 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
727715 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
728716 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -733,7 +721,6 @@ test "@exp f16" {
733721
734722test "@exp f32/f64" {
735723 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
736 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
737724 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
738725 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
739726 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -746,7 +733,6 @@ test "@exp f32/f64" {
746733
747734test "@exp f80/f128/c_longdouble" {
748735 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
749 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
750736 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
751737 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
752738 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -777,9 +763,9 @@ fn testExp(comptime T: type) !void {
777763}
778764
779765test "@exp with vectors" {
766 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
780767 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
781768 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
782 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
783769 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
784770 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
785771
......@@ -799,7 +785,6 @@ fn testExpWithVectors() !void {
799785
800786test "@exp2 f16" {
801787 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
802 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
803788 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
804789 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
805790 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -810,7 +795,6 @@ test "@exp2 f16" {
810795
811796test "@exp2 f32/f64" {
812797 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
813 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
814798 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
815799 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
816800 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -823,7 +807,6 @@ test "@exp2 f32/f64" {
823807
824808test "@exp2 f80/f128/c_longdouble" {
825809 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
826 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
827810 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
828811 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
829812 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -849,9 +832,9 @@ fn testExp2(comptime T: type) !void {
849832}
850833
851834test "@exp2 with @vectors" {
835 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
852836 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
853837 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
854 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
855838 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
856839 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
857840
......@@ -870,7 +853,6 @@ fn testExp2WithVectors() !void {
870853}
871854
872855test "@log f16" {
873 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
874856 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
875857 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
876858 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -881,7 +863,6 @@ test "@log f16" {
881863}
882864
883865test "@log f32/f64" {
884 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
885866 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
886867 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
887868 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -894,7 +875,6 @@ test "@log f32/f64" {
894875}
895876
896877test "@log f80/f128/c_longdouble" {
897 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
898878 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
899879 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
900880 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -921,8 +901,8 @@ fn testLog(comptime T: type) !void {
921901}
922902
923903test "@log with @vectors" {
904 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
924905 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
925 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
926906 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
927907 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
928908 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -940,7 +920,6 @@ test "@log with @vectors" {
940920}
941921
942922test "@log2 f16" {
943 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
944923 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
945924 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
946925 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -951,7 +930,6 @@ test "@log2 f16" {
951930}
952931
953932test "@log2 f32/f64" {
954 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
955933 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
956934 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
957935 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -964,7 +942,6 @@ test "@log2 f32/f64" {
964942}
965943
966944test "@log2 f80/f128/c_longdouble" {
967 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
968945 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
969946 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
970947 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -991,8 +968,8 @@ fn testLog2(comptime T: type) !void {
991968}
992969
993970test "@log2 with vectors" {
971 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
994972 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
995 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
996973 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
997974 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
998975 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1016,7 +993,6 @@ fn testLog2WithVectors() !void {
1016993}
1017994
1018995test "@log10 f16" {
1019 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1020996 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1021997 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1022998 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1027,7 +1003,6 @@ test "@log10 f16" {
10271003}
10281004
10291005test "@log10 f32/f64" {
1030 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10311006 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10321007 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10331008 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1040,7 +1015,6 @@ test "@log10 f32/f64" {
10401015}
10411016
10421017test "@log10 f80/f128/c_longdouble" {
1043 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10441018 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10451019 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10461020 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1067,8 +1041,8 @@ fn testLog10(comptime T: type) !void {
10671041}
10681042
10691043test "@log10 with vectors" {
1044 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
10701045 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1071 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10721046 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10731047 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
10741048 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1089,7 +1063,6 @@ fn testLog10WithVectors() !void {
10891063
10901064test "@abs f16" {
10911065 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1092 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10931066 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10941067 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
10951068
......@@ -1099,7 +1072,6 @@ test "@abs f16" {
10991072
11001073test "@abs f32/f64" {
11011074 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1102 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
11031075 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11041076
11051077 try testFabs(f32);
......@@ -1110,7 +1082,6 @@ test "@abs f32/f64" {
11101082
11111083test "@abs f80/f128/c_longdouble" {
11121084 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1113 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
11141085 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
11151086 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11161087 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1190,7 +1161,7 @@ fn testFabs(comptime T: type) !void {
11901161}
11911162
11921163test "@abs with vectors" {
1193 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1164 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
11941165 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11951166 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
11961167 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1210,7 +1181,6 @@ fn testFabsWithVectors() !void {
12101181}
12111182
12121183test "@floor f16" {
1213 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
12141184 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
12151185 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
12161186 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1220,7 +1190,6 @@ test "@floor f16" {
12201190}
12211191
12221192test "@floor f32/f64" {
1223 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
12241193 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
12251194 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
12261195 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1232,7 +1201,6 @@ test "@floor f32/f64" {
12321201}
12331202
12341203test "@floor f80/f128/c_longdouble" {
1235 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
12361204 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
12371205 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
12381206 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -1284,7 +1252,7 @@ fn testFloor(comptime T: type) !void {
12841252}
12851253
12861254test "@floor with vectors" {
1287 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1255 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
12881256 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
12891257 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
12901258 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1304,7 +1272,6 @@ fn testFloorWithVectors() !void {
13041272}
13051273
13061274test "@ceil f16" {
1307 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
13081275 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
13091276 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
13101277 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1314,7 +1281,6 @@ test "@ceil f16" {
13141281}
13151282
13161283test "@ceil f32/f64" {
1317 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
13181284 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
13191285 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
13201286 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1326,7 +1292,6 @@ test "@ceil f32/f64" {
13261292}
13271293
13281294test "@ceil f80/f128/c_longdouble" {
1329 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
13301295 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
13311296 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
13321297 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -1378,7 +1343,7 @@ fn testCeil(comptime T: type) !void {
13781343}
13791344
13801345test "@ceil with vectors" {
1381 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1346 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
13821347 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
13831348 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
13841349 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1398,7 +1363,6 @@ fn testCeilWithVectors() !void {
13981363}
13991364
14001365test "@trunc f16" {
1401 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
14021366 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
14031367 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
14041368 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1408,7 +1372,6 @@ test "@trunc f16" {
14081372}
14091373
14101374test "@trunc f32/f64" {
1411 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
14121375 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
14131376 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
14141377 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1420,7 +1383,6 @@ test "@trunc f32/f64" {
14201383}
14211384
14221385test "@trunc f80/f128/c_longdouble" {
1423 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
14241386 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
14251387 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
14261388 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -1472,7 +1434,7 @@ fn testTrunc(comptime T: type) !void {
14721434}
14731435
14741436test "@trunc with vectors" {
1475 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1437 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
14761438 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
14771439 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
14781440 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1492,7 +1454,6 @@ fn testTruncWithVectors() !void {
14921454}
14931455
14941456test "neg f16" {
1495 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
14961457 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
14971458 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
14981459 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1508,7 +1469,6 @@ test "neg f16" {
15081469}
15091470
15101471test "neg f32/f64" {
1511 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
15121472 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
15131473 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
15141474 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1520,7 +1480,6 @@ test "neg f32/f64" {
15201480}
15211481
15221482test "neg f80/f128/c_longdouble" {
1523 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
15241483 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
15251484 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
15261485 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1606,7 +1565,6 @@ fn testNeg(comptime T: type) !void {
16061565}
16071566
16081567test "eval @setFloatMode at compile-time" {
1609 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
16101568 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
16111569
16121570 const result = comptime fnWithFloatMode();
......@@ -1629,7 +1587,6 @@ test "f128 at compile time is lossy" {
16291587
16301588test "comptime fixed-width float zero divided by zero produces NaN" {
16311589 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1632 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
16331590 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
16341591 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
16351592 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1641,7 +1598,6 @@ test "comptime fixed-width float zero divided by zero produces NaN" {
16411598
16421599test "comptime fixed-width float non-zero divided by zero produces signed Inf" {
16431600 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1644 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
16451601 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
16461602 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
16471603
......@@ -1686,21 +1642,18 @@ test "comptime inf >= runtime 1" {
16861642 try std.testing.expect(f >= i);
16871643}
16881644test "comptime isNan(nan * 1)" {
1689 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
16901645 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
16911646
16921647 const nan_times_one = comptime std.math.nan(f64) * 1;
16931648 try std.testing.expect(std.math.isNan(nan_times_one));
16941649}
16951650test "runtime isNan(nan * 1)" {
1696 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
16971651 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
16981652
16991653 const nan_times_one = std.math.nan(f64) * 1;
17001654 try std.testing.expect(std.math.isNan(nan_times_one));
17011655}
17021656test "comptime isNan(nan * 0)" {
1703 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
17041657 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
17051658
17061659 const nan_times_zero = comptime std.math.nan(f64) * 0;
......@@ -1709,7 +1662,6 @@ test "comptime isNan(nan * 0)" {
17091662 try std.testing.expect(std.math.isNan(zero_times_nan));
17101663}
17111664test "runtime isNan(nan * 0)" {
1712 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
17131665 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
17141666
17151667 const nan_times_zero = std.math.nan(f64) * 0;
......@@ -1718,7 +1670,6 @@ test "runtime isNan(nan * 0)" {
17181670 try std.testing.expect(std.math.isNan(zero_times_nan));
17191671}
17201672test "comptime isNan(inf * 0)" {
1721 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
17221673 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
17231674
17241675 const inf_times_zero = comptime std.math.inf(f64) * 0;
......@@ -1727,7 +1678,6 @@ test "comptime isNan(inf * 0)" {
17271678 try std.testing.expect(std.math.isNan(zero_times_inf));
17281679}
17291680test "runtime isNan(inf * 0)" {
1730 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
17311681 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
17321682
17331683 const inf_times_zero = std.math.inf(f64) * 0;
test/behavior/fn.zig-13
......@@ -78,7 +78,6 @@ test "return inner function which references comptime variable of outer function
7878
7979test "discard the result of a function that returns a struct" {
8080 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
81 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
8281 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
8382
8483 const S = struct {
......@@ -101,7 +100,6 @@ test "discard the result of a function that returns a struct" {
101100
102101test "inline function call that calls optional function pointer, return pointer at callsite interacts correctly with callsite return type" {
103102 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
104 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
105103 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
106104 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
107105
......@@ -179,7 +177,6 @@ fn fComplexCallconvRet(x: u32) callconv(blk: {
179177
180178test "function with complex callconv and return type expressions" {
181179 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
182 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
183180 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
184181
185182 try expect(fComplexCallconvRet(3).x == 9);
......@@ -255,7 +252,6 @@ test "pass by non-copying value as method, at comptime" {
255252
256253test "implicit cast fn call result to optional in field result" {
257254 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
258 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
259255 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
260256 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
261257
......@@ -283,7 +279,6 @@ test "implicit cast fn call result to optional in field result" {
283279
284280test "void parameters" {
285281 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
286 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
287282
288283 try voidFun(1, void{}, 2, {});
289284}
......@@ -306,7 +301,6 @@ fn acceptsString(foo: []u8) void {
306301}
307302
308303test "function pointers" {
309 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
310304 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
311305 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
312306 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -345,7 +339,6 @@ fn numberLiteralArg(a: anytype) !void {
345339
346340test "function call with anon list literal" {
347341 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
348 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
349342 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
350343
351344 const S = struct {
......@@ -365,7 +358,6 @@ test "function call with anon list literal" {
365358
366359test "function call with anon list literal - 2D" {
367360 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
368 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
369361 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
370362
371363 const S = struct {
......@@ -426,7 +418,6 @@ test "import passed byref to function in return type" {
426418
427419test "implicit cast function to function ptr" {
428420 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
429 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
430421 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
431422 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
432423
......@@ -485,7 +476,6 @@ test "method call with optional pointer first param" {
485476
486477test "using @ptrCast on function pointers" {
487478 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
488 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
489479 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
490480 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
491481
......@@ -524,8 +514,6 @@ test "function returns function returning type" {
524514}
525515
526516test "peer type resolution of inferred error set with non-void payload" {
527 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
528
529517 const S = struct {
530518 fn openDataFile(mode: enum { read, write }) !u32 {
531519 return switch (mode) {
......@@ -582,7 +570,6 @@ test "pass and return comptime-only types" {
582570
583571test "pointer to alias behaves same as pointer to function" {
584572 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
585 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
586573 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
587574
588575 const S = struct {
test/behavior/for.zig-20
......@@ -5,7 +5,6 @@ const expectEqual = std.testing.expectEqual;
55const mem = std.mem;
66
77test "continue in for loop" {
8 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
98 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
109
1110 const array = [_]i32{ 1, 2, 3, 4, 5 };
......@@ -67,7 +66,6 @@ test "ignore lval with underscore (for loop)" {
6766
6867test "basic for loop" {
6968 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
70 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
7169 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
7270 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
7371
......@@ -111,7 +109,6 @@ test "basic for loop" {
111109
112110test "for with null and T peer types and inferred result location type" {
113111 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
114 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
115112 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
116113 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
117114
......@@ -132,7 +129,6 @@ test "for with null and T peer types and inferred result location type" {
132129}
133130
134131test "2 break statements and an else" {
135 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
136132 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
137133
138134 const S = struct {
......@@ -152,7 +148,6 @@ test "2 break statements and an else" {
152148}
153149
154150test "for loop with pointer elem var" {
155 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
156151 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
157152 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
158153 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -180,7 +175,6 @@ fn mangleString(s: []u8) void {
180175}
181176
182177test "for copies its payload" {
183 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
184178 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
185179
186180 const S = struct {
......@@ -198,7 +192,6 @@ test "for copies its payload" {
198192}
199193
200194test "for on slice with allowzero ptr" {
201 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
202195 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
203196 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
204197 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -215,7 +208,6 @@ test "for on slice with allowzero ptr" {
215208}
216209
217210test "else continue outer for" {
218 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
219211 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
220212 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
221213
......@@ -230,8 +222,6 @@ test "else continue outer for" {
230222}
231223
232224test "for loop with else branch" {
233 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
234
235225 {
236226 var x = [_]u32{ 1, 2 };
237227 _ = &x;
......@@ -312,7 +302,6 @@ test "1-based counter and ptr to array" {
312302test "slice and two counters, one is offset and one is runtime" {
313303 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
314304 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
315 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
316305 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
317306
318307 const slice: []const u8 = "blah";
......@@ -342,7 +331,6 @@ test "slice and two counters, one is offset and one is runtime" {
342331test "two slices, one captured by-ref" {
343332 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
344333 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
345 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
346334 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
347335
348336 var buf: [10]u8 = undefined;
......@@ -362,7 +350,6 @@ test "two slices, one captured by-ref" {
362350test "raw pointer and slice" {
363351 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
364352 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
365 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
366353 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
367354
368355 var buf: [10]u8 = undefined;
......@@ -382,7 +369,6 @@ test "raw pointer and slice" {
382369test "raw pointer and counter" {
383370 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
384371 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
385 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
386372 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
387373
388374 var buf: [10]u8 = undefined;
......@@ -401,7 +387,6 @@ test "raw pointer and counter" {
401387test "inline for with slice as the comptime-known" {
402388 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
403389 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
404 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
405390
406391 const comptime_slice = "hello";
407392 var runtime_i: usize = 3;
......@@ -432,7 +417,6 @@ test "inline for with slice as the comptime-known" {
432417test "inline for with counter as the comptime-known" {
433418 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
434419 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
435 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
436420 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
437421
438422 var runtime_slice = "hello";
......@@ -464,7 +448,6 @@ test "inline for with counter as the comptime-known" {
464448test "inline for on tuple pointer" {
465449 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
466450 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
467 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
468451 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
469452
470453 const S = struct { u32, u32, u32 };
......@@ -480,7 +463,6 @@ test "inline for on tuple pointer" {
480463test "ref counter that starts at zero" {
481464 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
482465 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
483 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
484466
485467 for ([_]usize{ 0, 1, 2 }, 0..) |i, j| {
486468 try expectEqual(i, j);
......@@ -495,7 +477,6 @@ test "ref counter that starts at zero" {
495477test "inferred alloc ptr of for loop" {
496478 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
497479 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
498 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
499480
500481 {
501482 var cond = false;
......@@ -516,7 +497,6 @@ test "inferred alloc ptr of for loop" {
516497}
517498
518499test "for loop results in a bool" {
519 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
520500 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
521501
522502 try std.testing.expect(for ([1]u8{0}) |x| {
test/behavior/generics.zig+1-18
......@@ -17,7 +17,6 @@ fn checkSize(comptime T: type) usize {
1717}
1818
1919test "simple generic fn" {
20 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2120 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2221
2322 try expect(max(i32, 3, -1) == 3);
......@@ -53,7 +52,6 @@ fn sameButWithFloats(a: f64, b: f64) f64 {
5352
5453test "fn with comptime args" {
5554 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
56 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
5755 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
5856
5957 try expect(gimmeTheBigOne(1234, 5678) == 5678);
......@@ -63,7 +61,6 @@ test "fn with comptime args" {
6361
6462test "anytype params" {
6563 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
66 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
6764 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
6865
6966 try expect(max_i32(12, 34) == 34);
......@@ -87,7 +84,6 @@ fn max_f64(a: f64, b: f64) f64 {
8784}
8885
8986test "type constructed by comptime function call" {
90 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
9187 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
9288 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
9389 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -113,7 +109,6 @@ fn SimpleList(comptime L: usize) type {
113109
114110test "function with return type type" {
115111 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
116 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
117112 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
118113
119114 var list: List(i32) = undefined;
......@@ -154,7 +149,6 @@ fn aGenericFn(comptime T: type, comptime a: T, b: T) T {
154149
155150test "generic fn with implicit cast" {
156151 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
157 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
158152 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
159153 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
160154
......@@ -173,7 +167,6 @@ fn getFirstByte(comptime T: type, mem: []const T) u8 {
173167
174168test "generic fn keeps non-generic parameter types" {
175169 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
176 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
177170 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
178171 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
179172
......@@ -249,7 +242,6 @@ test "function parameter is generic" {
249242}
250243
251244test "generic function instantiation turns into comptime call" {
252 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
253245 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
254246 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
255247 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -300,7 +292,6 @@ test "generic function with void and comptime parameter" {
300292}
301293
302294test "anonymous struct return type referencing comptime parameter" {
303 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
304295 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
305296
306297 const S = struct {
......@@ -318,7 +309,6 @@ test "anonymous struct return type referencing comptime parameter" {
318309
319310test "generic function instantiation non-duplicates" {
320311 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
321 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
322312 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
323313 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
324314
......@@ -339,7 +329,6 @@ test "generic function instantiation non-duplicates" {
339329
340330test "generic instantiation of tagged union with only one field" {
341331 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
342 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
343332
344333 if (builtin.os.tag == .wasi) return error.SkipZigTest;
345334
......@@ -439,8 +428,6 @@ test "null sentinel pointer passed as generic argument" {
439428}
440429
441430test "generic function passed as comptime argument" {
442 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
443
444431 const S = struct {
445432 fn doMath(comptime f: fn (comptime type, i32, i32) error{Overflow}!i32, a: i32, b: i32) !void {
446433 const result = try f(i32, a, b);
......@@ -451,7 +438,6 @@ test "generic function passed as comptime argument" {
451438}
452439
453440test "return type of generic function is function pointer" {
454 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
455441 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
456442
457443 const S = struct {
......@@ -464,8 +450,6 @@ test "return type of generic function is function pointer" {
464450}
465451
466452test "coerced function body has inequal value with its uncoerced body" {
467 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
468
469453 const S = struct {
470454 const A = B(i32, c);
471455 fn c() !i32 {
......@@ -513,7 +497,6 @@ test "union in struct captures argument" {
513497
514498test "function argument tuple used as struct field" {
515499 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
516 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
517500 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
518501
519502 const S = struct {
......@@ -546,8 +529,8 @@ test "comptime callconv(.c) function ptr uses comptime type argument" {
546529}
547530
548531test "call generic function with from function called by the generic function" {
549 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
550532 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
533 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
551534 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
552535
553536 const GET = struct {
test/behavior/globals.zig+2-4
......@@ -6,7 +6,6 @@ var pos = [2]f32{ 0.0, 0.0 };
66test "store to global array" {
77 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
88 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
9 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
109
1110 try expect(pos[1] == 0.0);
1211 pos = [2]f32{ 0.0, 1.0 };
......@@ -15,9 +14,9 @@ test "store to global array" {
1514
1615var vpos = @Vector(2, f32){ 0.0, 0.0 };
1716test "store to global vector" {
17 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1818 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
1919 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
20 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2120
2221 try expect(vpos[1] == 0.0);
2322 vpos = @Vector(2, f32){ 0.0, 1.0 };
......@@ -26,7 +25,6 @@ test "store to global vector" {
2625
2726test "slices pointing at the same address as global array." {
2827 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
29 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
3028 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
3129 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
3230
......@@ -47,7 +45,6 @@ test "slices pointing at the same address as global array." {
4745test "global loads can affect liveness" {
4846 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
4947 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
50 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
5148
5249 const S = struct {
5350 const ByRef = struct {
......@@ -188,6 +185,7 @@ test "function pointer field call on global extern struct, conditional on global
188185}
189186
190187test "function pointer field call on global extern struct" {
188 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
191189 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
192190
193191 const S = struct {
test/behavior/if.zig+4-2
......@@ -116,7 +116,6 @@ test "if prongs cast to expected type instead of peer type resolution" {
116116
117117test "if peer expressions inferred optional type" {
118118 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
119 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
120119 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
121120 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
122121
......@@ -135,7 +134,6 @@ test "if peer expressions inferred optional type" {
135134
136135test "if-else expression with runtime condition result location is inferred optional" {
137136 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
138 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
139137 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
140138
141139 const A = struct { b: u64, c: u64 };
......@@ -174,6 +172,8 @@ fn returnTrue() bool {
174172}
175173
176174test "if value shouldn't be load-elided if used later (structs)" {
175 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
176
177177 const Foo = struct { x: i32 };
178178
179179 var a = Foo{ .x = 1 };
......@@ -191,6 +191,8 @@ test "if value shouldn't be load-elided if used later (structs)" {
191191}
192192
193193test "if value shouldn't be load-elided if used later (optionals)" {
194 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
195
194196 var a: ?i32 = 1;
195197 var b: ?i32 = 1;
196198
test/behavior/import_c_keywords.zig-1
......@@ -27,7 +27,6 @@ extern fn @"break"() Id;
2727extern fn an_alias_of_some_non_c_keyword_function() Id;
2828
2929test "import c keywords" {
30 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
3130 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
3231 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
3332 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
test/behavior/inline_switch.zig-9
......@@ -3,7 +3,6 @@ const expect = std.testing.expect;
33const builtin = @import("builtin");
44
55test "inline scalar prongs" {
6 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
76 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
87
98 var x: usize = 0;
......@@ -18,7 +17,6 @@ test "inline scalar prongs" {
1817}
1918
2019test "inline prong ranges" {
21 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2220 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2321
2422 var x: usize = 0;
......@@ -33,7 +31,6 @@ test "inline prong ranges" {
3331
3432const E = enum { a, b, c, d };
3533test "inline switch enums" {
36 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
3734 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
3835
3936 var x: E = .a;
......@@ -46,7 +43,6 @@ test "inline switch enums" {
4643
4744const U = union(E) { a: void, b: u2, c: u3, d: u4 };
4845test "inline switch unions" {
49 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
5046 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
5147 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
5248
......@@ -73,7 +69,6 @@ test "inline switch unions" {
7369}
7470
7571test "inline else bool" {
76 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
7772 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
7873
7974 var a = true;
......@@ -85,7 +80,6 @@ test "inline else bool" {
8580}
8681
8782test "inline else error" {
88 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
8983 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
9084
9185 const Err = error{ a, b, c };
......@@ -98,7 +92,6 @@ test "inline else error" {
9892}
9993
10094test "inline else enum" {
101 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10295 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10396
10497 const E2 = enum(u8) { a = 2, b = 3, c = 4, d = 5 };
......@@ -111,7 +104,6 @@ test "inline else enum" {
111104}
112105
113106test "inline else int with gaps" {
114 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
115107 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
116108 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
117109
......@@ -130,7 +122,6 @@ test "inline else int with gaps" {
130122}
131123
132124test "inline else int all values" {
133 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
134125 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
135126
136127 var a: u2 = 0;
test/behavior/int128.zig-5
......@@ -5,7 +5,6 @@ const minInt = std.math.minInt;
55const builtin = @import("builtin");
66
77test "uint128" {
8 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
98 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
109 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1110 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -25,7 +24,6 @@ test "uint128" {
2524}
2625
2726test "undefined 128 bit int" {
28 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2927 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
3028 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
3129 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -45,7 +43,6 @@ test "undefined 128 bit int" {
4543}
4644
4745test "int128" {
48 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
4946 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
5047 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
5148 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -68,7 +65,6 @@ test "int128" {
6865}
6966
7067test "truncate int128" {
71 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
7268 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
7369 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
7470 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -92,7 +88,6 @@ test "truncate int128" {
9288}
9389
9490test "shift int128" {
95 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
9691 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
9792 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
9893 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
test/behavior/int_comparison_elision.zig-1
......@@ -15,7 +15,6 @@ test "int comparison elision" {
1515
1616 // TODO: support int types > 128 bits wide in other backends
1717 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
18 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1918 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2019 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
2120
test/behavior/ir_block_deps.zig-1
......@@ -18,7 +18,6 @@ fn getErrInt() anyerror!i32 {
1818}
1919
2020test "ir block deps" {
21 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2221 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2322 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2423
test/behavior/lower_strlit_to_vector.zig-1
......@@ -3,7 +3,6 @@ const builtin = @import("builtin");
33
44test "strlit to vector" {
55 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
6 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
76 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
87 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
98 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
test/behavior/math.zig+23-49
......@@ -62,11 +62,11 @@ fn assertFalse(b: bool) !void {
6262}
6363
6464test "@clz" {
65 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
6665 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
6766 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
6867 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
6968 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
69
7070 try testClz();
7171 try comptime testClz();
7272}
......@@ -80,7 +80,6 @@ fn testClz() !void {
8080}
8181
8282test "@clz big ints" {
83 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
8483 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
8584 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
8685 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -100,8 +99,8 @@ fn testOneClz(comptime T: type, x: T) u32 {
10099}
101100
102101test "@clz vectors" {
102 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
103103 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
104 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
105104 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
106105 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
107106 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -146,7 +145,6 @@ fn expectVectorsEqual(a: anytype, b: anytype) !void {
146145}
147146
148147test "@ctz" {
149 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
150148 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
151149 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
152150 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -170,7 +168,7 @@ fn testOneCtz(comptime T: type, x: T) u32 {
170168}
171169
172170test "@ctz 128-bit integers" {
173 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
171 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
174172 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
175173 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
176174 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -188,8 +186,8 @@ fn testCtz128() !void {
188186}
189187
190188test "@ctz vectors" {
189 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
191190 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
192 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
193191 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
194192 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
195193 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -227,7 +225,6 @@ test "const number literal" {
227225const ten = 10;
228226
229227test "float equality" {
230 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
231228 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
232229 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
233230
......@@ -433,7 +430,6 @@ test "binary not" {
433430}
434431
435432test "binary not big int <= 128 bits" {
436 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
437433 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
438434 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
439435 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -467,7 +463,7 @@ test "binary not big int <= 128 bits" {
467463}
468464
469465test "division" {
470 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
466 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
471467 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
472468 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
473469 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -609,7 +605,6 @@ test "large integer division" {
609605}
610606
611607test "division half-precision floats" {
612 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
613608 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
614609 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
615610 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -696,7 +691,6 @@ fn testUnsignedNegationWrappingEval(x: u16) !void {
696691}
697692
698693test "negation wrapping" {
699 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
700694 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
701695 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
702696
......@@ -749,7 +743,6 @@ fn testShrTrunc(x: u16) !void {
749743}
750744
751745test "f128" {
752 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
753746 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
754747 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
755748 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -778,6 +771,7 @@ fn should_not_be_zero(x: f128) !void {
778771}
779772
780773test "umax wrapped squaring" {
774 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
781775 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
782776 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
783777
......@@ -834,7 +828,6 @@ test "umax wrapped squaring" {
834828}
835829
836830test "128-bit multiplication" {
837 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
838831 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
839832 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
840833 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 {
869862}
870863
871864test "@addWithOverflow" {
872 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
873865 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
874866 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
875867 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
......@@ -888,7 +880,6 @@ test "@addWithOverflow" {
888880}
889881
890882test "@addWithOverflow > 64 bits" {
891 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
892883 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
893884 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
894885 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 {
960951}
961952
962953test "basic @mulWithOverflow" {
963 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
954 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
964955 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
965956 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
966957
......@@ -972,7 +963,7 @@ test "basic @mulWithOverflow" {
972963}
973964
974965test "extensive @mulWithOverflow" {
975 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
966 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
976967 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
977968 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
978969 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1012,11 +1003,9 @@ test "extensive @mulWithOverflow" {
10121003}
10131004
10141005test "@mulWithOverflow bitsize > 32" {
1015 if (builtin.zig_backend == .stage2_riscv64) 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
1006 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
10191007 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1008 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
10201009 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10211010
10221011 try testMulWithOverflow(u40, 3, 0x55_5555_5555, 0xff_ffff_ffff, 0);
......@@ -1043,9 +1032,9 @@ test "@mulWithOverflow bitsize > 32" {
10431032}
10441033
10451034test "@mulWithOverflow bitsize 128 bits" {
1035 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
10461036 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
10471037 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1048 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10491038 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10501039 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10511040 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
......@@ -1070,6 +1059,7 @@ test "@mulWithOverflow bitsize 128 bits" {
10701059}
10711060
10721061test "@mulWithOverflow bitsize 256 bits" {
1062 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
10731063 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
10741064 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
10751065 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 {
11161106}
11171107
11181108test "@subWithOverflow" {
1119 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
11201109 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11211110 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11221111
......@@ -1133,7 +1122,6 @@ test "@subWithOverflow" {
11331122}
11341123
11351124test "@subWithOverflow > 64 bits" {
1136 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
11371125 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11381126 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11391127 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:
11811169}
11821170
11831171test "@shlWithOverflow" {
1184 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1172 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
11851173 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11861174 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
11871175 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1200,7 +1188,7 @@ test "@shlWithOverflow" {
12001188}
12011189
12021190test "@shlWithOverflow > 64 bits" {
1203 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1191 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
12041192 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
12051193 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
12061194 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
12691257}
12701258
12711259test "quad hex float literal parsing accurate" {
1272 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
12731260 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
12741261 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
12751262 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1427,8 +1414,8 @@ test "comptime float rem int" {
14271414}
14281415
14291416test "remainder division" {
1417 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
14301418 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1431 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
14321419 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
14331420 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
14341421 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 {
14671454
14681455test "float remainder division using @rem" {
14691456 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1470 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
14711457 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
14721458 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
14731459 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 {
15081494}
15091495
15101496test "float modulo division using @mod" {
1497 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
15111498 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1512 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
15131499 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
15141500 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
15151501 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 {
15521538
15531539test "@round f16" {
15541540 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1555 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
15561541 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
15571542 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
15581543
......@@ -1562,7 +1547,6 @@ test "@round f16" {
15621547
15631548test "@round f32/f64" {
15641549 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1565 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
15661550 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
15671551 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
15681552
......@@ -1579,7 +1563,6 @@ test "@round f32/f64" {
15791563
15801564test "@round f80" {
15811565 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1582 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
15831566 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
15841567 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
15851568 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
......@@ -1591,7 +1574,6 @@ test "@round f80" {
15911574
15921575test "@round f128" {
15931576 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1594 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
15951577 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
15961578 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
15971579 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 {
16081590}
16091591
16101592test "vector integer addition" {
1593 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
16111594 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
16121595 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1613 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
16141596 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
16151597 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
16161598 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1632,7 +1614,6 @@ test "vector integer addition" {
16321614
16331615test "NaN comparison" {
16341616 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1635 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
16361617 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
16371618 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
16381619 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1650,7 +1631,6 @@ test "NaN comparison" {
16501631
16511632test "NaN comparison f80" {
16521633 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1653 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
16541634 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
16551635 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
16561636 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1672,9 +1652,9 @@ fn testNanEqNan(comptime F: type) !void {
16721652}
16731653
16741654test "vector comparison" {
1655 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
16751656 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
16761657 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1677 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
16781658 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
16791659 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
16801660 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1705,7 +1685,6 @@ test "compare undefined literal with comptime_int" {
17051685
17061686test "signed zeros are represented properly" {
17071687 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1708 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
17091688 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
17101689 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
17111690 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1737,7 +1716,6 @@ test "signed zeros are represented properly" {
17371716
17381717test "absFloat" {
17391718 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1740 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
17411719 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
17421720
17431721 try testAbsFloat();
......@@ -1767,8 +1745,8 @@ test "mod lazy values" {
17671745}
17681746
17691747test "@clz works on both vector and scalar inputs" {
1748 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
17701749 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1771 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
17721750 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
17731751 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
17741752 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1786,7 +1764,6 @@ test "@clz works on both vector and scalar inputs" {
17861764
17871765test "runtime comparison to NaN is comptime-known" {
17881766 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1789 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
17901767 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
17911768 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
17921769 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1816,7 +1793,6 @@ test "runtime comparison to NaN is comptime-known" {
18161793
18171794test "runtime int comparison to inf is comptime-known" {
18181795 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1819 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
18201796 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
18211797 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
18221798 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1845,8 +1821,8 @@ test "runtime int comparison to inf is comptime-known" {
18451821}
18461822
18471823test "float divide by zero" {
1824 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
18481825 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1849 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
18501826 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
18511827 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
18521828 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1880,8 +1856,8 @@ test "float divide by zero" {
18801856}
18811857
18821858test "partially-runtime integer vector division would be illegal if vector elements were reordered" {
1859 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
18831860 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1884 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
18851861 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
18861862 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
18871863 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
19091885}
19101886
19111887test "float vector division of comptime zero by runtime nan is nan" {
1888 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
19121889 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1913 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
19141890 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
19151891 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
19161892 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" {
19271903}
19281904
19291905test "float vector multiplication of comptime zero by runtime nan is nan" {
1906 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
19301907 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1931 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
19321908 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
19331909 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
19341910 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" {
19451921
19461922test "comptime float vector division of zero by nan is nan" {
19471923 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1948 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
19491924 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
19501925 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
19511926 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1961,7 +1936,6 @@ test "comptime float vector division of zero by nan is nan" {
19611936
19621937test "comptime float vector multiplication of zero by nan is nan" {
19631938 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1964 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
19651939 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
19661940 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
19671941 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
test/behavior/maximum_minimum.zig+7-15
......@@ -7,7 +7,6 @@ const expectEqual = std.testing.expectEqual;
77
88test "@max" {
99 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1110 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1211 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1312
......@@ -28,9 +27,9 @@ test "@max" {
2827}
2928
3029test "@max on vectors" {
30 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
3131 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
3232 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
33 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
3433 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
3534 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
3635 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -61,7 +60,6 @@ test "@max on vectors" {
6160}
6261
6362test "@min" {
64 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
6563 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
6664 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
6765 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -83,8 +81,8 @@ test "@min" {
8381}
8482
8583test "@min for vectors" {
84 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
8685 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
87 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
8886 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
8987 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
9088 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -116,7 +114,6 @@ test "@min for vectors" {
116114}
117115
118116test "@min/max for floats" {
119 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
120117 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
121118 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
122119 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -167,8 +164,8 @@ test "@min/@max more than two arguments" {
167164}
168165
169166test "@min/@max more than two vector arguments" {
167 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
170168 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
171 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
172169 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
173170 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
174171 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -181,7 +178,6 @@ test "@min/@max more than two vector arguments" {
181178}
182179
183180test "@min/@max notices bounds" {
184 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
185181 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
186182 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
187183
......@@ -198,8 +194,8 @@ test "@min/@max notices bounds" {
198194}
199195
200196test "@min/@max notices vector bounds" {
197 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
201198 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
202 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
203199 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
204200 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
205201 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -217,7 +213,6 @@ test "@min/@max notices vector bounds" {
217213}
218214
219215test "@min/@max on comptime_int" {
220 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
221216 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
222217 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
223218
......@@ -231,7 +226,6 @@ test "@min/@max on comptime_int" {
231226}
232227
233228test "@min/@max notices bounds from types" {
234 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
235229 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
236230 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
237231
......@@ -251,8 +245,8 @@ test "@min/@max notices bounds from types" {
251245}
252246
253247test "@min/@max notices bounds from vector types" {
248 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
254249 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
255 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
256250 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
257251 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
258252 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -273,7 +267,6 @@ test "@min/@max notices bounds from vector types" {
273267}
274268
275269test "@min/@max notices bounds from types when comptime-known value is undef" {
276 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
277270 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
278271 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
279272 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -293,8 +286,8 @@ test "@min/@max notices bounds from types when comptime-known value is undef" {
293286}
294287
295288test "@min/@max notices bounds from vector types when element of comptime-known vector is undef" {
289 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
296290 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
297 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
298291 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
299292 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
300293 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -333,7 +326,6 @@ test "@min/@max of signed and unsigned runtime integers" {
333326}
334327
335328test "@min resulting in u0" {
336 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
337329 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
338330 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
339331
......@@ -364,8 +356,8 @@ test "@min/@max with runtime signed and unsigned integers of same size" {
364356}
365357
366358test "@min/@max with runtime vectors of signed and unsigned integers of same size" {
359 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
367360 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
368 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
369361 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
370362 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
371363 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
test/behavior/member_func.zig-2
......@@ -28,7 +28,6 @@ const HasFuncs = struct {
2828
2929test "standard field calls" {
3030 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
31 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
3231 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
3332 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
3433
......@@ -72,7 +71,6 @@ test "standard field calls" {
7271
7372test "@field field calls" {
7473 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
75 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
7674 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
7775 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
7876
test/behavior/memcpy.zig+1-4
......@@ -4,7 +4,6 @@ const expect = std.testing.expect;
44const assert = std.debug.assert;
55
66test "memcpy and memset intrinsics" {
7 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
87 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
98 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
109 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -26,7 +25,6 @@ fn testMemcpyMemset() !void {
2625}
2726
2827test "@memcpy with both operands single-ptr-to-array, one is null-terminated" {
29 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
3028 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
3129 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
3230 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -47,7 +45,6 @@ fn testMemcpyBothSinglePtrArrayOneIsNullTerminated() !void {
4745}
4846
4947test "@memcpy dest many pointer" {
50 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
5148 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
5249 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
5350 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -70,7 +67,6 @@ fn testMemcpyDestManyPtr() !void {
7067}
7168
7269test "@memcpy C pointer" {
73 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
7470 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
7571 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
7672 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -156,6 +152,7 @@ test "@memcpy zero-bit type with aliasing" {
156152}
157153
158154test "@memcpy with sentinel" {
155 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
159156 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
160157
161158 const S = struct {
test/behavior/memmove.zig-3
......@@ -3,7 +3,6 @@ const builtin = @import("builtin");
33const expect = std.testing.expect;
44
55test "memmove and memset intrinsics" {
6 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
76 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
87 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
98 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -32,7 +31,6 @@ fn testMemmoveMemset() !void {
3231}
3332
3433test "@memmove with both operands single-ptr-to-array, one is null-terminated" {
35 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
3634 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
3735 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
3836 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -77,7 +75,6 @@ fn testMemmoveBothSinglePtrArrayOneIsNullTerminated() !void {
7775}
7876
7977test "@memmove dest many pointer" {
80 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
8178 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
8279 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
8380 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
test/behavior/memset.zig-7
......@@ -3,7 +3,6 @@ const builtin = @import("builtin");
33const expect = std.testing.expect;
44
55test "@memset on array pointers" {
6 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
76 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
87 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
98 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -32,7 +31,6 @@ fn testMemsetArray() !void {
3231}
3332
3433test "@memset on slices" {
35 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
3634 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
3735 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
3836 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -68,7 +66,6 @@ fn testMemsetSlice() !void {
6866}
6967
7068test "memset with bool element" {
71 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
7269 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
7370 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
7471 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -80,7 +77,6 @@ test "memset with bool element" {
8077}
8178
8279test "memset with 1-byte struct element" {
83 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
8480 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
8581 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
8682 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -94,7 +90,6 @@ test "memset with 1-byte struct element" {
9490}
9591
9692test "memset with 1-byte array element" {
97 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
9893 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
9994 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
10095 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -145,7 +140,6 @@ test "memset with large array element, comptime known" {
145140}
146141
147142test "@memset provides result type" {
148 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
149143 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
150144 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
151145 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -164,7 +158,6 @@ test "@memset provides result type" {
164158}
165159
166160test "zero keys with @memset" {
167 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
168161 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
169162 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
170163 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
test/behavior/muladd.zig+5-9
......@@ -4,7 +4,6 @@ const expect = std.testing.expect;
44
55test "@mulAdd" {
66 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
7 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
87 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
98 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
109 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -32,7 +31,6 @@ fn testMulAdd() !void {
3231
3332test "@mulAdd f16" {
3433 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
35 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
3634 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
3735 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
3836 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -51,7 +49,6 @@ fn testMulAdd16() !void {
5149
5250test "@mulAdd f80" {
5351 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
54 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
5552 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
5653 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
5754 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
......@@ -71,7 +68,6 @@ fn testMulAdd80() !void {
7168
7269test "@mulAdd f128" {
7370 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
74 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
7571 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
7672 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
7773 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
......@@ -103,9 +99,9 @@ fn vector16() !void {
10399}
104100
105101test "vector f16" {
102 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
106103 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
107104 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
108 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
109105 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
110106 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
111107 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -128,9 +124,9 @@ fn vector32() !void {
128124}
129125
130126test "vector f32" {
127 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
131128 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
132129 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
133 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
134130 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
135131 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
136132 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -153,9 +149,9 @@ fn vector64() !void {
153149}
154150
155151test "vector f64" {
152 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
156153 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
157154 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
158 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
159155 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
160156 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
161157 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -177,9 +173,9 @@ fn vector80() !void {
177173}
178174
179175test "vector f80" {
176 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
180177 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
181178 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
182 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
183179 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
184180 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
185181 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
......@@ -203,9 +199,9 @@ fn vector128() !void {
203199}
204200
205201test "vector f128" {
202 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
206203 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
207204 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
208 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
209205 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
210206 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
211207 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
test/behavior/multiple_externs_with_conflicting_types.zig-1
......@@ -11,7 +11,6 @@ comptime {
1111const builtin = @import("builtin");
1212
1313test "call extern function defined with conflicting type" {
14 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1514 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1615 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1716 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
test/behavior/nan.zig-1
......@@ -23,7 +23,6 @@ const snan_f128: f128 = math.snan(f128);
2323
2424test "nan memory equality" {
2525 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
26 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2726 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
2827 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
2928
test/behavior/null.zig+2-4
......@@ -29,8 +29,8 @@ test "optional type" {
2929}
3030
3131test "test maybe object and get a pointer to the inner value" {
32 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
3332 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
33 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
3434 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
3535 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
3636
......@@ -51,7 +51,6 @@ test "rhs maybe unwrap return" {
5151
5252test "maybe return" {
5353 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
54 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
5554 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
5655
5756 try maybeReturnImpl();
......@@ -140,8 +139,8 @@ test "optional pointer to 0 bit type null value at runtime" {
140139}
141140
142141test "if var maybe pointer" {
143 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
144142 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
143 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
145144 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
146145 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
147146
......@@ -185,7 +184,6 @@ const here_is_a_null_literal = SillyStruct{ .context = null };
185184
186185test "unwrap optional which is field of global var" {
187186 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
188 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
189187 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
190188
191189 struct_with_optional.field = null;
test/behavior/optional.zig+8-12
......@@ -59,6 +59,7 @@ fn testNullPtrsEql() !void {
5959}
6060
6161test "optional with zero-bit type" {
62 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
6263 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
6364
6465 const S = struct {
......@@ -109,7 +110,6 @@ test "optional with zero-bit type" {
109110}
110111
111112test "address of unwrap optional" {
112 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
113113 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
114114 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
115115 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -132,7 +132,6 @@ test "address of unwrap optional" {
132132}
133133
134134test "nested optional field in struct" {
135 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
136135 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
137136 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
138137
......@@ -210,6 +209,7 @@ test "equality compare optionals and non-optionals" {
210209}
211210
212211test "compare optionals with modified payloads" {
212 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
213213 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
214214
215215 var lhs: ?bool = false;
......@@ -319,7 +319,6 @@ test "assigning to an unwrapped optional field in an inline loop" {
319319}
320320
321321test "coerce an anon struct literal to optional struct" {
322 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
323322 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
324323 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
325324 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -339,7 +338,6 @@ test "coerce an anon struct literal to optional struct" {
339338}
340339
341340test "0-bit child type coerced to optional return ptr result location" {
342 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
343341 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
344342 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" {
365363}
366364
367365test "0-bit child type coerced to optional" {
366 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
368367 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
369368 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
370369
......@@ -391,7 +390,7 @@ test "0-bit child type coerced to optional" {
391390}
392391
393392test "array of optional unaligned types" {
394 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
393 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
395394 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
396395 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
397396 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -428,8 +427,8 @@ test "array of optional unaligned types" {
428427}
429428
430429test "optional pointer to zero bit optional payload" {
430 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
431431 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
432 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
433432 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
434433 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
435434
......@@ -448,7 +447,6 @@ test "optional pointer to zero bit optional payload" {
448447
449448test "optional pointer to zero bit error union payload" {
450449 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
451 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
452450 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
453451 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
454452 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -543,7 +541,6 @@ test "alignment of wrapping an optional payload" {
543541}
544542
545543test "Optional slice size is optimized" {
546 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
547544 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
548545 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
549546 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -556,7 +553,7 @@ test "Optional slice size is optimized" {
556553}
557554
558555test "Optional slice passed to function" {
559 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
556 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
560557 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
561558 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
562559 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -574,7 +571,6 @@ test "Optional slice passed to function" {
574571}
575572
576573test "peer type resolution in nested if expressions" {
577 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
578574 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
579575
580576 const Thing = struct { n: i32 };
......@@ -623,8 +619,8 @@ test "variable of optional of noreturn" {
623619}
624620
625621test "copied optional doesn't alias source" {
622 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
626623 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
627 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
628624 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
629625 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
630626
......@@ -637,8 +633,8 @@ test "copied optional doesn't alias source" {
637633}
638634
639635test "result location initialization of optional with OPV payload" {
636 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
640637 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
641 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
642638 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
643639 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
644640 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
test/behavior/packed-struct.zig+24-22
......@@ -120,7 +120,6 @@ test "consistent size of packed structs" {
120120}
121121
122122test "correct sizeOf and offsets in packed structs" {
123 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
124123 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
125124 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
126125
......@@ -187,7 +186,6 @@ test "correct sizeOf and offsets in packed structs" {
187186}
188187
189188test "nested packed structs" {
190 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
191189 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
192190 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
193191
......@@ -484,7 +482,6 @@ test "load pointer from packed struct" {
484482}
485483
486484test "@intFromPtr on a packed struct field" {
487 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
488485 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
489486 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
490487 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -507,7 +504,6 @@ test "@intFromPtr on a packed struct field" {
507504}
508505
509506test "@intFromPtr on a packed struct field unaligned and nested" {
510 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
511507 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
512508 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
513509 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -617,6 +613,7 @@ test "@intFromPtr on a packed struct field unaligned and nested" {
617613}
618614
619615test "packed struct fields modification" {
616 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
620617 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
621618
622619 // Originally reported at https://github.com/ziglang/zig/issues/16615
......@@ -656,9 +653,9 @@ test "optional pointer in packed struct" {
656653}
657654
658655test "nested packed struct field access test" {
656 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
659657 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
660658 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO packed structs larger than 64 bits
661 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
662659 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
663660 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
664661 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -777,6 +774,7 @@ test "nested packed struct field access test" {
777774}
778775
779776test "nested packed struct at non-zero offset" {
777 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
780778 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
781779 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
782780
......@@ -915,7 +913,6 @@ test "packed struct passed to callconv(.c) function" {
915913}
916914
917915test "overaligned pointer to packed struct" {
918 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
919916 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
920917 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
921918 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -937,7 +934,7 @@ test "overaligned pointer to packed struct" {
937934}
938935
939936test "packed struct initialized in bitcast" {
940 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
937 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
941938 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
942939 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
943940 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -986,8 +983,8 @@ test "store undefined to packed result location" {
986983 try expectEqual(x, s.x);
987984}
988985
986// Originally reported at https://github.com/ziglang/zig/issues/9914
989987test "bitcast back and forth" {
990 // Originally reported at https://github.com/ziglang/zig/issues/9914
991988 const S = packed struct { one: u6, two: u1 };
992989 const s = S{ .one = 0b110101, .two = 0b1 };
993990 const u: u7 = @bitCast(s);
......@@ -996,8 +993,9 @@ test "bitcast back and forth" {
996993 try expect(s.two == s2.two);
997994}
998995
996// Originally reported at https://github.com/ziglang/zig/issues/14200
999997test "field access of packed struct smaller than its abi size inside struct initialized with rls" {
1000 // Originally reported at https://github.com/ziglang/zig/issues/14200
998 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1001999 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
10021000 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
10031001
......@@ -1015,8 +1013,8 @@ test "field access of packed struct smaller than its abi size inside struct init
10151013 try expect(@as(i2, 1) == s.ps.y);
10161014}
10171015
1016// Originally reported at https://github.com/ziglang/zig/issues/14632
10181017test "modify nested packed struct aligned field" {
1019 // Originally reported at https://github.com/ziglang/zig/issues/14632
10201018 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
10211019 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
10221020 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
......@@ -1045,10 +1043,10 @@ test "modify nested packed struct aligned field" {
10451043 try std.testing.expect(!opts.baz);
10461044}
10471045
1046// Originally reported at https://github.com/ziglang/zig/issues/9674
10481047test "assigning packed struct inside another packed struct" {
1048 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
10491049 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1050
1051 // Originally reported at https://github.com/ziglang/zig/issues/9674
10521050 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
10531051
10541052 const S = struct {
......@@ -1078,7 +1076,6 @@ test "assigning packed struct inside another packed struct" {
10781076}
10791077
10801078test "packed struct used as part of anon decl name" {
1081 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10821079 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10831080 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10841081 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1104,7 +1101,13 @@ test "packed struct acts as a namespace" {
11041101}
11051102
11061103test "pointer loaded correctly from packed struct" {
1104 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1105 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
11071106 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1107 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
1108 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1109
1110 if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) return error.SkipZigTest; // crashes MSVC
11081111
11091112 const RAM = struct {
11101113 data: [0xFFFF + 1]u8,
......@@ -1132,12 +1135,6 @@ test "pointer loaded correctly from packed struct" {
11321135 }
11331136 }
11341137 };
1135 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1136 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1137 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
1138 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1139
1140 if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) return error.SkipZigTest; // crashes MSVC
11411138
11421139 var ram = try RAM.new();
11431140 var cpu = try CPU.new(&ram);
......@@ -1146,7 +1143,7 @@ test "pointer loaded correctly from packed struct" {
11461143}
11471144
11481145test "assignment to non-byte-aligned field in packed struct" {
1149 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1146 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
11501147 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11511148 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
11521149 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
......@@ -1167,7 +1164,6 @@ test "assignment to non-byte-aligned field in packed struct" {
11671164}
11681165
11691166test "packed struct field pointer aligned properly" {
1170 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
11711167 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11721168 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11731169 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
......@@ -1186,7 +1182,7 @@ test "packed struct field pointer aligned properly" {
11861182}
11871183
11881184test "load flag from packed struct in union" {
1189 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1185 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
11901186 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11911187 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11921188 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1311,6 +1307,7 @@ test "packed struct equality" {
13111307}
13121308
13131309test "packed struct equality ignores padding bits" {
1310 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
13141311 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
13151312 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
13161313
......@@ -1322,6 +1319,8 @@ test "packed struct equality ignores padding bits" {
13221319}
13231320
13241321test "packed struct with signed field" {
1322 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1323
13251324 var s: packed struct {
13261325 a: i2,
13271326 b: u6,
......@@ -1332,6 +1331,7 @@ test "packed struct with signed field" {
13321331}
13331332
13341333test "assign packed struct initialized with RLS to packed struct literal field" {
1334 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
13351335 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch.isWasm()) return error.SkipZigTest;
13361336 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
13371337 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1349,6 +1349,7 @@ test "assign packed struct initialized with RLS to packed struct literal field"
13491349}
13501350
13511351test "byte-aligned packed relocation" {
1352 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
13521353 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
13531354 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
13541355 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1363,6 +1364,7 @@ test "byte-aligned packed relocation" {
13631364}
13641365
13651366test "packed struct store of comparison result" {
1367 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
13661368 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
13671369 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
13681370
test/behavior/packed-union.zig+3-3
......@@ -99,10 +99,10 @@ fn testFlagsInPackedUnionAtOffset() !void {
9999 try expectEqual(false, test_bits.adv_flags.adv.flags.enable_2);
100100}
101101
102// Originally reported at https://github.com/ziglang/zig/issues/16581
102103test "packed union in packed struct" {
104 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
103105 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
104
105 // Originally reported at https://github.com/ziglang/zig/issues/16581
106106 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
107107
108108 try testPackedUnionInPackedStruct();
......@@ -136,7 +136,7 @@ fn testPackedUnionInPackedStruct() !void {
136136}
137137
138138test "packed union initialized with a runtime value" {
139 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
139 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
140140 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
141141 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
142142 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
test/behavior/packed_struct_explicit_backing_int.zig-1
......@@ -5,7 +5,6 @@ const expectEqual = std.testing.expectEqual;
55const native_endian = builtin.cpu.arch.endian();
66
77test "packed struct explicit backing integer" {
8 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
98 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
109 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1110
test/behavior/pointers.zig+1-13
......@@ -18,7 +18,6 @@ fn testDerefPtr() !void {
1818}
1919
2020test "pointer-integer arithmetic" {
21 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2221 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2322 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
2423 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -232,7 +231,6 @@ test "peer type resolution with C pointer and const pointer" {
232231
233232test "implicit casting between C pointer and optional non-C pointer" {
234233 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
235 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
236234 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
237235 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
238236 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -248,8 +246,8 @@ test "implicit casting between C pointer and optional non-C pointer" {
248246}
249247
250248test "implicit cast error unions with non-optional to optional pointer" {
249 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
251250 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
252 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
253251 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
254252 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
255253 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -298,7 +296,6 @@ test "allowzero pointer and slice" {
298296
299297test "assign null directly to C pointer and test null equality" {
300298 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
301 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
302299 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
303300 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
304301
......@@ -366,7 +363,6 @@ test "array initialization types" {
366363}
367364
368365test "null terminated pointer" {
369 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
370366 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
371367 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
372368
......@@ -384,7 +380,6 @@ test "null terminated pointer" {
384380}
385381
386382test "allow any sentinel" {
387 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
388383 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
389384 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
390385 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -401,7 +396,6 @@ test "allow any sentinel" {
401396}
402397
403398test "pointer sentinel with enums" {
404 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
405399 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
406400 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
407401 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -442,7 +436,6 @@ test "pointer sentinel with optional element" {
442436}
443437
444438test "pointer sentinel with +inf" {
445 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
446439 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
447440 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
448441 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -515,7 +508,6 @@ test "@intFromPtr on null optional at comptime" {
515508}
516509
517510test "indexing array with sentinel returns correct type" {
518 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
519511 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
520512 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
521513 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -525,7 +517,6 @@ test "indexing array with sentinel returns correct type" {
525517}
526518
527519test "element pointer to slice" {
528 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
529520 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
530521 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
531522
......@@ -548,7 +539,6 @@ test "element pointer to slice" {
548539}
549540
550541test "element pointer arithmetic to slice" {
551 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
552542 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
553543 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
554544
......@@ -604,7 +594,6 @@ test "pointer to constant decl preserves alignment" {
604594
605595test "ptrCast comptime known slice to C pointer" {
606596 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
607 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
608597 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
609598 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
610599
......@@ -625,7 +614,6 @@ test "pointer alignment and element type include call expression" {
625614}
626615
627616test "pointer to array has explicit alignment" {
628 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
629617 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
630618
631619 const S = struct {
test/behavior/popcount.zig+2-3
......@@ -4,7 +4,6 @@ const expect = std.testing.expect;
44const expectEqual = std.testing.expectEqual;
55
66test "@popCount integers" {
7 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
87 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
98 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
109 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -15,7 +14,7 @@ test "@popCount integers" {
1514}
1615
1716test "@popCount 128bit integer" {
18 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
17 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1918 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2019 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2120 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -77,8 +76,8 @@ fn testPopCountIntegers() !void {
7776}
7877
7978test "@popCount vectors" {
79 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
8080 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
81 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
8281 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
8382 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
8483 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
test/behavior/ptrcast.zig+10-19
......@@ -22,7 +22,6 @@ fn testReinterpretBytesAsInteger() !void {
2222
2323test "reinterpret an array over multiple elements, with no well-defined layout" {
2424 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
25 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2625 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2726 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
2827
......@@ -56,7 +55,6 @@ fn testReinterpretStructWrappedBytesAsInteger() !void {
5655}
5756
5857test "reinterpret bytes of an array into an extern struct" {
59 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
6058 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
6159 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
6260
......@@ -130,7 +128,6 @@ fn testReinterpretOverAlignedExternStructAsExternStruct() !void {
130128
131129test "lower reinterpreted comptime field ptr (with under-aligned fields)" {
132130 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
133 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
134131 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
135132
136133 // Test lowering a field ptr
......@@ -152,7 +149,6 @@ test "lower reinterpreted comptime field ptr (with under-aligned fields)" {
152149
153150test "lower reinterpreted comptime field ptr" {
154151 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
155 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
156152 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
157153
158154 // Test lowering a field ptr
......@@ -174,7 +170,6 @@ test "lower reinterpreted comptime field ptr" {
174170
175171test "reinterpret struct field at comptime" {
176172 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
177 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
178173 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
179174
180175 const numNative = comptime Bytes.init(0x12345678);
......@@ -232,7 +227,6 @@ test "ptrcast of const integer has the correct object size" {
232227test "implicit optional pointer to optional anyopaque pointer" {
233228 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
234229 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
235 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
236230 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
237231
238232 var buf: [4]u8 = "aoeu".*;
......@@ -244,7 +238,6 @@ test "implicit optional pointer to optional anyopaque pointer" {
244238
245239test "@ptrCast slice to slice" {
246240 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
247 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
248241 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
249242 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
250243
......@@ -262,7 +255,6 @@ test "@ptrCast slice to slice" {
262255
263256test "comptime @ptrCast a subset of an array, then write through it" {
264257 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
265 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
266258 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
267259
268260 comptime {
......@@ -354,7 +346,6 @@ test "@ptrCast restructures sliced comptime-only array" {
354346
355347test "@ptrCast slice multiplying length" {
356348 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
357 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
358349 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
359350 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
360351
......@@ -372,7 +363,6 @@ test "@ptrCast slice multiplying length" {
372363
373364test "@ptrCast array pointer to slice multiplying length" {
374365 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
375 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
376366 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
377367 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
378368
......@@ -390,7 +380,6 @@ test "@ptrCast array pointer to slice multiplying length" {
390380
391381test "@ptrCast slice dividing length" {
392382 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
393 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
394383 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
395384 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
396385
......@@ -408,7 +397,6 @@ test "@ptrCast slice dividing length" {
408397
409398test "@ptrCast array pointer to slice dividing length" {
410399 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
411 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
412400 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
413401 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
414402
......@@ -426,7 +414,6 @@ test "@ptrCast array pointer to slice dividing length" {
426414
427415test "@ptrCast slice with complex length increase" {
428416 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
429 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
430417 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
431418 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
432419
......@@ -447,7 +434,6 @@ test "@ptrCast slice with complex length increase" {
447434
448435test "@ptrCast array pointer to slice with complex length increase" {
449436 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
450 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
451437 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
452438 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
453439
......@@ -468,7 +454,6 @@ test "@ptrCast array pointer to slice with complex length increase" {
468454
469455test "@ptrCast slice with complex length decrease" {
470456 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
471 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
472457 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
473458 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
474459
......@@ -489,7 +474,6 @@ test "@ptrCast slice with complex length decrease" {
489474
490475test "@ptrCast array pointer to slice with complex length decrease" {
491476 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
492 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
493477 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
494478 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
495479
......@@ -510,7 +494,6 @@ test "@ptrCast array pointer to slice with complex length decrease" {
510494
511495test "@ptrCast slice of zero-bit type to different slice" {
512496 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
513 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
514497 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
515498 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
516499
......@@ -530,7 +513,6 @@ test "@ptrCast slice of zero-bit type to different slice" {
530513
531514test "@ptrCast single-item pointer to slice with length 1" {
532515 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
533 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
534516 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
535517 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
536518 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
......@@ -552,7 +534,6 @@ test "@ptrCast single-item pointer to slice with length 1" {
552534
553535test "@ptrCast single-item pointer to slice of bytes" {
554536 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
555 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
556537 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
557538 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
558539 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
......@@ -571,3 +552,13 @@ test "@ptrCast single-item pointer to slice of bytes" {
571552 try comptime S.doTheTest(void, &{});
572553 try comptime S.doTheTest(struct { x: u32 }, &.{ .x = 123 });
573554}
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 {
1717
1818test "mutate through ptr initialized with constant ptrFromInt value" {
1919 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
20 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2120 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2221 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
2322
......@@ -35,7 +34,6 @@ fn forceCompilerAnalyzeBranchHardCodedPtrDereference(x: bool) void {
3534
3635test "@ptrFromInt creates null pointer" {
3736 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
38 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
3937 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
4038 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
4139
......@@ -45,7 +43,6 @@ test "@ptrFromInt creates null pointer" {
4543
4644test "@ptrFromInt creates allowzero zero pointer" {
4745 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
48 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
4946 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
5047
5148 const ptr = @as(*allowzero u32, @ptrFromInt(0));
test/behavior/ref_var_in_if_after_if_2nd_switch_prong.zig-1
......@@ -6,7 +6,6 @@ const mem = std.mem;
66var ok: bool = false;
77test "reference a variable in an if after an if in the 2nd switch prong" {
88 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
9 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
109 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1110 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1211
test/behavior/reflection.zig-1
......@@ -26,7 +26,6 @@ fn dummy(a: bool, b: i32, c: f32) i32 {
2626}
2727
2828test "reflection: @field" {
29 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
3029 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
3130
3231 var f = Foo{
test/behavior/return_address.zig-1
......@@ -6,7 +6,6 @@ fn retAddr() usize {
66}
77
88test "return address" {
9 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
109 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1110 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1211 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
test/behavior/saturating_arithmetic.zig+9-8
......@@ -5,7 +5,7 @@ const maxInt = std.math.maxInt;
55const expect = std.testing.expect;
66
77test "saturating add" {
8 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
8 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
99 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1010 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1111 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -52,8 +52,8 @@ test "saturating add" {
5252}
5353
5454test "saturating add 128bit" {
55 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
5556 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
56 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
5757 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
5858 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
5959 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -79,7 +79,7 @@ test "saturating add 128bit" {
7979}
8080
8181test "saturating subtraction" {
82 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
82 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
8383 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
8484 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
8585 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -125,8 +125,8 @@ test "saturating subtraction" {
125125}
126126
127127test "saturating subtraction 128bit" {
128 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
128129 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
129 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
130130 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
131131 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
132132 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -158,7 +158,6 @@ fn testSatMul(comptime T: type, a: T, b: T, expected: T) !void {
158158}
159159
160160test "saturating multiplication <= 32 bits" {
161 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
162161 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
163162 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
164163 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -229,6 +228,7 @@ test "saturating multiplication <= 32 bits" {
229228}
230229
231230test "saturating mul i64, i128" {
231 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
232232 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
233233 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
234234
......@@ -256,8 +256,8 @@ test "saturating mul i64, i128" {
256256}
257257
258258test "saturating multiplication" {
259 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
259260 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
260 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
261261 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
262262 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
263263 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -295,7 +295,7 @@ test "saturating multiplication" {
295295}
296296
297297test "saturating shift-left" {
298 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
298 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
299299 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
300300 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
301301 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -340,6 +340,7 @@ test "saturating shift-left" {
340340}
341341
342342test "saturating shift-left large rhs" {
343 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
343344 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
344345 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
345346 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -357,7 +358,7 @@ test "saturating shift-left large rhs" {
357358}
358359
359360test "saturating shl uses the LHS type" {
360 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
361 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
361362 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
362363 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
363364 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
test/behavior/select.zig+3-2
......@@ -4,9 +4,9 @@ const mem = std.mem;
44const expect = std.testing.expect;
55
66test "@select vectors" {
7 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
78 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
89 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
9 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1010 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1111 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1212 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -35,9 +35,9 @@ fn selectVectors() !void {
3535}
3636
3737test "@select arrays" {
38 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
3839 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
3940 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
40 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
4141 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
4242 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
4343 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -66,6 +66,7 @@ fn selectArrays() !void {
6666}
6767
6868test "@select compare result" {
69 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
6970 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
7071 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
7172 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .hexagon) return error.SkipZigTest;
test/behavior/shuffle.zig+4-4
......@@ -5,7 +5,7 @@ const expect = std.testing.expect;
55const expectEqual = std.testing.expectEqual;
66
77test "@shuffle int" {
8 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
8 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
99 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1010 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1111 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -50,8 +50,8 @@ test "@shuffle int" {
5050}
5151
5252test "@shuffle int strange sizes" {
53 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
5354 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
54 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
5555 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
5656 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
5757 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -132,8 +132,8 @@ fn testShuffle(
132132}
133133
134134test "@shuffle bool 1" {
135 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
135136 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
136 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
137137 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
138138 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
139139 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -155,8 +155,8 @@ test "@shuffle bool 1" {
155155}
156156
157157test "@shuffle bool 2" {
158 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
158159 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
159 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
160160 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
161161 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
162162 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
test/behavior/sizeof_and_typeof.zig-3
......@@ -270,7 +270,6 @@ test "bitSizeOf comptime_int" {
270270}
271271
272272test "runtime instructions inside typeof in comptime only scope" {
273 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
274273 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
275274 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
276275
......@@ -326,7 +325,6 @@ test "lazy abi size used in comparison" {
326325}
327326
328327test "peer type resolution with @TypeOf doesn't trigger dependency loop check" {
329 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
330328 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
331329 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
332330
......@@ -437,7 +435,6 @@ test "Peer resolution of extern function calls in @TypeOf" {
437435}
438436
439437test "Extern function calls, dereferences and field access in @TypeOf" {
440 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
441438 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
442439
443440 const Test = struct {
test/behavior/slice.zig+2-22
......@@ -211,7 +211,6 @@ test "comptime pointer cast array and then slice" {
211211}
212212
213213test "slicing zero length array" {
214 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
215214 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
216215 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
217216
......@@ -273,7 +272,6 @@ test "result location zero sized array inside struct field implicit cast to slic
273272}
274273
275274test "runtime safety lets us slice from len..len" {
276 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
277275 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
278276 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
279277 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -287,7 +285,6 @@ fn sliceFromLenToLen(a_slice: []u8, start: usize, end: usize) []u8 {
287285}
288286
289287test "C pointer" {
290 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
291288 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
292289 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
293290
......@@ -299,7 +296,6 @@ test "C pointer" {
299296}
300297
301298test "C pointer slice access" {
302 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
303299 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
304300 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
305301 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -331,7 +327,6 @@ fn sliceSum(comptime q: []const u8) i32 {
331327}
332328
333329test "slice type with custom alignment" {
334 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
335330 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
336331 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
337332
......@@ -390,7 +385,6 @@ test "empty array to slice" {
390385}
391386
392387test "@ptrCast slice to pointer" {
393 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
394388 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
395389 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
396390
......@@ -445,7 +439,6 @@ test "slice multi-pointer without end" {
445439}
446440
447441test "slice syntax resulting in pointer-to-array" {
448 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
449442 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
450443 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
451444 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -665,7 +658,6 @@ test "slice syntax resulting in pointer-to-array" {
665658}
666659
667660test "slice pointer-to-array null terminated" {
668 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
669661 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
670662 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
671663
......@@ -718,7 +710,7 @@ test "slice pointer-to-array zero length" {
718710}
719711
720712test "type coercion of pointer to anon struct literal to pointer to slice" {
721 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
713 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
722714 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
723715 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
724716 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -812,7 +804,6 @@ test "slice sentinel access at comptime" {
812804}
813805
814806test "slicing array with sentinel as end index" {
815 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
816807 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
817808 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
818809
......@@ -831,7 +822,6 @@ test "slicing array with sentinel as end index" {
831822}
832823
833824test "slicing slice with sentinel as end index" {
834 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
835825 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
836826 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
837827
......@@ -888,7 +878,7 @@ test "slice field ptr var" {
888878}
889879
890880test "global slice field access" {
891 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
881 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
892882 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
893883 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
894884 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -929,7 +919,6 @@ test "slice with dereferenced value" {
929919}
930920
931921test "empty slice ptr is non null" {
932 if (builtin.zig_backend == .stage2_aarch64 and builtin.os.tag == .macos) return error.SkipZigTest; // TODO
933922 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // Test assumes `undefined` is non-zero
934923
935924 {
......@@ -947,7 +936,6 @@ test "empty slice ptr is non null" {
947936}
948937
949938test "slice decays to many pointer" {
950 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
951939 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
952940 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
953941
......@@ -957,7 +945,6 @@ test "slice decays to many pointer" {
957945}
958946
959947test "write through pointer to optional slice arg" {
960 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
961948 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
962949 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
963950 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -977,7 +964,6 @@ test "write through pointer to optional slice arg" {
977964}
978965
979966test "modify slice length at comptime" {
980 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
981967 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
982968 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
983969 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -994,7 +980,6 @@ test "modify slice length at comptime" {
994980}
995981
996982test "slicing zero length array field of struct" {
997 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
998983 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
999984 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1000985 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1010,7 +995,6 @@ test "slicing zero length array field of struct" {
1010995}
1011996
1012997test "slicing slices gives correct result" {
1013 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1014998 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1015999 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
10161000
......@@ -1024,7 +1008,6 @@ test "slicing slices gives correct result" {
10241008}
10251009
10261010test "get address of element of zero-sized slice" {
1027 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10281011 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10291012 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
10301013
......@@ -1037,7 +1020,6 @@ test "get address of element of zero-sized slice" {
10371020}
10381021
10391022test "sentinel-terminated 0-length slices" {
1040 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10411023 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10421024 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
10431025
......@@ -1058,8 +1040,6 @@ test "sentinel-terminated 0-length slices" {
10581040}
10591041
10601042test "peer slices keep abi alignment with empty struct" {
1061 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1062
10631043 var cond: bool = undefined;
10641044 cond = false;
10651045 const slice = if (cond) &[1]u32{42} else &.{};
test/behavior/src.zig-1
......@@ -16,7 +16,6 @@ const expect = std.testing.expect;
1616const expectEqualStrings = std.testing.expectEqualStrings;
1717
1818test "@src" {
19 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2019 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2120 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2221 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
test/behavior/string_literals.zig+1-5
......@@ -6,7 +6,6 @@ const tag_name = @tagName(TestEnum.TestEnumValue);
66const ptr_tag_name: [*:0]const u8 = tag_name;
77
88test "@tagName() returns a string literal" {
9 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
109 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1110 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1211
......@@ -20,7 +19,6 @@ const error_name = @errorName(TestError.TestErrorCode);
2019const ptr_error_name: [*:0]const u8 = error_name;
2120
2221test "@errorName() returns a string literal" {
23 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2422 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2523 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
2624
......@@ -34,7 +32,6 @@ const type_name = @typeName(TestType);
3432const ptr_type_name: [*:0]const u8 = type_name;
3533
3634test "@typeName() returns a string literal" {
37 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
3835 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
3936 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
4037
......@@ -48,7 +45,6 @@ const ptr_actual_contents: [*:0]const u8 = actual_contents;
4845const expected_contents = "hello zig\n";
4946
5047test "@embedFile() returns a string literal" {
51 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
5248 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
5349 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
5450 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -64,7 +60,7 @@ fn testFnForSrc() std.builtin.SourceLocation {
6460}
6561
6662test "@src() returns a struct containing 0-terminated string slices" {
67 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
63 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
6864 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
6965 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
7066
test/behavior/struct.zig+13-46
......@@ -10,7 +10,6 @@ const maxInt = std.math.maxInt;
1010top_level_field: i32,
1111
1212test "top level fields" {
13 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1413 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1514
1615 var instance = @This(){
......@@ -87,7 +86,6 @@ const StructFoo = struct {
8786};
8887
8988test "structs" {
90 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
9189 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
9290 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
9391 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -200,7 +198,6 @@ const MemberFnRand = struct {
200198};
201199
202200test "return struct byval from function" {
203 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
204201 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
205202
206203 const Bar = struct {
......@@ -237,7 +234,6 @@ test "call method with mutable reference to struct with no fields" {
237234}
238235
239236test "struct field init with catch" {
240 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
241237 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
242238
243239 const S = struct {
......@@ -280,7 +276,6 @@ const Val = struct {
280276};
281277
282278test "struct point to self" {
283 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
284279 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
285280 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
286281
......@@ -297,7 +292,6 @@ test "struct point to self" {
297292}
298293
299294test "void struct fields" {
300 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
301295 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
302296
303297 const foo = VoidStructFieldsFoo{
......@@ -335,7 +329,6 @@ fn testPassSliceOfEmptyStructToFn(slice: []const EmptyStruct2) usize {
335329}
336330
337331test "self-referencing struct via array member" {
338 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
339332 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
340333 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
341334 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -492,7 +485,7 @@ const Bitfields = packed struct {
492485};
493486
494487test "packed struct fields are ordered from LSB to MSB" {
495 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
488 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
496489 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
497490 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
498491 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -610,7 +603,6 @@ fn getC(data: *const BitField1) u2 {
610603}
611604
612605test "default struct initialization fields" {
613 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
614606 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
615607
616608 const S = struct {
......@@ -634,8 +626,8 @@ test "default struct initialization fields" {
634626}
635627
636628test "packed array 24bits" {
637 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
638629 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
630 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
639631 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
640632 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
641633
......@@ -701,8 +693,8 @@ const FooArrayOfAligned = packed struct {
701693};
702694
703695test "pointer to packed struct member in a stack variable" {
696 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
704697 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
705 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
706698 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
707699 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
708700 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
......@@ -731,7 +723,6 @@ test "packed struct with u0 field access" {
731723}
732724
733725test "access to global struct fields" {
734 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
735726 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
736727
737728 g_foo.bar.value = 42;
......@@ -753,8 +744,8 @@ const S0 = struct {
753744var g_foo: S0 = S0.init();
754745
755746test "packed struct with fp fields" {
747 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
756748 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
757 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
758749 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
759750 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
760751 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -783,7 +774,6 @@ test "packed struct with fp fields" {
783774
784775test "fn with C calling convention returns struct by value" {
785776 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
786 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
787777 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
788778
789779 const S = struct {
......@@ -807,7 +797,6 @@ test "fn with C calling convention returns struct by value" {
807797}
808798
809799test "non-packed struct with u128 entry in union" {
810 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
811800 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
812801 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
813802 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -834,8 +823,8 @@ test "non-packed struct with u128 entry in union" {
834823}
835824
836825test "packed struct field passed to generic function" {
826 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
837827 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
838 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
839828 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
840829 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
841830
......@@ -859,7 +848,6 @@ test "packed struct field passed to generic function" {
859848}
860849
861850test "anonymous struct literal syntax" {
862 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
863851 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
864852
865853 const S = struct {
......@@ -951,7 +939,6 @@ test "comptime struct field" {
951939test "tuple element initialized with fn call" {
952940 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
953941 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
954 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
955942 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
956943
957944 const S = struct {
......@@ -968,8 +955,8 @@ test "tuple element initialized with fn call" {
968955}
969956
970957test "struct with union field" {
958 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
971959 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
972 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
973960 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
974961 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
975962
......@@ -990,7 +977,6 @@ test "struct with union field" {
990977}
991978
992979test "struct with 0-length union array field" {
993 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
994980 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
995981 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" {
10781064}
10791065
10801066test "anon init through error unions and optionals" {
1081 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1067 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
10821068 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10831069 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10841070 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1105,7 +1091,6 @@ test "anon init through error unions and optionals" {
11051091}
11061092
11071093test "anon init through optional" {
1108 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
11091094 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11101095 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11111096 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1125,7 +1110,6 @@ test "anon init through optional" {
11251110}
11261111
11271112test "anon init through error union" {
1128 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
11291113 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11301114 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11311115 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1145,7 +1129,7 @@ test "anon init through error union" {
11451129}
11461130
11471131test "typed init through error unions and optionals" {
1148 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1132 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
11491133 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11501134 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11511135
......@@ -1171,7 +1155,6 @@ test "typed init through error unions and optionals" {
11711155}
11721156
11731157test "initialize struct with empty literal" {
1174 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
11751158 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11761159
11771160 const S = struct { x: i32 = 1234 };
......@@ -1206,7 +1189,7 @@ test "loading a struct pointer perfoms a copy" {
12061189}
12071190
12081191test "packed struct aggregate init" {
1209 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1192 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
12101193 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
12111194 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
12121195 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1226,7 +1209,7 @@ test "packed struct aggregate init" {
12261209}
12271210
12281211test "packed struct field access via pointer" {
1229 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1212 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
12301213 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
12311214 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
12321215 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1267,7 +1250,6 @@ test "store to comptime field" {
12671250}
12681251
12691252test "struct field init value is size of the struct" {
1270 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
12711253 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
12721254
12731255 const namespace = struct {
......@@ -1282,7 +1264,6 @@ test "struct field init value is size of the struct" {
12821264}
12831265
12841266test "under-aligned struct field" {
1285 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
12861267 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
12871268 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
12881269 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1306,7 +1287,6 @@ test "under-aligned struct field" {
13061287}
13071288
13081289test "fieldParentPtr of a zero-bit field" {
1309 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
13101290 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
13111291 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
13121292 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1357,7 +1337,6 @@ test "fieldParentPtr of a zero-bit field" {
13571337
13581338test "struct field has a pointer to an aligned version of itself" {
13591339 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1360 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
13611340
13621341 const E = struct {
13631342 next: *align(1) @This(),
......@@ -1415,7 +1394,6 @@ test "struct has only one reference" {
14151394}
14161395
14171396test "no dependency loop on pointer to optional struct" {
1418 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
14191397 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
14201398 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
14211399
......@@ -1437,7 +1415,6 @@ test "discarded struct initialization works as expected" {
14371415}
14381416
14391417test "function pointer in struct returns the struct" {
1440 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
14411418 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
14421419
14431420 const A = struct {
......@@ -1455,7 +1432,6 @@ test "function pointer in struct returns the struct" {
14551432
14561433test "no dependency loop on optional field wrapped in generic function" {
14571434 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1458 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
14591435
14601436 const S = struct {
14611437 fn Atomic(comptime T: type) type {
......@@ -1473,7 +1449,6 @@ test "no dependency loop on optional field wrapped in generic function" {
14731449}
14741450
14751451test "optional field init with tuple" {
1476 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
14771452 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
14781453
14791454 const S = struct {
......@@ -1488,8 +1463,6 @@ test "optional field init with tuple" {
14881463}
14891464
14901465test "if inside struct init inside if" {
1491 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1492
14931466 const MyStruct = struct { x: u32 };
14941467 const b: u32 = 5;
14951468 var i: u32 = 1;
......@@ -1580,7 +1553,6 @@ test "instantiate struct with comptime field" {
15801553test "struct field pointer has correct alignment" {
15811554 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
15821555 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1583 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
15841556 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
15851557
15861558 const S = struct {
......@@ -1610,7 +1582,6 @@ test "struct field pointer has correct alignment" {
16101582test "extern struct field pointer has correct alignment" {
16111583 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
16121584 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1613 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
16141585 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
16151586
16161587 const S = struct {
......@@ -1828,7 +1799,6 @@ test "tuple with comptime-only field" {
18281799}
18291800
18301801test "extern struct fields are aligned to 1" {
1831 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
18321802 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
18331803
18341804 const Foo = extern struct {
......@@ -1845,7 +1815,7 @@ test "extern struct fields are aligned to 1" {
18451815}
18461816
18471817test "assign to slice.len of global variable" {
1848 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1818 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
18491819 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
18501820 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
18511821 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1897,7 +1867,6 @@ test "array of structs inside struct initialized with undefined" {
18971867}
18981868
18991869test "runtime call in nested initializer" {
1900 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
19011870 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
19021871 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
19031872
......@@ -1929,7 +1898,6 @@ test "runtime call in nested initializer" {
19291898}
19301899
19311900test "runtime value in nested initializer passed as pointer to function" {
1932 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
19331901 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
19341902
19351903 const Bar = struct {
......@@ -1953,7 +1921,7 @@ test "runtime value in nested initializer passed as pointer to function" {
19531921}
19541922
19551923test "struct field default value is a call" {
1956 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1924 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
19571925 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
19581926 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
19591927
......@@ -2001,7 +1969,6 @@ test "aggregate initializers should allow initializing comptime fields, verifyin
20011969
20021970test "assignment of field with padding" {
20031971 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
2004 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
20051972 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
20061973
20071974 const Mesh = extern struct {
......@@ -2031,7 +1998,6 @@ test "assignment of field with padding" {
20311998
20321999test "initiate global variable with runtime value" {
20332000 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
2034 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
20352001 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
20362002
20372003 const S = struct {
......@@ -2126,6 +2092,7 @@ test "anonymous struct equivalence" {
21262092}
21272093
21282094test "field access through mem ptr arg" {
2095 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
21292096 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
21302097
21312098 const S = struct {
test/behavior/struct_contains_null_ptr_itself.zig-1
......@@ -3,7 +3,6 @@ const expect = std.testing.expect;
33const builtin = @import("builtin");
44
55test "struct contains null pointer which contains original struct" {
6 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
76 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
87 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
98
test/behavior/struct_contains_slice_of_itself.zig+2-1
......@@ -12,6 +12,7 @@ const NodeAligned = struct {
1212};
1313
1414test "struct contains slice of itself" {
15 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1516 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1617 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1718
......@@ -52,7 +53,7 @@ test "struct contains slice of itself" {
5253}
5354
5455test "struct contains aligned slice of itself" {
55 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
56 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
5657 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
5758 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
5859
test/behavior/switch.zig+25-13
......@@ -43,7 +43,7 @@ fn testSwitchWithAllRanges(x: u32, y: u32) u32 {
4343}
4444
4545test "switch arbitrary int size" {
46 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
46 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
4747 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
4848 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
4949 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
......@@ -274,8 +274,8 @@ const SwitchProngWithVarEnum = union(enum) {
274274};
275275
276276test "switch prong with variable" {
277 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
277278 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
278 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
279279 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
280280 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
281281
......@@ -300,7 +300,6 @@ fn switchProngWithVarFn(a: SwitchProngWithVarEnum) !void {
300300
301301test "switch on enum using pointer capture" {
302302 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
303 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
304303 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
305304
306305 try testSwitchEnumPtrCapture();
......@@ -361,7 +360,6 @@ fn testSwitchHandleAllCasesRange(x: u8) u8 {
361360
362361test "switch on union with some prongs capturing" {
363362 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
364 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
365363 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
366364
367365 const X = union(enum) {
......@@ -398,7 +396,6 @@ test "switch on const enum with var" {
398396}
399397
400398test "anon enum literal used in switch on union enum" {
401 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
402399 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
403400
404401 const Foo = union(enum) {
......@@ -469,8 +466,8 @@ test "switch on integer with else capturing expr" {
469466}
470467
471468test "else prong of switch on error set excludes other cases" {
469 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
472470 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
473 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
474471 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
475472 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
476473 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -505,8 +502,8 @@ test "else prong of switch on error set excludes other cases" {
505502}
506503
507504test "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;
508506 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
509 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
510507 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
511508 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
512509 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
563560
564561test "switch with null and T peer types and inferred result location type" {
565562 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
566 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
567563 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
568564
569565 const S = struct {
......@@ -582,7 +578,7 @@ test "switch with null and T peer types and inferred result location type" {
582578}
583579
584580test "switch prongs with cases with identical payload types" {
585 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
581 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
586582 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
587583 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
588584
......@@ -689,7 +685,7 @@ test "switch prong pointer capture alignment" {
689685}
690686
691687test "switch on pointer type" {
692 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
688 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
693689 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
694690 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
695691
......@@ -737,8 +733,8 @@ test "switch on error set with single else" {
737733}
738734
739735test "switch capture copies its payload" {
736 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
740737 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
741 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
742738 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
743739 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
744740
......@@ -831,6 +827,7 @@ test "comptime inline switch" {
831827}
832828
833829test "switch capture peer type resolution" {
830 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
834831 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
835832
836833 const U = union(enum) {
......@@ -848,6 +845,8 @@ test "switch capture peer type resolution" {
848845}
849846
850847test "switch capture peer type resolution for in-memory coercible payloads" {
848 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
849
851850 const T1 = c_int;
852851 const T2 = @Type(@typeInfo(T1));
853852
......@@ -868,6 +867,8 @@ test "switch capture peer type resolution for in-memory coercible payloads" {
868867}
869868
870869test "switch pointer capture peer type resolution" {
870 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
871
871872 const T1 = c_int;
872873 const T2 = @Type(@typeInfo(T1));
873874
......@@ -904,6 +905,7 @@ test "inline switch range that includes the maximum value of the switched type"
904905}
905906
906907test "nested break ignores switch conditions and breaks instead" {
908 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
907909 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
908910 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
909911
......@@ -926,6 +928,7 @@ test "nested break ignores switch conditions and breaks instead" {
926928}
927929
928930test "peer type resolution on switch captures ignores unused payload bits" {
931 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
929932 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
930933 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" {
951954}
952955
953956test "switch prong captures range" {
954 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
955957 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
956958 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
957959
......@@ -1042,7 +1044,7 @@ test "labeled switch with break" {
10421044}
10431045
10441046test "unlabeled break ignores switch" {
1045 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1047 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
10461048 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10471049 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10481050 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" {
10651067 else => {},
10661068 }
10671069}
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");
33const expect = std.testing.expect;
44
55test "simple switch loop" {
6 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
6 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
77 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
88 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
99 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
......@@ -27,7 +27,7 @@ test "simple switch loop" {
2727}
2828
2929test "switch loop with ranges" {
30 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
30 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
3131 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
3232 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
3333 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
......@@ -48,7 +48,7 @@ test "switch loop with ranges" {
4848}
4949
5050test "switch loop on enum" {
51 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
51 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
5252 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
5353 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
5454 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
......@@ -72,7 +72,7 @@ test "switch loop on enum" {
7272}
7373
7474test "switch loop with error set" {
75 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
75 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
7676 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
7777 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
7878 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
......@@ -96,7 +96,7 @@ test "switch loop with error set" {
9696}
9797
9898test "switch loop on tagged union" {
99 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
99 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
100100 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
101101 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
102102 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
......@@ -129,7 +129,7 @@ test "switch loop on tagged union" {
129129}
130130
131131test "switch loop dispatching instructions" {
132 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
132 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
133133 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
134134 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
135135 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
......@@ -179,7 +179,7 @@ test "switch loop dispatching instructions" {
179179}
180180
181181test "switch loop with pointer capture" {
182 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
182 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
183183 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
184184 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
185185 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
......@@ -218,11 +218,34 @@ test "switch loop with pointer capture" {
218218}
219219
220220test "unanalyzed continue with operand" {
221 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
222
223221 @setRuntimeSafety(false);
224222 label: switch (false) {
225223 false => if (false) continue :label true,
226224 true => {},
227225 }
228226}
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" {
300300}
301301
302302test "switch on error union if else capture" {
303 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
303304 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
304305 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 {
2121}
2222
2323test "switch prong returns error enum" {
24 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
2524 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
25 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
2626 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2727 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
2828
test/behavior/switch_prong_implicit_cast.zig+1-1
......@@ -15,8 +15,8 @@ fn foo(id: u64) !FormValue {
1515}
1616
1717test "switch prong implicit cast" {
18 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1918 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
19 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
2020 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2121
2222 const result = switch (foo(2) catch unreachable) {
test/behavior/this.zig-2
......@@ -26,7 +26,6 @@ test "this refer to module call private fn" {
2626}
2727
2828test "this refer to container" {
29 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
3029 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
3130
3231 var pt: Point(i32) = undefined;
......@@ -47,7 +46,6 @@ fn prev(p: ?State) void {
4746}
4847
4948test "this used as optional function parameter" {
50 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
5149 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
5250 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
5351 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
test/behavior/threadlocal.zig-3
......@@ -4,7 +4,6 @@ const expect = std.testing.expect;
44
55test "thread local variable" {
66 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
7 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
87 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
98 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
109 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -25,7 +24,6 @@ test "thread local variable" {
2524
2625test "pointer to thread local array" {
2726 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
28 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2927 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
3028 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
3129 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -40,7 +38,6 @@ threadlocal var buffer: [11]u8 = undefined;
4038
4139test "reference a global threadlocal variable" {
4240 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
43 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
4441 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
4542 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
4643 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
test/behavior/truncate.zig+1-1
......@@ -65,8 +65,8 @@ test "truncate on comptime integer" {
6565}
6666
6767test "truncate on vectors" {
68 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
6968 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
69 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
7070 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
7171 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
7272 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
test/behavior/try.zig+80-2
......@@ -47,7 +47,7 @@ test "try then not executed with assignment" {
4747}
4848
4949test "`try`ing an if/else expression" {
50 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
50 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
5151 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
5252 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
5353 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -68,7 +68,6 @@ test "`try`ing an if/else expression" {
6868}
6969
7070test "'return try' of empty error set in function returning non-error" {
71 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
7271 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
7372 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
7473
......@@ -122,3 +121,82 @@ test "'return try' through conditional" {
122121 comptime std.debug.assert(result == 123);
123122 }
124123}
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;
88
99test "tuple concatenation" {
1010 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1211 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1312
1413 const S = struct {
......@@ -51,7 +50,6 @@ test "tuple multiplication" {
5150}
5251
5352test "more tuple concatenation" {
54 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
5553 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
5654 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
5755 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -129,7 +127,6 @@ test "tuple initializer for var" {
129127}
130128
131129test "array-like initializer for tuple types" {
132 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
133130 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
134131 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
135132
......@@ -216,7 +213,6 @@ test "initializing anon struct with explicit type" {
216213}
217214
218215test "fieldParentPtr of tuple" {
219 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
220216 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
221217 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
222218 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -229,7 +225,6 @@ test "fieldParentPtr of tuple" {
229225}
230226
231227test "fieldParentPtr of anon struct" {
232 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
233228 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
234229 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
235230 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -256,7 +251,6 @@ test "offsetOf anon struct" {
256251}
257252
258253test "initializing tuple with mixed comptime-runtime fields" {
259 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
260254 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
261255
262256 var x: u32 = 15;
......@@ -268,7 +262,6 @@ test "initializing tuple with mixed comptime-runtime fields" {
268262}
269263
270264test "initializing anon struct with mixed comptime-runtime fields" {
271 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
272265 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
273266
274267 var x: u32 = 15;
......@@ -280,7 +273,6 @@ test "initializing anon struct with mixed comptime-runtime fields" {
280273}
281274
282275test "tuple in tuple passed to generic function" {
283 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
284276 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
285277 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
286278 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -300,7 +292,6 @@ test "tuple in tuple passed to generic function" {
300292}
301293
302294test "coerce tuple to tuple" {
303 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
304295 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
305296 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
306297 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -315,7 +306,6 @@ test "coerce tuple to tuple" {
315306}
316307
317308test "tuple type with void field" {
318 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
319309 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
320310 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
321311 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -353,7 +343,6 @@ test "zero sized struct in tuple handled correctly" {
353343}
354344
355345test "tuple type with void field and a runtime field" {
356 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
357346 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
358347 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
359348
......@@ -364,7 +353,6 @@ test "tuple type with void field and a runtime field" {
364353}
365354
366355test "branching inside tuple literal" {
367 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
368356 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
369357 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
370358
......@@ -410,7 +398,6 @@ test "tuple of struct concatenation and coercion to array" {
410398}
411399
412400test "nested runtime conditionals in tuple initializer" {
413 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
414401 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
415402 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
416403 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -446,7 +433,6 @@ test "sentinel slice in tuple" {
446433}
447434
448435test "tuple pointer is indexable" {
449 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
450436 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
451437 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
452438 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -470,7 +456,6 @@ test "tuple pointer is indexable" {
470456}
471457
472458test "coerce anon tuple to tuple" {
473 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
474459 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
475460 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
476461
......@@ -496,14 +481,12 @@ test "empty tuple type" {
496481}
497482
498483test "tuple with comptime fields with non empty initializer" {
499 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
500
501484 const a: struct { comptime comptime_int = 0 } = .{0};
502485 _ = a;
503486}
504487
505488test "tuple with runtime value coerced into a slice with a sentinel" {
506 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
489 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
507490 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
508491 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
509492 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -578,7 +561,6 @@ test "comptime fields in tuple can be initialized" {
578561
579562test "empty struct in tuple" {
580563 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
581 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
582564 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
583565 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
584566
......@@ -591,7 +573,6 @@ test "empty struct in tuple" {
591573
592574test "empty union in tuple" {
593575 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
594 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
595576 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
596577 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
597578
......@@ -604,6 +585,7 @@ test "empty union in tuple" {
604585
605586test "field pointer of underaligned tuple" {
606587 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
588
607589 const S = struct {
608590 fn doTheTest() !void {
609591 const T = struct { u8, u32 };
test/behavior/tuple_declarations.zig-2
......@@ -5,7 +5,6 @@ const expect = testing.expect;
55const expectEqualStrings = testing.expectEqualStrings;
66
77test "tuple declaration type info" {
8 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
98 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
109 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1110
......@@ -34,7 +33,6 @@ test "tuple declaration type info" {
3433}
3534
3635test "tuple declaration usage" {
37 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
3836 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
3937 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
4038
test/behavior/type.zig+3-6
......@@ -200,8 +200,8 @@ test "Type.ErrorUnion" {
200200}
201201
202202test "Type.Opaque" {
203 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
203204 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
204 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
205205 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
206206 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
207207
......@@ -258,8 +258,8 @@ test "Type.ErrorSet" {
258258}
259259
260260test "Type.Struct" {
261 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
261262 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
262 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
263263 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
264264 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
265265
......@@ -348,7 +348,6 @@ test "Type.Struct" {
348348
349349test "Type.Enum" {
350350 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
351 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
352351 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
353352
354353 const Foo = @Type(.{
......@@ -409,8 +408,8 @@ test "Type.Enum" {
409408}
410409
411410test "Type.Union" {
411 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
412412 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
413 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
414413 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
415414
416415 const Untagged = @Type(.{
......@@ -547,7 +546,6 @@ test "Type.Union from empty Type.Enum" {
547546
548547test "Type.Fn" {
549548 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
550 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
551549
552550 const some_opaque = opaque {};
553551 const some_ptr = *some_opaque;
......@@ -724,7 +722,6 @@ test "@Type should resolve its children types" {
724722}
725723
726724test "struct field names sliced at comptime from larger string" {
727 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
728725 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
729726
730727 const text =
test/behavior/type_info.zig+2-4
......@@ -158,7 +158,6 @@ fn testArray() !void {
158158}
159159
160160test "type info: error set, error union info, anyerror" {
161 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
162161 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
163162 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
164163 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -190,7 +189,6 @@ fn testErrorSet() !void {
190189}
191190
192191test "type info: error set single value" {
193 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
194192 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
195193 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
196194 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -204,7 +202,6 @@ test "type info: error set single value" {
204202}
205203
206204test "type info: error set merged" {
207 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
208205 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
209206 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
210207 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -221,7 +218,6 @@ test "type info: error set merged" {
221218
222219test "type info: enum info" {
223220 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
224 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
225221 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
226222 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
227223
......@@ -362,6 +358,8 @@ test "type info: function type info" {
362358}
363359
364360fn testFunction() !void {
361 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
362
365363 const S = struct {
366364 export fn typeInfoFoo() callconv(.c) usize {
367365 unreachable;
test/behavior/typename.zig-8
......@@ -12,7 +12,6 @@ const expectStringStartsWith = std.testing.expectStringStartsWith;
1212// failures.
1313
1414test "anon fn param" {
15 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1615 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1716 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1817 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -38,7 +37,6 @@ test "anon fn param" {
3837}
3938
4039test "anon field init" {
41 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
4240 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
4341 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
4442 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -64,7 +62,6 @@ test "anon field init" {
6462}
6563
6664test "basic" {
67 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
6865 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
6966 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
7067 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -86,7 +83,6 @@ test "basic" {
8683}
8784
8885test "top level decl" {
89 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
9086 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
9187 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
9288 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -136,7 +132,6 @@ const B = struct {
136132};
137133
138134test "fn param" {
139 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
140135 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
141136 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
142137 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -216,7 +211,6 @@ pub fn expectEqualStringsIgnoreDigits(expected: []const u8, actual: []const u8)
216211}
217212
218213test "local variable" {
219 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
220214 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
221215 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
222216 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -235,7 +229,6 @@ test "local variable" {
235229}
236230
237231test "comptime parameters not converted to anytype in function type" {
238 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
239232 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
240233 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
241234 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -245,7 +238,6 @@ test "comptime parameters not converted to anytype in function type" {
245238}
246239
247240test "anon name strategy used in sub expression" {
248 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
249241 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
250242 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
251243 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
test/behavior/undefined.zig-4
......@@ -46,7 +46,6 @@ fn setFooX(foo: *Foo) void {
4646
4747test "assign undefined to struct" {
4848 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
49 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
5049 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
5150
5251 comptime {
......@@ -63,7 +62,6 @@ test "assign undefined to struct" {
6362
6463test "assign undefined to struct with method" {
6564 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
66 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
6765 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
6866
6967 comptime {
......@@ -89,7 +87,6 @@ test "type name of undefined" {
8987var buf: []u8 = undefined;
9088
9189test "reslice of undefined global var slice" {
92 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
9390 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
9491 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
9592
......@@ -100,7 +97,6 @@ test "reslice of undefined global var slice" {
10097}
10198
10299test "returned undef is 0xaa bytes when runtime safety is enabled" {
103 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
104100 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
105101 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
106102 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
test/behavior/union.zig+43-61
......@@ -12,8 +12,8 @@ const FooWithFloats = union {
1212};
1313
1414test "basic unions with floats" {
15 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1615 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
16 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1717 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1818 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1919 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -29,8 +29,8 @@ fn setFloat(foo: *FooWithFloats, x: f64) void {
2929}
3030
3131test "init union with runtime value - floats" {
32 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
3332 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
33 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
3434 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
3535 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
3636
......@@ -60,8 +60,8 @@ const Foo = union {
6060};
6161
6262test "init union with runtime value" {
63 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
6463 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
64 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
6565 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
6666 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
6767 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -161,7 +161,6 @@ test "unions embedded in aggregate types" {
161161
162162test "constant tagged union with payload" {
163163 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
164 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
165164 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
166165
167166 var empty = TaggedUnionWithPayload{ .Empty = {} };
......@@ -210,8 +209,8 @@ const Payload = union(Letter) {
210209};
211210
212211test "union with specified enum tag" {
213 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
214212 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
213 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
215214 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
216215 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
217216 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -221,8 +220,8 @@ test "union with specified enum tag" {
221220}
222221
223222test "packed union generates correctly aligned type" {
224 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
225223 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
224 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
226225 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
227226 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
228227 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -264,7 +263,6 @@ fn testComparison() !void {
264263
265264test "comparison between union and enum literal" {
266265 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
267 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
268266 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
269267 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
270268
......@@ -280,7 +278,6 @@ const TheUnion = union(TheTag) {
280278};
281279test "cast union to tag type of union" {
282280 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
283 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
284281 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
285282
286283 try testCastUnionToTag();
......@@ -301,7 +298,6 @@ test "union field access gives the enum values" {
301298
302299test "cast tag type of union to union" {
303300 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
304 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
305301 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
306302
307303 var x: Value2 = Letter2.B;
......@@ -317,7 +313,6 @@ const Value2 = union(Letter2) {
317313
318314test "implicit cast union to its tag type" {
319315 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
320 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
321316 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
322317
323318 var x: Value2 = Letter2.B;
......@@ -337,8 +332,8 @@ pub const PackThis = union(enum) {
337332};
338333
339334test "constant packed union" {
340 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
341335 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
336 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
342337 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
343338 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
344339
......@@ -357,7 +352,6 @@ const MultipleChoice = union(enum(u32)) {
357352};
358353test "simple union(enum(u32))" {
359354 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
360 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
361355 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
362356
363357 var x = MultipleChoice.C;
......@@ -403,7 +397,6 @@ test "assigning to union with zero size field" {
403397
404398test "tagged union initialization with runtime void" {
405399 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
406 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
407400 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
408401
409402 try expect(testTaggedUnionInit({}));
......@@ -423,7 +416,6 @@ pub const UnionEnumNoPayloads = union(enum) { A, B };
423416
424417test "tagged union with no payloads" {
425418 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
426 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
427419 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
428420
429421 const a = UnionEnumNoPayloads{ .B = {} };
......@@ -470,7 +462,6 @@ var glbl: Foo1 = undefined;
470462
471463test "global union with single field is correctly initialized" {
472464 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
473 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
474465 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
475466
476467 glbl = Foo1{
......@@ -487,8 +478,8 @@ pub const FooUnion = union(enum) {
487478var glbl_array: [2]FooUnion = undefined;
488479
489480test "initialize global array of union" {
490 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
491481 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
482 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
492483 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
493484 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
494485
......@@ -500,7 +491,6 @@ test "initialize global array of union" {
500491
501492test "update the tag value for zero-sized unions" {
502493 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
503 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
504494 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
505495
506496 const S = union(enum) {
......@@ -515,7 +505,6 @@ test "update the tag value for zero-sized unions" {
515505
516506test "union initializer generates padding only if needed" {
517507 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
518 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
519508 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
520509
521510 const U = union(enum) {
......@@ -528,7 +517,6 @@ test "union initializer generates padding only if needed" {
528517}
529518
530519test "runtime tag name with single field" {
531 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
532520 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
533521 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
534522
......@@ -543,7 +531,6 @@ test "runtime tag name with single field" {
543531
544532test "method call on an empty union" {
545533 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
546 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
547534 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
548535
549536 const S = struct {
......@@ -604,8 +591,8 @@ test "tagged union type" {
604591}
605592
606593test "tagged union as return value" {
607 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
608594 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
595 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
609596 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
610597 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
611598 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -621,8 +608,8 @@ fn returnAnInt(x: i32) TaggedFoo {
621608}
622609
623610test "tagged union with all void fields but a meaningful tag" {
624 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
625611 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
612 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
626613 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
627614
628615 const S = struct {
......@@ -649,8 +636,8 @@ test "tagged union with all void fields but a meaningful tag" {
649636}
650637
651638test "union(enum(u32)) with specified and unspecified tag values" {
652 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
653639 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
640 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
654641 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
655642 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
656643
......@@ -687,7 +674,6 @@ fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) !void {
687674}
688675
689676test "switch on union with only 1 field" {
690 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
691677 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
692678 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
743729
744730test "@intFromEnum works on unions" {
745731 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
746 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
747732 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
748733
749734 const Bar = union(enum) {
......@@ -801,8 +786,8 @@ fn Setter(comptime attr: Attribute) type {
801786}
802787
803788test "return union init with void payload" {
804 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
805789 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
790 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
806791 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
807792
808793 const S = struct {
......@@ -825,7 +810,7 @@ test "return union init with void payload" {
825810}
826811
827812test "@unionInit stored to a const" {
828 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
813 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
829814 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
830815 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
831816 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -856,7 +841,6 @@ test "@unionInit stored to a const" {
856841}
857842
858843test "@unionInit can modify a union type" {
859 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
860844 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
861845 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
862846
......@@ -879,7 +863,6 @@ test "@unionInit can modify a union type" {
879863}
880864
881865test "@unionInit can modify a pointer value" {
882 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
883866 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
884867 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
885868
......@@ -899,7 +882,6 @@ test "@unionInit can modify a pointer value" {
899882}
900883
901884test "union no tag with struct member" {
902 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
903885 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
904886 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
905887 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -935,8 +917,8 @@ test "extern union doesn't trigger field check at comptime" {
935917}
936918
937919test "anonymous union literal syntax" {
920 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
938921 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
939 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
940922 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
941923 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
942924 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -964,8 +946,8 @@ test "anonymous union literal syntax" {
964946}
965947
966948test "function call result coerces from tagged union to the tag" {
949 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
967950 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
968 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
969951 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
970952
971953 const S = struct {
......@@ -1000,7 +982,6 @@ test "function call result coerces from tagged union to the tag" {
1000982
1001983test "switching on non exhaustive union" {
1002984 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1003 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1004985 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1005986
1006987 const S = struct {
......@@ -1028,7 +1009,6 @@ test "switching on non exhaustive union" {
10281009
10291010test "containers with single-field enums" {
10301011 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1031 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10321012 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10331013
10341014 const S = struct {
......@@ -1057,8 +1037,8 @@ test "containers with single-field enums" {
10571037}
10581038
10591039test "@unionInit on union with tag but no fields" {
1040 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
10601041 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1061 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10621042 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10631043
10641044 const S = struct {
......@@ -1106,7 +1086,7 @@ test "union enum type gets a separate scope" {
11061086}
11071087
11081088test "global variable struct contains union initialized to non-most-aligned field" {
1109 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1089 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
11101090 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11111091 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11121092 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
11331113}
11341114
11351115test "union with no result loc initiated with a runtime value" {
1116 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
11361117 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1137 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
11381118 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11391119 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" {
11511131}
11521132
11531133test "union with a large struct field" {
1134 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
11541135 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1155 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
11561136 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11571137 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
11581138
......@@ -1187,7 +1167,6 @@ test "comptime equality of extern unions with same tag" {
11871167
11881168test "union tag is set when initiated as a temporary value at runtime" {
11891169 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1190 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
11911170 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11921171 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" {
12061185}
12071186
12081187test "extern union most-aligned field is smaller" {
1188 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
12091189 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1210 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
12111190 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
12121191 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
12131192
......@@ -1227,7 +1206,6 @@ test "extern union most-aligned field is smaller" {
12271206
12281207test "return an extern union from C calling convention" {
12291208 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1230 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
12311209 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
12321210 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
12331211
......@@ -1258,7 +1236,6 @@ test "return an extern union from C calling convention" {
12581236}
12591237
12601238test "noreturn field in union" {
1261 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
12621239 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
12631240 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
12641241
......@@ -1309,7 +1286,7 @@ test "noreturn field in union" {
13091286}
13101287
13111288test "@unionInit uses tag value instead of field index" {
1312 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1289 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
13131290 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
13141291 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
13151292 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1339,7 +1316,6 @@ test "@unionInit uses tag value instead of field index" {
13391316}
13401317
13411318test "union field ptr - zero sized payload" {
1342 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
13431319 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
13441320 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
13451321 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1354,7 +1330,6 @@ test "union field ptr - zero sized payload" {
13541330}
13551331
13561332test "union field ptr - zero sized field" {
1357 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
13581333 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
13591334 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
13601335 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1369,7 +1344,7 @@ test "union field ptr - zero sized field" {
13691344}
13701345
13711346test "packed union in packed struct" {
1372 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1347 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
13731348 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
13741349 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
13751350
......@@ -1420,8 +1395,8 @@ test "union int tag type is properly managed" {
14201395}
14211396
14221397test "no dependency loop when function pointer in union returns the union" {
1398 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
14231399 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1424 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
14251400 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
14261401 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" {
14421417}
14431418
14441419test "union reassignment can use previous value" {
1445 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1420 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
14461421 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
14471422 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
14481423
......@@ -1456,7 +1431,7 @@ test "union reassignment can use previous value" {
14561431}
14571432
14581433test "packed union with zero-bit field" {
1459 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1434 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
14601435 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
14611436 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
14621437
......@@ -1475,7 +1450,7 @@ test "packed union with zero-bit field" {
14751450}
14761451
14771452test "reinterpreting enum value inside packed union" {
1478 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1453 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
14791454 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
14801455
14811456 const U = packed union {
......@@ -1493,8 +1468,6 @@ test "reinterpreting enum value inside packed union" {
14931468}
14941469
14951470test "access the tag of a global tagged union" {
1496 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1497
14981471 const U = union(enum) {
14991472 a,
15001473 b: u8,
......@@ -1504,7 +1477,7 @@ test "access the tag of a global tagged union" {
15041477}
15051478
15061479test "coerce enum literal to union in result loc" {
1507 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1480 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
15081481
15091482 const U = union(enum) {
15101483 a,
......@@ -1522,7 +1495,6 @@ test "coerce enum literal to union in result loc" {
15221495test "defined-layout union field pointer has correct alignment" {
15231496 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
15241497 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1525 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
15261498 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
15271499
15281500 const S = struct {
......@@ -1557,7 +1529,6 @@ test "defined-layout union field pointer has correct alignment" {
15571529test "undefined-layout union field pointer has correct alignment" {
15581530 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
15591531 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1560 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
15611532 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
15621533
15631534 const S = struct {
......@@ -1590,8 +1561,8 @@ test "undefined-layout union field pointer has correct alignment" {
15901561}
15911562
15921563test "packed union field pointer has correct alignment" {
1564 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
15931565 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1594 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
15951566 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
15961567 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
15971568
......@@ -1624,6 +1595,7 @@ test "packed union field pointer has correct alignment" {
16241595}
16251596
16261597test "union with 128 bit integer" {
1598 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
16271599 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
16281600
16291601 const ValueTag = enum { int, other };
......@@ -1647,6 +1619,7 @@ test "union with 128 bit integer" {
16471619}
16481620
16491621test "memset extern union" {
1622 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
16501623 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
16511624
16521625 const U = extern union {
......@@ -1668,6 +1641,7 @@ test "memset extern union" {
16681641}
16691642
16701643test "memset packed union" {
1644 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
16711645 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
16721646
16731647 const U = packed union {
......@@ -1768,6 +1742,7 @@ test "reinterpret extern union" {
17681742}
17691743
17701744test "reinterpret packed union" {
1745 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
17711746 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
17721747
17731748 const U = packed union {
......@@ -1840,6 +1815,7 @@ test "reinterpret packed union" {
18401815}
18411816
18421817test "reinterpret packed union inside packed struct" {
1818 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
18431819 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
18441820 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
18451821
......@@ -1945,6 +1921,8 @@ test "extern union initialized via reintepreted struct field initializer" {
19451921}
19461922
19471923test "packed union initialized via reintepreted struct field initializer" {
1924 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1925
19481926 const bytes = [_]u8{ 0xaa, 0xbb, 0xcc, 0xdd };
19491927
19501928 const U = packed union {
......@@ -1963,6 +1941,7 @@ test "packed union initialized via reintepreted struct field initializer" {
19631941}
19641942
19651943test "store of comptime reinterpreted memory to extern union" {
1944 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
19661945 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
19671946
19681947 const bytes = [_]u8{ 0xaa, 0xbb, 0xcc, 0xdd };
......@@ -1985,6 +1964,8 @@ test "store of comptime reinterpreted memory to extern union" {
19851964}
19861965
19871966test "store of comptime reinterpreted memory to packed union" {
1967 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1968
19881969 const bytes = [_]u8{ 0xaa, 0xbb, 0xcc, 0xdd };
19891970
19901971 const U = packed union {
......@@ -2005,7 +1986,6 @@ test "store of comptime reinterpreted memory to packed union" {
20051986}
20061987
20071988test "union field is a pointer to an aligned version of itself" {
2008 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
20091989 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
20101990 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" {
20191999}
20202000
20212001test "pass register-sized field as non-register-sized union" {
2002 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
20222003 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
20232004 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
20242005
......@@ -2067,6 +2048,7 @@ test "circular dependency through pointer field of a union" {
20672048}
20682049
20692050test "pass nested union with rls" {
2051 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
20702052 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
20712053 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
20722054
......@@ -2088,8 +2070,8 @@ test "pass nested union with rls" {
20882070}
20892071
20902072test "runtime union init, most-aligned field != largest" {
2073 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
20912074 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2092 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
20932075 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
20942076 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
20952077 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -2115,7 +2097,6 @@ test "runtime union init, most-aligned field != largest" {
21152097
21162098test "copied union field doesn't alias source" {
21172099 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2118 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
21192100 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
21202101 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
21212102
......@@ -2134,7 +2115,7 @@ test "copied union field doesn't alias source" {
21342115}
21352116
21362117test "create union(enum) from other union(enum)" {
2137 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2118 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
21382119 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
21392120 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
21402121 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -2258,7 +2239,7 @@ test "matching captures causes union equivalence" {
22582239}
22592240
22602241test "signed enum tag with negative value" {
2261 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2242 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
22622243 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
22632244 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
22642245 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -2315,6 +2296,7 @@ test "extern union @FieldType" {
23152296}
23162297
23172298test "assign global tagged union" {
2299 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
23182300 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
23192301
23202302 const U = union(enum) {
test/behavior/union_with_members.zig-1
......@@ -18,7 +18,6 @@ const ET = union(enum) {
1818
1919test "enum with members" {
2020 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
21 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2221 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2322 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" {
2828}
2929
3030test "pass args directly" {
31 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
3231 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
3332
3433 try expect(addSomeStuff(.{ @as(i32, 1), @as(i32, 2), @as(i32, 3), @as(i32, 4) }) == 10);
......@@ -41,7 +40,6 @@ fn addSomeStuff(args: anytype) i32 {
4140}
4241
4342test "runtime parameter before var args" {
44 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
4543 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
4644
4745 try expect((try extraFn(10, .{})) == 0);
......@@ -94,13 +92,12 @@ fn doNothingWithFirstArg(args: anytype) void {
9492}
9593
9694test "simple variadic function" {
97 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
9895 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
9996 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10097 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
10198 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
10299 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()) {
104101 // https://github.com/ziglang/zig/issues/14096
105102 return error.SkipZigTest;
106103 }
......@@ -156,13 +153,12 @@ test "simple variadic function" {
156153}
157154
158155test "coerce reference to var arg" {
159 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
160156 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
161157 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
162158 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
163159 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
164160 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()) {
166162 // https://github.com/ziglang/zig/issues/14096
167163 return error.SkipZigTest;
168164 }
......@@ -189,13 +185,13 @@ test "coerce reference to var arg" {
189185}
190186
191187test "variadic functions" {
192 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
188 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
193189 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
194190 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
195191 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
196192 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
197193 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()) {
199195 // https://github.com/ziglang/zig/issues/14096
200196 return error.SkipZigTest;
201197 }
......@@ -236,12 +232,11 @@ test "variadic functions" {
236232}
237233
238234test "copy VaList" {
239 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
240235 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
241236 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
242237 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
243238 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()) {
245240 // https://github.com/ziglang/zig/issues/14096
246241 return error.SkipZigTest;
247242 }
......@@ -271,12 +266,11 @@ test "copy VaList" {
271266}
272267
273268test "unused VaList arg" {
274 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
275269 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
276270 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
277271 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
278272 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()) {
280274 // https://github.com/ziglang/zig/issues/14096
281275 return error.SkipZigTest;
282276 }
test/behavior/vector.zig+43-55
......@@ -8,7 +8,6 @@ const expectEqual = std.testing.expectEqual;
88
99test "implicit cast vector to array - bool" {
1010 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
11 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1211 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1312 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1413 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -25,8 +24,8 @@ test "implicit cast vector to array - bool" {
2524}
2625
2726test "vector wrap operators" {
27 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2828 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
29 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
3029 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
3130 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
3231 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -49,8 +48,8 @@ test "vector wrap operators" {
4948}
5049
5150test "vector bin compares with mem.eql" {
51 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
5252 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
53 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
5453 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
5554 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
5655 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -74,8 +73,8 @@ test "vector bin compares with mem.eql" {
7473}
7574
7675test "vector int operators" {
76 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
7777 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
78 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
7978 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
8079 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
8180 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -97,8 +96,8 @@ test "vector int operators" {
9796}
9897
9998test "vector float operators" {
99 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
100100 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
101 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
102101 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
103102 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
104103 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -141,8 +140,8 @@ test "vector float operators" {
141140}
142141
143142test "vector bit operators" {
143 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
144144 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
145 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
146145 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
147146 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
148147 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -173,7 +172,7 @@ test "vector bit operators" {
173172}
174173
175174test "implicit cast vector to array" {
176 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
175 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
177176 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
178177 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
179178 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -193,7 +192,7 @@ test "implicit cast vector to array" {
193192}
194193
195194test "array to vector" {
196 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
195 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
197196 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
198197 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
199198 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -212,7 +211,7 @@ test "array to vector" {
212211}
213212
214213test "array vector coercion - odd sizes" {
215 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
214 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
216215 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
217216 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
218217 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
......@@ -251,7 +250,7 @@ test "array vector coercion - odd sizes" {
251250}
252251
253252test "array to vector with element type coercion" {
254 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
253 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
255254 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
256255 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
257256 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
......@@ -273,7 +272,6 @@ test "array to vector with element type coercion" {
273272
274273test "peer type resolution with coercible element types" {
275274 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
276 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
277275 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
278276 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
279277
......@@ -291,8 +289,8 @@ test "peer type resolution with coercible element types" {
291289}
292290
293291test "tuple to vector" {
292 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
294293 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
295 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
296294 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
297295 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
298296 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -314,8 +312,8 @@ test "tuple to vector" {
314312}
315313
316314test "vector casts of sizes not divisible by 8" {
315 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
317316 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
318 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
319317 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
320318 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
321319 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -354,7 +352,7 @@ test "vector casts of sizes not divisible by 8" {
354352}
355353
356354test "vector @splat" {
357 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
355 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
358356 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
359357 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
360358 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -395,7 +393,7 @@ test "vector @splat" {
395393}
396394
397395test "load vector elements via comptime index" {
398 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
396 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
399397 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
400398 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
401399
......@@ -416,7 +414,7 @@ test "load vector elements via comptime index" {
416414}
417415
418416test "store vector elements via comptime index" {
419 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
417 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
420418 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
421419 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
422420
......@@ -443,7 +441,6 @@ test "store vector elements via comptime index" {
443441}
444442
445443test "load vector elements via runtime index" {
446 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
447444 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
448445 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
449446
......@@ -465,7 +462,7 @@ test "load vector elements via runtime index" {
465462}
466463
467464test "store vector elements via runtime index" {
468 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
465 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
469466 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
470467 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
471468
......@@ -487,7 +484,6 @@ test "store vector elements via runtime index" {
487484}
488485
489486test "initialize vector which is a struct field" {
490 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
491487 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
492488 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
493489
......@@ -508,8 +504,8 @@ test "initialize vector which is a struct field" {
508504}
509505
510506test "vector comparison operators" {
507 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
511508 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
512 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
513509 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
514510 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
515511 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -554,8 +550,8 @@ test "vector comparison operators" {
554550}
555551
556552test "vector division operators" {
553 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
557554 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
558 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
559555 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
560556 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
561557 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -647,9 +643,9 @@ test "vector division operators" {
647643}
648644
649645test "vector bitwise not operator" {
646 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
650647 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
651648 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
652 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
653649 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
654650 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
655651 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -681,9 +677,9 @@ test "vector bitwise not operator" {
681677}
682678
683679test "vector boolean not operator" {
680 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
684681 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
685682 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
686 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
687683 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
688684 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
689685 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -705,8 +701,8 @@ test "vector boolean not operator" {
705701}
706702
707703test "vector shift operators" {
704 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
708705 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
709 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
710706 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
711707 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
712708 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -776,8 +772,8 @@ test "vector shift operators" {
776772}
777773
778774test "vector reduce operation" {
775 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
779776 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
780 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
781777 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
782778 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
783779 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -908,7 +904,6 @@ test "vector reduce operation" {
908904
909905test "vector @reduce comptime" {
910906 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
911 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
912907 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
913908 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
914909
......@@ -924,7 +919,7 @@ test "vector @reduce comptime" {
924919}
925920
926921test "mask parameter of @shuffle is comptime scope" {
927 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
922 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
928923 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
929924 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
930925 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -946,8 +941,8 @@ test "mask parameter of @shuffle is comptime scope" {
946941}
947942
948943test "saturating add" {
944 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
949945 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
950 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
951946 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
952947 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
953948 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -980,8 +975,8 @@ test "saturating add" {
980975}
981976
982977test "saturating subtraction" {
978 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
983979 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
984 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
985980 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
986981 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
987982 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1004,8 +999,8 @@ test "saturating subtraction" {
1004999}
10051000
10061001test "saturating multiplication" {
1002 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
10071003 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1008 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10091004 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10101005 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10111006 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1032,8 +1027,8 @@ test "saturating multiplication" {
10321027}
10331028
10341029test "saturating shift-left" {
1030 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
10351031 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1036 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10371032 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10381033 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10391034 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1056,8 +1051,8 @@ test "saturating shift-left" {
10561051}
10571052
10581053test "multiplication-assignment operator with an array operand" {
1054 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
10591055 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1060 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10611056 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10621057 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10631058 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1077,8 +1072,8 @@ test "multiplication-assignment operator with an array operand" {
10771072}
10781073
10791074test "@addWithOverflow" {
1075 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
10801076 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1081 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10821077 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10831078 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10841079 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1127,8 +1122,8 @@ test "@addWithOverflow" {
11271122}
11281123
11291124test "@subWithOverflow" {
1125 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
11301126 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1131 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
11321127 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11331128 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11341129 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1161,8 +1156,8 @@ test "@subWithOverflow" {
11611156}
11621157
11631158test "@mulWithOverflow" {
1159 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
11641160 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1165 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
11661161 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11671162 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11681163 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1184,8 +1179,8 @@ test "@mulWithOverflow" {
11841179}
11851180
11861181test "@shlWithOverflow" {
1182 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
11871183 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1188 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
11891184 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11901185 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11911186 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1229,8 +1224,8 @@ test "alignment of vectors" {
12291224}
12301225
12311226test "loading the second vector from a slice of vectors" {
1227 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
12321228 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1233 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
12341229 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
12351230 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
12361231 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1246,8 +1241,8 @@ test "loading the second vector from a slice of vectors" {
12461241}
12471242
12481243test "array of vectors is copied" {
1244 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
12491245 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1250 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
12511246 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
12521247 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
12531248 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1270,8 +1265,8 @@ test "array of vectors is copied" {
12701265}
12711266
12721267test "byte vector initialized in inline function" {
1268 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
12731269 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1274 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
12751270 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
12761271 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
12771272 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1297,7 +1292,6 @@ test "byte vector initialized in inline function" {
12971292
12981293test "zero divisor" {
12991294 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1300 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
13011295 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
13021296 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
13031297
......@@ -1317,7 +1311,6 @@ test "zero divisor" {
13171311
13181312test "zero multiplicand" {
13191313 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1320 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
13211314 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
13221315 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
13231316 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
......@@ -1341,7 +1334,6 @@ test "zero multiplicand" {
13411334
13421335test "@intCast to u0" {
13431336 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1344 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
13451337 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
13461338 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
13471339 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1364,8 +1356,8 @@ test "modRem with zero divisor" {
13641356}
13651357
13661358test "array operands to shuffle are coerced to vectors" {
1359 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
13671360 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1368 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
13691361 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
13701362 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
13711363 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1379,7 +1371,7 @@ test "array operands to shuffle are coerced to vectors" {
13791371}
13801372
13811373test "load packed vector element" {
1382 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1374 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
13831375 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
13841376 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
13851377 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
......@@ -1391,7 +1383,7 @@ test "load packed vector element" {
13911383}
13921384
13931385test "store packed vector element" {
1394 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1386 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
13951387 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
13961388 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
13971389 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
......@@ -1408,7 +1400,7 @@ test "store packed vector element" {
14081400}
14091401
14101402test "store to vector in slice" {
1411 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1403 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
14121404 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
14131405 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
14141406 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -1426,7 +1418,7 @@ test "store to vector in slice" {
14261418}
14271419
14281420test "store vector with memset" {
1429 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1421 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
14301422 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
14311423 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
14321424 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -1459,7 +1451,7 @@ test "store vector with memset" {
14591451}
14601452
14611453test "addition of vectors represented as strings" {
1462 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1454 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
14631455 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
14641456
14651457 const V = @Vector(3, u8);
......@@ -1469,7 +1461,7 @@ test "addition of vectors represented as strings" {
14691461}
14701462
14711463test "compare vectors with different element types" {
1472 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1464 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
14731465 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
14741466 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
14751467 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -1482,7 +1474,6 @@ test "compare vectors with different element types" {
14821474}
14831475
14841476test "vector pointer is indexable" {
1485 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
14861477 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
14871478 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
14881479 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -1506,7 +1497,6 @@ test "vector pointer is indexable" {
15061497}
15071498
15081499test "boolean vector with 2 or more booleans" {
1509 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
15101500 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
15111501 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
15121502 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -1519,7 +1509,7 @@ test "boolean vector with 2 or more booleans" {
15191509}
15201510
15211511test "bitcast to vector with different child type" {
1522 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1512 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
15231513 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
15241514 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
15251515 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -1551,7 +1541,6 @@ test "index into comptime-known vector is comptime-known" {
15511541
15521542test "arithmetic on zero-length vectors" {
15531543 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1554 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
15551544 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
15561545
15571546 {
......@@ -1568,7 +1557,6 @@ test "arithmetic on zero-length vectors" {
15681557
15691558test "@reduce on bool vector" {
15701559 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1571 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
15721560 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
15731561
15741562 const a = @Vector(2, bool){ true, true };
......@@ -1578,7 +1566,7 @@ test "@reduce on bool vector" {
15781566}
15791567
15801568test "bitcast vector to array of smaller vectors" {
1581 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1569 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
15821570 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
15831571 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
15841572
test/behavior/void.zig-1
......@@ -36,7 +36,6 @@ fn times(n: usize) []const void {
3636
3737test "void optional" {
3838 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
39 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
4039 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
4140
4241 var x: ?void = {};
test/behavior/while.zig-9
......@@ -124,8 +124,6 @@ test "while copies its payload" {
124124}
125125
126126test "continue and break" {
127 if (builtin.zig_backend == .stage2_aarch64 and builtin.os.tag == .macos) return error.SkipZigTest;
128
129127 try runContinueAndBreakTest();
130128 try expect(continue_and_break_counter == 8);
131129}
......@@ -209,7 +207,6 @@ test "while on bool with else result follow break prong" {
209207
210208test "while on optional with else result follow else prong" {
211209 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
212 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
213210 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
214211
215212 const result = while (returnNull()) |value| {
......@@ -220,7 +217,6 @@ test "while on optional with else result follow else prong" {
220217
221218test "while on optional with else result follow break prong" {
222219 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
223 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
224220 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
225221
226222 const result = while (returnOptional(10)) |value| {
......@@ -292,7 +288,6 @@ test "while bool 2 break statements and an else" {
292288
293289test "while optional 2 break statements and an else" {
294290 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
295 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
296291 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
297292
298293 const S = struct {
......@@ -311,7 +306,6 @@ test "while optional 2 break statements and an else" {
311306
312307test "while error 2 break statements and an else" {
313308 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
314 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
315309 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
316310
317311 const S = struct {
......@@ -349,7 +343,6 @@ test "else continue outer while" {
349343
350344test "try terminating an infinite loop" {
351345 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
352 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
353346 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
354347
355348 // 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
376369}
377370
378371test "int returned from switch in while" {
379 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
380372 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
381373
382374 var x: u32 = 3;
......@@ -389,7 +381,6 @@ test "int returned from switch in while" {
389381
390382test "breaking from a loop in an if statement" {
391383 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
392 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
393384 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
394385
395386 const S = struct {
test/behavior/widening.zig-5
......@@ -4,7 +4,6 @@ const mem = std.mem;
44const builtin = @import("builtin");
55
66test "integer widening" {
7 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
87 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
98 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
109 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -29,7 +28,6 @@ test "integer widening u0 to u8" {
2928}
3029
3130test "implicit unsigned integer to signed integer" {
32 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
3331 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
3432 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
3533
......@@ -40,7 +38,6 @@ test "implicit unsigned integer to signed integer" {
4038}
4139
4240test "float widening" {
43 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
4441 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
4542 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
4643 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -60,7 +57,6 @@ test "float widening" {
6057}
6158
6259test "float widening f16 to f128" {
63 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
6460 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
6561 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
6662 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -73,7 +69,6 @@ test "float widening f16 to f128" {
7369}
7470
7571test "cast small unsigned to larger signed" {
76 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
7772 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
7873 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
7974 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
test/c_import/macros.zig-12
......@@ -25,7 +25,6 @@ test "casting to void with a macro" {
2525
2626test "initializer list expression" {
2727 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
28 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2928 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
3029 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
3130
......@@ -38,7 +37,6 @@ test "initializer list expression" {
3837}
3938
4039test "sizeof in macros" {
41 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
4240 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
4341 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
4442
......@@ -55,7 +53,6 @@ test "reference to a struct type" {
5553
5654test "cast negative integer to pointer" {
5755 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
58 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
5956 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
6057 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
6158
......@@ -64,7 +61,6 @@ test "cast negative integer to pointer" {
6461
6562test "casting to union with a macro" {
6663 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
67 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
6864 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
6965 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
7066
......@@ -80,7 +76,6 @@ test "casting to union with a macro" {
8076
8177test "casting or calling a value with a paren-surrounded macro" {
8278 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
83 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
8479 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
8580 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
8681
......@@ -99,7 +94,6 @@ test "casting or calling a value with a paren-surrounded macro" {
9994
10095test "nested comma operator" {
10196 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
102 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10397 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10498 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
10599
......@@ -109,7 +103,6 @@ test "nested comma operator" {
109103
110104test "cast functions" {
111105 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
112 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
113106 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
114107 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
115108
......@@ -123,7 +116,6 @@ test "cast functions" {
123116test "large integer macro" {
124117 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
125118 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
126 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
127119 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
128120 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
129121
......@@ -132,7 +124,6 @@ test "large integer macro" {
132124
133125test "string literal macro with embedded tab character" {
134126 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
135 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
136127 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
137128 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
138129
......@@ -141,7 +132,6 @@ test "string literal macro with embedded tab character" {
141132
142133test "string and char literals that are not UTF-8 encoded. Issue #12784" {
143134 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
144 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
145135 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
146136 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
147137
......@@ -152,7 +142,6 @@ test "string and char literals that are not UTF-8 encoded. Issue #12784" {
152142test "Macro that uses division operator. Issue #13162" {
153143 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
154144 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
155 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
156145 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
157146 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
158147 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
......@@ -196,7 +185,6 @@ test "Macro that uses division operator. Issue #13162" {
196185test "Macro that uses remainder operator. Issue #13346" {
197186 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
198187 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
199 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
200188 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
201189 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
202190
test/cases/array_in_anon_struct.zig+1-1
......@@ -19,4 +19,4 @@ pub fn main() !void {
1919
2020// run
2121// backend=stage2,llvm
22// target=native
22// 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 {}
77// target=aarch64-linux-none
88//
99// :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'
11// :1:30: error: calling convention 'avr_interrupt' only available on architectures 'avr'
10// :2:30: error: calling convention 'x86_interrupt' only available on architectures 'x86'
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 {
2525
2626// error
2727// backend=stage2
28// target=native
28// target=x86_64-linux
2929//
3030// :23:29: error: expected type 'error{InvalidCharacter}', found '@typeInfo(@typeInfo(@TypeOf(tmp.fooey)).@"fn".return_type.?).error_union.error_set'
3131// :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 {
1010
1111// error
1212// backend=stage2
13// target=native
13// target=x86_64-linux
1414//
1515// :8:41: error: expected type '*align(2) const fn () void', found '*const fn () void'
1616// :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 {
1515
1616// error
1717// backend=stage2
18// target=native
18// target=x86_64-linux
1919//
2020// :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 {
66
77// error
88// backend=stage2
9// target=native
9// target=x86_64-linux
1010//
1111// :2:23: error: expected error union type, found 'bool'
test/cases/pic_freestanding.zig+1-1
......@@ -1,7 +1,7 @@
11const builtin = @import("builtin");
22const std = @import("std");
33
4fn _start() callconv(.naked) void {}
4pub fn _start() callconv(.naked) void {}
55
66comptime {
77 @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 {
2222}
2323// run
2424// backend=stage2,llvm
25// target=native
25// 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 {}
2323
2424// run
2525// backend=stage2,llvm
26// target=native
26// target=x86_64-linux
test/cases/safety/@enumFromInt truncated bits - exhaustive.zig +1-1
......@@ -20,4 +20,4 @@ pub fn main() u8 {
2020
2121// run
2222// backend=stage2,llvm
23// target=native
23// target=x86_64-linux
test/cases/safety/@enumFromInt truncated bits - nonexhaustive.zig +1-1
......@@ -20,4 +20,4 @@ pub fn main() u8 {
2020
2121// run
2222// backend=stage2,llvm
23// target=native
23// 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 {
1818}
1919// run
2020// backend=stage2,llvm
21// target=native
21// 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 {
1717}
1818// run
1919// backend=stage2,llvm
20// target=native
20// 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 {
1919}
2020// run
2121// backend=stage2,llvm
22// target=native
22// 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 {
1313}
1414// run
1515// backend=stage2,llvm
16// target=native
16// 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 {
1313}
1414// run
1515// backend=stage2,llvm
16// target=native
16// 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 {
1313}
1414// run
1515// backend=stage2,llvm
16// target=native
16// 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 {
1313}
1414// run
1515// backend=stage2,llvm
16// target=native
16// 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 {
1313}
1414// run
1515// backend=stage2,llvm
16// target=native
16// 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 {
1313}
1414// run
1515// backend=stage2,llvm
16// target=native
16// 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 {
1313}
1414// run
1515// backend=stage2,llvm
16// target=native
16// 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 {
1313}
1414// run
1515// backend=stage2,llvm
16// target=native
16// 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 {
1313}
1414// run
1515// backend=stage2,llvm
16// target=native
16// 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 {
1313}
1414// run
1515// backend=stage2,llvm
16// target=native
16// 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 {
1717fn baz(_: i8) void {}
1818// run
1919// backend=stage2,llvm
20// target=native
20// 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 {
1717fn baz(_: u8) void {}
1818// run
1919// backend=stage2,llvm
20// target=native
20// 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 {
1717fn baz(_: u8) void {}
1818// run
1919// backend=stage2,llvm
20// target=native
20// 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 {
1616}
1717// run
1818// backend=stage2,llvm
19// target=native
19// 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 {
1616}
1717// run
1818// backend=stage2,llvm
19// target=native
19// target=x86_64-linux,aarch64-linux
test/cases/safety/@ptrFromInt with misaligned address.zig +1-1
......@@ -16,4 +16,4 @@ pub fn main() !void {
1616}
1717// run
1818// backend=stage2,llvm
19// target=native
19// 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 {
2323
2424// run
2525// backend=stage2,llvm
26// target=native
26// target=x86_64-linux
test/cases/safety/@tagName on corrupted union value.zig +1-1
......@@ -24,4 +24,4 @@ pub fn main() !void {
2424
2525// run
2626// backend=stage2,llvm
27// target=native
27// target=x86_64-linux
test/cases/safety/array slice sentinel mismatch vector.zig +1-1
......@@ -16,4 +16,4 @@ pub fn main() !void {
1616}
1717// run
1818// backend=stage2,llvm
19// target=native
19// target=x86_64-linux
test/cases/safety/array slice sentinel mismatch.zig +1-1
......@@ -16,4 +16,4 @@ pub fn main() !void {
1616}
1717// run
1818// backend=stage2,llvm
19// target=native
19// 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 {
2424}
2525// run
2626// backend=stage2,llvm
27// target=native
27// target=x86_64-linux
test/cases/safety/calling panic.zig +1-1
......@@ -13,4 +13,4 @@ pub fn main() !void {
1313}
1414// run
1515// backend=stage2,llvm
16// target=native
16// 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 {
1818}
1919// run
2020// backend=stage2,llvm
21// target=native
21// 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 {
1616}
1717// run
1818// backend=stage2,llvm
19// target=native
19// 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 {
1818
1919// run
2020// backend=stage2,llvm
21// target=native
21// 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) {
2020}
2121// run
2222// backend=stage2,llvm
23// target=native
23// target=x86_64-linux
test/cases/safety/exact division failure.zig +1-1
......@@ -18,4 +18,4 @@ fn divExact(a: i32, b: i32) i32 {
1818}
1919// run
2020// backend=stage2,llvm
21// target=native
21// target=x86_64-linux,aarch64-linux
test/cases/safety/for_len_mismatch.zig+1-1
......@@ -22,4 +22,4 @@ pub fn main() !void {
2222}
2323// run
2424// backend=stage2,llvm
25// target=native
25// target=x86_64-linux,aarch64-linux
test/cases/safety/for_len_mismatch_three.zig+1-1
......@@ -21,4 +21,4 @@ pub fn main() !void {
2121}
2222// run
2323// backend=stage2,llvm
24// target=native
24// target=x86_64-linux,aarch64-linux
test/cases/safety/ignored expression integer overflow.zig +1-1
......@@ -18,4 +18,4 @@ pub fn main() !void {
1818
1919// run
2020// backend=stage2,llvm
21// target=native
21// target=x86_64-linux
test/cases/safety/integer addition overflow.zig +1-1
......@@ -20,4 +20,4 @@ fn add(a: u16, b: u16) u16 {
2020
2121// run
2222// backend=stage2,llvm
23// target=native
23// 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) {
1919}
2020// run
2121// backend=stage2,llvm
22// target=native
22// 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 {
1717}
1818// run
1919// backend=stage2,llvm
20// target=native
20// 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 {
1818}
1919// run
2020// backend=stage2,llvm
21// target=native
21// target=x86_64-linux,aarch64-linux
test/cases/safety/integer negation overflow.zig +1-1
......@@ -18,4 +18,4 @@ fn neg(a: i16) i16 {
1818}
1919// run
2020// backend=stage2,llvm
21// target=native
21// 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 {
1818}
1919// run
2020// backend=stage2,llvm
21// target=native
21// target=x86_64-linux,aarch64-linux
test/cases/safety/memcpy_alias.zig+1-1
......@@ -16,4 +16,4 @@ pub fn main() !void {
1616}
1717// run
1818// backend=stage2,llvm
19// target=native
19// target=x86_64-linux,aarch64-linux
test/cases/safety/memcpy_len_mismatch.zig+1-1
......@@ -16,4 +16,4 @@ pub fn main() !void {
1616}
1717// run
1818// backend=stage2,llvm
19// target=native
19// target=x86_64-linux,aarch64-linux
test/cases/safety/memmove_len_mismatch.zig+1-1
......@@ -16,4 +16,4 @@ pub fn main() !void {
1616}
1717// run
1818// backend=stage2,llvm
19// target=native
19// target=x86_64-linux,aarch64-linux
test/cases/safety/memset_array_undefined_bytes.zig+1-1
......@@ -15,4 +15,4 @@ pub fn main() !void {
1515}
1616// run
1717// backend=stage2,llvm
18// target=native
18// target=x86_64-linux,aarch64-linux
test/cases/safety/memset_array_undefined_large.zig+1-1
......@@ -15,4 +15,4 @@ pub fn main() !void {
1515}
1616// run
1717// backend=stage2,llvm
18// target=native
18// target=x86_64-linux,aarch64-linux
test/cases/safety/memset_slice_undefined_bytes.zig+1-1
......@@ -17,4 +17,4 @@ pub fn main() !void {
1717}
1818// run
1919// backend=stage2,llvm
20// target=native
20// target=x86_64-linux,aarch64-linux
test/cases/safety/memset_slice_undefined_large.zig+1-1
......@@ -17,4 +17,4 @@ pub fn main() !void {
1717}
1818// run
1919// backend=stage2,llvm
20// target=native
20// 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 {
1717}
1818// run
1919// backend=stage2,llvm
20// target=native
20// 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 {
1717}
1818// run
1919// backend=stage2,llvm
20// target=native
20// target=x86_64-linux
test/cases/safety/noreturn returned.zig +1-1
......@@ -20,4 +20,4 @@ pub fn main() void {
2020}
2121// run
2222// backend=stage2,llvm
23// target=native
23// 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 {
1616}
1717// run
1818// backend=stage2,llvm
19// target=native
19// 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 {
1616}
1717// run
1818// backend=stage2,llvm
19// target=native
19// target=x86_64-linux,aarch64-linux
test/cases/safety/optional_empty_error_set.zig+1-1
......@@ -19,4 +19,4 @@ fn foo() !void {
1919}
2020// run
2121// backend=stage2,llvm
22// target=native
22// 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 {
1717}
1818// run
1919// backend=stage2,llvm
20// target=native
20// 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 {
1818fn baz(_: i32) void {}
1919// run
2020// backend=stage2,llvm
21// target=native
21// 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 {
1818
1919// run
2020// backend=stage2,llvm
21// target=native
21// 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 {
2020
2121// run
2222// backend=stage2,llvm
23// target=native
23// target=x86_64-linux,aarch64-linux
test/cases/safety/pointer slice sentinel mismatch.zig +1-1
......@@ -18,4 +18,4 @@ pub fn main() !void {
1818
1919// run
2020// backend=stage2,llvm
21// target=native
21// 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 {
1717}
1818// run
1919// backend=stage2,llvm
20// target=native
20// 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 {
1919
2020// run
2121// backend=stage2,llvm
22// target=native
22// 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 {
1919
2020// run
2121// backend=stage2,llvm
22// target=native
22// 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) {
2020}
2121// run
2222// backend=stage2,llvm
23// target=native
23// 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 {
1818}
1919// run
2020// backend=stage2,llvm
21// target=native
21// 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 {
1616}
1717// run
1818// backend=stage2,llvm
19// target=native
19// 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 {
1717}
1818// run
1919// backend=stage2,llvm
20// target=native
20// 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 {
1818}
1919// run
2020// backend=stage2,llvm
21// target=native
21// 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 {
1818}
1919// run
2020// backend=stage2,llvm
21// target=native
21// target=x86_64-linux,aarch64-linux
test/cases/safety/signed-unsigned vector cast.zig +1-1
......@@ -18,4 +18,4 @@ pub fn main() !void {
1818
1919// run
2020// backend=stage2,llvm
21// target=native
21// 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 {
1515}
1616// run
1717// backend=stage2,llvm
18// target=native
18// 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 {
1515}
1616// run
1717// backend=stage2,llvm
18// target=native
18// target=x86_64-linux,aarch64-linux
test/cases/safety/slice sentinel mismatch - floats.zig +1-1
......@@ -17,4 +17,4 @@ pub fn main() !void {
1717
1818// run
1919// backend=stage2,llvm
20// target=native
20// target=x86_64-linux
test/cases/safety/slice sentinel mismatch - optional pointers.zig +1-1
......@@ -17,4 +17,4 @@ pub fn main() !void {
1717
1818// run
1919// backend=stage2,llvm
20// target=native
20// target=x86_64-linux,aarch64-linux
test/cases/safety/slice slice sentinel mismatch.zig +1-1
......@@ -16,4 +16,4 @@ pub fn main() !void {
1616}
1717// run
1818// backend=stage2,llvm
19// target=native
19// 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 {
2121
2222// run
2323// backend=stage2,llvm
24// target=native
24// 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 {
2020
2121// run
2222// backend=stage2,llvm
23// target=native
23// 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 {
1818
1919// run
2020// backend=stage2,llvm
21// target=native
21// 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");
2424
2525// run
2626// backend=stage2,llvm
27// target=x86_64-linux
27// 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");
2424
2525// run
2626// backend=stage2,llvm
27// target=x86_64-linux
27// 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");
2424
2525// run
2626// backend=stage2,llvm
27// target=x86_64-linux
27// 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 {
1818}
1919// run
2020// backend=stage2,llvm
21// target=native
21// target=x86_64-linux,aarch64-linux
test/cases/safety/slicing null C pointer.zig +1-1
......@@ -17,4 +17,4 @@ pub fn main() !void {
1717}
1818// run
1919// backend=stage2,llvm
20// target=native
20// 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 {
2121}
2222// run
2323// backend=stage2,llvm
24// target=native
24// 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 {
2626}
2727// run
2828// backend=stage2,llvm
29// target=native
29// target=x86_64-linux
test/cases/safety/switch else on corrupt enum value.zig +1-1
......@@ -20,4 +20,4 @@ pub fn main() !void {
2020}
2121// run
2222// backend=stage2,llvm
23// target=native
23// target=x86_64-linux
test/cases/safety/switch on corrupted enum value.zig +1-1
......@@ -24,4 +24,4 @@ pub fn main() !void {
2424
2525// run
2626// backend=stage2,llvm
27// target=native
27// 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 {
2424
2525// run
2626// backend=stage2,llvm
27// target=native
27// target=x86_64-linux
test/cases/safety/truncating vector cast.zig +1-1
......@@ -18,4 +18,4 @@ pub fn main() !void {
1818
1919// run
2020// backend=stage2,llvm
21// target=native
21// target=x86_64-linux
test/cases/safety/unreachable.zig+1-1
......@@ -12,4 +12,4 @@ pub fn main() !void {
1212}
1313// run
1414// backend=stage2,llvm
15// target=native
15// 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 {
1616}
1717// run
1818// backend=stage2,llvm
19// target=native
19// 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 {
1818}
1919// run
2020// backend=stage2,llvm
21// target=native
21// 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 {
1818}
1919// run
2020// backend=stage2,llvm
21// target=native
21// target=x86_64-linux,aarch64-linux
test/cases/safety/unsigned-signed vector cast.zig +1-1
......@@ -18,4 +18,4 @@ pub fn main() !void {
1818
1919// run
2020// backend=stage2,llvm
21// target=native
21// target=x86_64-linux
test/cases/safety/unwrap error switch.zig +1-1
......@@ -18,4 +18,4 @@ fn bar() !void {
1818}
1919// run
2020// backend=stage2,llvm
21// target=native
21// target=x86_64-linux,aarch64-linux
test/cases/safety/unwrap error.zig +1-1
......@@ -16,4 +16,4 @@ fn bar() !void {
1616}
1717// run
1818// backend=stage2,llvm
19// target=native
19// 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 {
1818}
1919// run
2020// backend=stage2,llvm
21// target=native
21// 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 {
1818}
1919// run
2020// backend=stage2,llvm
21// target=native
21// 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) {
1919}
2020// run
2121// backend=stage2,llvm
22// target=native
22// 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) {
1919}
2020// run
2121// backend=stage2,llvm
22// target=native
22// 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) {
1919}
2020// run
2121// backend=stage2,llvm
22// target=native
22// 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) {
1919}
2020// run
2121// backend=stage2,llvm
22// target=native
22// target=x86_64-linux
test/cases/safety/zero casted to error.zig +1-1
......@@ -16,4 +16,4 @@ fn bar(x: u16) anyerror {
1616}
1717// run
1818// backend=stage2,llvm
19// target=native
19// 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 {
2323
2424// run
2525// backend=stage2,llvm
26// target=native
26// 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 @@
11.{
2 .name = "link_test_cases",
2 .name = .link_test_cases,
3 .fingerprint = 0x404f657576fec9f2,
34 .version = "0.0.0",
45 .dependencies = .{
56 .bss = .{
test/link/elf.zig+369-369
......@@ -210,8 +210,8 @@ fn testAbsSymbols(b: *Build, opts: Options) *Step {
210210 \\}
211211 ,
212212 });
213 exe.addObject(obj);
214 exe.linkLibC();
213 exe.root_module.addObject(obj);
214 exe.root_module.link_libc = true;
215215
216216 const run = addRunArtifact(exe);
217217 run.expectExitCode(0);
......@@ -235,7 +235,7 @@ fn testAsNeeded(b: *Build, opts: Options) *Step {
235235 \\
236236 ,
237237 });
238 main_o.linkLibC();
238 main_o.root_module.link_libc = true;
239239
240240 const libfoo = addSharedLibrary(b, opts, .{ .name = "foo" });
241241 addCSourceBytes(libfoo, "int foo() { return 42; }", &.{});
......@@ -253,17 +253,17 @@ fn testAsNeeded(b: *Build, opts: Options) *Step {
253253 const exe = addExecutable(b, opts, .{
254254 .name = "test",
255255 });
256 exe.addObject(main_o);
257 exe.linkSystemLibrary2("foo", .{ .needed = true });
258 exe.addLibraryPath(libfoo.getEmittedBinDirectory());
259 exe.addRPath(libfoo.getEmittedBinDirectory());
260 exe.linkSystemLibrary2("bar", .{ .needed = true });
261 exe.addLibraryPath(libbar.getEmittedBinDirectory());
262 exe.addRPath(libbar.getEmittedBinDirectory());
263 exe.linkSystemLibrary2("baz", .{ .needed = true });
264 exe.addLibraryPath(libbaz.getEmittedBinDirectory());
265 exe.addRPath(libbaz.getEmittedBinDirectory());
266 exe.linkLibC();
256 exe.root_module.addObject(main_o);
257 exe.root_module.linkSystemLibrary("foo", .{ .needed = true });
258 exe.root_module.addLibraryPath(libfoo.getEmittedBinDirectory());
259 exe.root_module.addRPath(libfoo.getEmittedBinDirectory());
260 exe.root_module.linkSystemLibrary("bar", .{ .needed = true });
261 exe.root_module.addLibraryPath(libbar.getEmittedBinDirectory());
262 exe.root_module.addRPath(libbar.getEmittedBinDirectory());
263 exe.root_module.linkSystemLibrary("baz", .{ .needed = true });
264 exe.root_module.addLibraryPath(libbaz.getEmittedBinDirectory());
265 exe.root_module.addRPath(libbaz.getEmittedBinDirectory());
266 exe.root_module.link_libc = true;
267267
268268 const run = addRunArtifact(exe);
269269 run.expectStdOutEqual("42\n");
......@@ -281,17 +281,17 @@ fn testAsNeeded(b: *Build, opts: Options) *Step {
281281 const exe = addExecutable(b, opts, .{
282282 .name = "test",
283283 });
284 exe.addObject(main_o);
285 exe.linkSystemLibrary2("foo", .{ .needed = false });
286 exe.addLibraryPath(libfoo.getEmittedBinDirectory());
287 exe.addRPath(libfoo.getEmittedBinDirectory());
288 exe.linkSystemLibrary2("bar", .{ .needed = false });
289 exe.addLibraryPath(libbar.getEmittedBinDirectory());
290 exe.addRPath(libbar.getEmittedBinDirectory());
291 exe.linkSystemLibrary2("baz", .{ .needed = false });
292 exe.addLibraryPath(libbaz.getEmittedBinDirectory());
293 exe.addRPath(libbaz.getEmittedBinDirectory());
294 exe.linkLibC();
284 exe.root_module.addObject(main_o);
285 exe.root_module.linkSystemLibrary("foo", .{ .needed = false });
286 exe.root_module.addLibraryPath(libfoo.getEmittedBinDirectory());
287 exe.root_module.addRPath(libfoo.getEmittedBinDirectory());
288 exe.root_module.linkSystemLibrary("bar", .{ .needed = false });
289 exe.root_module.addLibraryPath(libbar.getEmittedBinDirectory());
290 exe.root_module.addRPath(libbar.getEmittedBinDirectory());
291 exe.root_module.linkSystemLibrary("baz", .{ .needed = false });
292 exe.root_module.addLibraryPath(libbaz.getEmittedBinDirectory());
293 exe.root_module.addRPath(libbaz.getEmittedBinDirectory());
294 exe.root_module.link_libc = true;
295295
296296 const run = addRunArtifact(exe);
297297 run.expectStdOutEqual("42\n");
......@@ -351,15 +351,15 @@ fn testCanonicalPlt(b: *Build, opts: Options) *Step {
351351 ,
352352 .pic = false,
353353 });
354 main_o.linkLibC();
354 main_o.root_module.link_libc = true;
355355
356356 const exe = addExecutable(b, opts, .{
357357 .name = "main",
358358 });
359 exe.addObject(main_o);
360 exe.addObject(b_o);
361 exe.linkLibrary(dso);
362 exe.linkLibC();
359 exe.root_module.addObject(main_o);
360 exe.root_module.addObject(b_o);
361 exe.root_module.linkLibrary(dso);
362 exe.root_module.link_libc = true;
363363 exe.pie = false;
364364
365365 const run = addRunArtifact(exe);
......@@ -384,7 +384,7 @@ fn testComdatElimination(b: *Build, opts: Options) *Step {
384384 \\}
385385 ,
386386 });
387 a_o.linkLibCpp();
387 a_o.root_module.link_libcpp = true;
388388
389389 const main_o = addObject(b, opts, .{
390390 .name = "main",
......@@ -401,13 +401,13 @@ fn testComdatElimination(b: *Build, opts: Options) *Step {
401401 \\}
402402 ,
403403 });
404 main_o.linkLibCpp();
404 main_o.root_module.link_libcpp = true;
405405
406406 {
407407 const exe = addExecutable(b, opts, .{ .name = "main1" });
408 exe.addObject(a_o);
409 exe.addObject(main_o);
410 exe.linkLibCpp();
408 exe.root_module.addObject(a_o);
409 exe.root_module.addObject(main_o);
410 exe.root_module.link_libcpp = true;
411411
412412 const run = addRunArtifact(exe);
413413 run.expectStdOutEqual(
......@@ -420,9 +420,9 @@ fn testComdatElimination(b: *Build, opts: Options) *Step {
420420
421421 {
422422 const exe = addExecutable(b, opts, .{ .name = "main2" });
423 exe.addObject(main_o);
424 exe.addObject(a_o);
425 exe.linkLibCpp();
423 exe.root_module.addObject(main_o);
424 exe.root_module.addObject(a_o);
425 exe.root_module.link_libcpp = true;
426426
427427 const run = addRunArtifact(exe);
428428 run.expectStdOutEqual(
......@@ -435,12 +435,12 @@ fn testComdatElimination(b: *Build, opts: Options) *Step {
435435
436436 {
437437 const c_o = addObject(b, opts, .{ .name = "c" });
438 c_o.addObject(main_o);
439 c_o.addObject(a_o);
438 c_o.root_module.addObject(main_o);
439 c_o.root_module.addObject(a_o);
440440
441441 const exe = addExecutable(b, opts, .{ .name = "main3" });
442 exe.addObject(c_o);
443 exe.linkLibCpp();
442 exe.root_module.addObject(c_o);
443 exe.root_module.link_libcpp = true;
444444
445445 const run = addRunArtifact(exe);
446446 run.expectStdOutEqual(
......@@ -453,12 +453,12 @@ fn testComdatElimination(b: *Build, opts: Options) *Step {
453453
454454 {
455455 const d_o = addObject(b, opts, .{ .name = "d" });
456 d_o.addObject(a_o);
457 d_o.addObject(main_o);
456 d_o.root_module.addObject(a_o);
457 d_o.root_module.addObject(main_o);
458458
459459 const exe = addExecutable(b, opts, .{ .name = "main4" });
460 exe.addObject(d_o);
461 exe.linkLibCpp();
460 exe.root_module.addObject(d_o);
461 exe.root_module.link_libcpp = true;
462462
463463 const run = addRunArtifact(exe);
464464 run.expectStdOutEqual(
......@@ -522,7 +522,7 @@ fn testCommonSymbols(b: *Build, opts: Options) *Step {
522522 \\ printf("%d %d %d\n", foo, bar, baz);
523523 \\}
524524 , &.{"-fcommon"});
525 exe.linkLibC();
525 exe.root_module.link_libc = true;
526526
527527 const run = addRunArtifact(exe);
528528 run.expectStdOutEqual("0 5 42\n");
......@@ -549,7 +549,7 @@ fn testCommonSymbolsInArchive(b: *Build, opts: Options) *Step {
549549 ,
550550 .c_source_flags = &.{"-fcommon"},
551551 });
552 a_o.linkLibC();
552 a_o.root_module.link_libc = true;
553553
554554 const b_o = addObject(b, opts, .{
555555 .name = "b",
......@@ -575,16 +575,16 @@ fn testCommonSymbolsInArchive(b: *Build, opts: Options) *Step {
575575 });
576576
577577 const lib = addStaticLibrary(b, opts, .{ .name = "lib" });
578 lib.addObject(b_o);
579 lib.addObject(c_o);
580 lib.addObject(d_o);
578 lib.root_module.addObject(b_o);
579 lib.root_module.addObject(c_o);
580 lib.root_module.addObject(d_o);
581581
582582 const exe = addExecutable(b, opts, .{
583583 .name = "test",
584584 });
585 exe.addObject(a_o);
586 exe.linkLibrary(lib);
587 exe.linkLibC();
585 exe.root_module.addObject(a_o);
586 exe.root_module.linkLibrary(lib);
587 exe.root_module.link_libc = true;
588588
589589 const run = addRunArtifact(exe);
590590 run.expectStdOutEqual("5 0 0 -1\n");
......@@ -603,15 +603,15 @@ fn testCommonSymbolsInArchive(b: *Build, opts: Options) *Step {
603603 });
604604
605605 const lib = addStaticLibrary(b, opts, .{ .name = "lib" });
606 lib.addObject(b_o);
607 lib.addObject(e_o);
606 lib.root_module.addObject(b_o);
607 lib.root_module.addObject(e_o);
608608
609609 const exe = addExecutable(b, opts, .{
610610 .name = "test",
611611 });
612 exe.addObject(a_o);
613 exe.linkLibrary(lib);
614 exe.linkLibC();
612 exe.root_module.addObject(a_o);
613 exe.root_module.linkLibrary(lib);
614 exe.root_module.link_libc = true;
615615
616616 const run = addRunArtifact(exe);
617617 run.expectStdOutEqual("5 0 7 2\n");
......@@ -641,8 +641,8 @@ fn testCopyrel(b: *Build, opts: Options) *Step {
641641 \\}
642642 ,
643643 });
644 exe.linkLibrary(dso);
645 exe.linkLibC();
644 exe.root_module.linkLibrary(dso);
645 exe.root_module.link_libc = true;
646646
647647 const run = addRunArtifact(exe);
648648 run.expectStdOutEqual("3 5\n");
......@@ -679,8 +679,8 @@ fn testCopyrelAlias(b: *Build, opts: Options) *Step {
679679 \\extern int bar;
680680 \\int *get_bar() { return &bar; }
681681 , &.{});
682 exe.linkLibrary(dso);
683 exe.linkLibC();
682 exe.root_module.linkLibrary(dso);
683 exe.root_module.link_libc = true;
684684 exe.pie = false;
685685
686686 const run = addRunArtifact(exe);
......@@ -712,15 +712,15 @@ fn testCopyrelAlignment(b: *Build, opts: Options) *Step {
712712 ,
713713 .pic = false,
714714 });
715 obj.linkLibC();
715 obj.root_module.link_libc = true;
716716
717717 const exp_stdout = "5\n";
718718
719719 {
720720 const exe = addExecutable(b, opts, .{ .name = "main" });
721 exe.addObject(obj);
722 exe.linkLibrary(a_so);
723 exe.linkLibC();
721 exe.root_module.addObject(obj);
722 exe.root_module.linkLibrary(a_so);
723 exe.root_module.link_libc = true;
724724 exe.pie = false;
725725
726726 const run = addRunArtifact(exe);
......@@ -737,9 +737,9 @@ fn testCopyrelAlignment(b: *Build, opts: Options) *Step {
737737
738738 {
739739 const exe = addExecutable(b, opts, .{ .name = "main" });
740 exe.addObject(obj);
741 exe.linkLibrary(b_so);
742 exe.linkLibC();
740 exe.root_module.addObject(obj);
741 exe.root_module.linkLibrary(b_so);
742 exe.root_module.link_libc = true;
743743 exe.pie = false;
744744
745745 const run = addRunArtifact(exe);
......@@ -756,9 +756,9 @@ fn testCopyrelAlignment(b: *Build, opts: Options) *Step {
756756
757757 {
758758 const exe = addExecutable(b, opts, .{ .name = "main" });
759 exe.addObject(obj);
760 exe.linkLibrary(c_so);
761 exe.linkLibC();
759 exe.root_module.addObject(obj);
760 exe.root_module.linkLibrary(c_so);
761 exe.root_module.link_libc = true;
762762 exe.pie = false;
763763
764764 const run = addRunArtifact(exe);
......@@ -793,7 +793,7 @@ fn testDsoPlt(b: *Build, opts: Options) *Step {
793793 \\ real_hello();
794794 \\}
795795 , &.{});
796 dso.linkLibC();
796 dso.root_module.link_libc = true;
797797
798798 const exe = addExecutable(b, opts, .{ .name = "test" });
799799 addCSourceBytes(exe,
......@@ -806,8 +806,8 @@ fn testDsoPlt(b: *Build, opts: Options) *Step {
806806 \\ hello();
807807 \\}
808808 , &.{});
809 exe.linkLibrary(dso);
810 exe.linkLibC();
809 exe.root_module.linkLibrary(dso);
810 exe.root_module.link_libc = true;
811811
812812 const run = addRunArtifact(exe);
813813 run.expectStdOutEqual("Hello WORLD\n");
......@@ -825,7 +825,7 @@ fn testDsoUndef(b: *Build, opts: Options) *Step {
825825 \\int bar = 5;
826826 \\int baz() { return foo; }
827827 , &.{});
828 dso.linkLibC();
828 dso.root_module.link_libc = true;
829829
830830 const obj = addObject(b, opts, .{
831831 .name = "obj",
......@@ -833,18 +833,18 @@ fn testDsoUndef(b: *Build, opts: Options) *Step {
833833 });
834834
835835 const lib = addStaticLibrary(b, opts, .{ .name = "lib" });
836 lib.addObject(obj);
836 lib.root_module.addObject(obj);
837837
838838 const exe = addExecutable(b, opts, .{ .name = "test" });
839 exe.linkLibrary(dso);
840 exe.linkLibrary(lib);
839 exe.root_module.linkLibrary(dso);
840 exe.root_module.linkLibrary(lib);
841841 addCSourceBytes(exe,
842842 \\extern int bar;
843843 \\int main() {
844844 \\ return bar - 5;
845845 \\}
846846 , &.{});
847 exe.linkLibC();
847 exe.root_module.link_libc = true;
848848
849849 const run = addRunArtifact(exe);
850850 run.expectExitCode(0);
......@@ -871,7 +871,7 @@ fn testEmitRelocatable(b: *Build, opts: Options) *Step {
871871 \\ std.debug.print("foo={d}\n", .{foo()});
872872 \\}
873873 });
874 a_o.linkLibC();
874 a_o.root_module.link_libc = true;
875875
876876 const b_o = addObject(b, opts, .{ .name = "b", .c_source_bytes =
877877 \\#include <stdio.h>
......@@ -880,11 +880,11 @@ fn testEmitRelocatable(b: *Build, opts: Options) *Step {
880880 \\ fprintf(stderr, "bar=%d\n", bar);
881881 \\}
882882 });
883 b_o.linkLibC();
883 b_o.root_module.link_libc = true;
884884
885885 const c_o = addObject(b, opts, .{ .name = "c" });
886 c_o.addObject(a_o);
887 c_o.addObject(b_o);
886 c_o.root_module.addObject(a_o);
887 c_o.root_module.addObject(b_o);
888888
889889 const exe = addExecutable(b, opts, .{ .name = "test", .zig_source_bytes =
890890 \\const std = @import("std");
......@@ -895,8 +895,8 @@ fn testEmitRelocatable(b: *Build, opts: Options) *Step {
895895 \\ printBar();
896896 \\}
897897 });
898 exe.addObject(c_o);
899 exe.linkLibC();
898 exe.root_module.addObject(c_o);
899 exe.root_module.link_libc = true;
900900
901901 const run = addRunArtifact(exe);
902902 run.expectStdErrEqual(
......@@ -944,9 +944,9 @@ fn testEmitStaticLib(b: *Build, opts: Options) *Step {
944944 });
945945
946946 const lib = addStaticLibrary(b, opts, .{ .name = "lib" });
947 lib.addObject(obj1);
948 lib.addObject(obj2);
949 lib.addObject(obj3);
947 lib.root_module.addObject(obj1);
948 lib.root_module.addObject(obj2);
949 lib.root_module.addObject(obj3);
950950
951951 const check = lib.checkObject();
952952 check.checkInArchiveSymtab();
......@@ -996,7 +996,7 @@ fn testEmitStaticLibZig(b: *Build, opts: Options) *Step {
996996 \\}
997997 ,
998998 });
999 lib.addObject(obj1);
999 lib.root_module.addObject(obj1);
10001000
10011001 const exe = addExecutable(b, opts, .{
10021002 .name = "test",
......@@ -1008,7 +1008,7 @@ fn testEmitStaticLibZig(b: *Build, opts: Options) *Step {
10081008 \\}
10091009 ,
10101010 });
1011 exe.linkLibrary(lib);
1011 exe.root_module.linkLibrary(lib);
10121012
10131013 const run = addRunArtifact(exe);
10141014 run.expectStdErrEqual("44");
......@@ -1023,7 +1023,7 @@ fn testEmptyObject(b: *Build, opts: Options) *Step {
10231023 const exe = addExecutable(b, opts, .{ .name = "test" });
10241024 addCSourceBytes(exe, "int main() { return 0; }", &.{});
10251025 addCSourceBytes(exe, "", &.{});
1026 exe.linkLibC();
1026 exe.root_module.link_libc = true;
10271027
10281028 const run = addRunArtifact(exe);
10291029 run.expectExitCode(0);
......@@ -1052,8 +1052,8 @@ fn testEntryPoint(b: *Build, opts: Options) *Step {
10521052
10531053 {
10541054 const exe = addExecutable(b, opts, .{ .name = "main" });
1055 exe.addObject(a_o);
1056 exe.addObject(b_o);
1055 exe.root_module.addObject(a_o);
1056 exe.root_module.addObject(b_o);
10571057 exe.entry = .{ .symbol_name = "foo" };
10581058
10591059 const check = exe.checkObject();
......@@ -1068,8 +1068,8 @@ fn testEntryPoint(b: *Build, opts: Options) *Step {
10681068 // cause an artifact collision taking the cached executable from the above
10691069 // step instead of generating a new one.
10701070 const exe = addExecutable(b, opts, .{ .name = "other" });
1071 exe.addObject(a_o);
1072 exe.addObject(b_o);
1071 exe.root_module.addObject(a_o);
1072 exe.root_module.addObject(b_o);
10731073 exe.entry = .{ .symbol_name = "bar" };
10741074
10751075 const check = exe.checkObject();
......@@ -1113,8 +1113,8 @@ fn testExportDynamic(b: *Build, opts: Options) *Step {
11131113 \\ return baz;
11141114 \\}
11151115 , &.{});
1116 exe.addObject(obj);
1117 exe.linkLibrary(dso);
1116 exe.root_module.addObject(obj);
1117 exe.root_module.linkLibrary(dso);
11181118 exe.rdynamic = true;
11191119
11201120 const check = exe.checkObject();
......@@ -1152,8 +1152,8 @@ fn testExportSymbolsFromExe(b: *Build, opts: Options) *Step {
11521152 \\ foo();
11531153 \\}
11541154 , &.{});
1155 exe.linkLibrary(dso);
1156 exe.linkLibC();
1155 exe.root_module.linkLibrary(dso);
1156 exe.root_module.link_libc = true;
11571157
11581158 const check = exe.checkObject();
11591159 check.checkInDynamicSymtab();
......@@ -1181,7 +1181,7 @@ fn testFuncAddress(b: *Build, opts: Options) *Step {
11811181 \\ assert(fn == ptr);
11821182 \\}
11831183 , &.{});
1184 exe.linkLibrary(dso);
1184 exe.root_module.linkLibrary(dso);
11851185 exe.root_module.pic = false;
11861186 exe.pie = false;
11871187
......@@ -1216,15 +1216,15 @@ fn testGcSections(b: *Build, opts: Options) *Step {
12161216 });
12171217 obj.link_function_sections = true;
12181218 obj.link_data_sections = true;
1219 obj.linkLibC();
1220 obj.linkLibCpp();
1219 obj.root_module.link_libc = true;
1220 obj.root_module.link_libcpp = true;
12211221
12221222 {
12231223 const exe = addExecutable(b, opts, .{ .name = "test" });
1224 exe.addObject(obj);
1224 exe.root_module.addObject(obj);
12251225 exe.link_gc_sections = false;
1226 exe.linkLibC();
1227 exe.linkLibCpp();
1226 exe.root_module.link_libc = true;
1227 exe.root_module.link_libcpp = true;
12281228
12291229 const run = addRunArtifact(exe);
12301230 run.expectStdOutEqual("1 2\n");
......@@ -1252,10 +1252,10 @@ fn testGcSections(b: *Build, opts: Options) *Step {
12521252
12531253 {
12541254 const exe = addExecutable(b, opts, .{ .name = "test" });
1255 exe.addObject(obj);
1255 exe.root_module.addObject(obj);
12561256 exe.link_gc_sections = true;
1257 exe.linkLibC();
1258 exe.linkLibCpp();
1257 exe.root_module.link_libc = true;
1258 exe.root_module.link_libcpp = true;
12591259
12601260 const run = addRunArtifact(exe);
12611261 run.expectStdOutEqual("1 2\n");
......@@ -1321,7 +1321,7 @@ fn testGcSectionsZig(b: *Build, opts: Options) *Step {
13211321 \\}
13221322 ,
13231323 });
1324 exe.addObject(obj);
1324 exe.root_module.addObject(obj);
13251325 exe.link_gc_sections = false;
13261326
13271327 const run = addRunArtifact(exe);
......@@ -1363,7 +1363,7 @@ fn testGcSectionsZig(b: *Build, opts: Options) *Step {
13631363 \\}
13641364 ,
13651365 });
1366 exe.addObject(obj);
1366 exe.root_module.addObject(obj);
13671367 exe.link_gc_sections = true;
13681368
13691369 const run = addRunArtifact(exe);
......@@ -1427,7 +1427,7 @@ fn testIFuncAlias(b: *Build, opts: Options) *Step {
14271427 \\}
14281428 , &.{});
14291429 exe.root_module.pic = true;
1430 exe.linkLibC();
1430 exe.root_module.link_libc = true;
14311431
14321432 const run = addRunArtifact(exe);
14331433 run.expectExitCode(0);
......@@ -1467,9 +1467,9 @@ fn testIFuncDlopen(b: *Build, opts: Options) *Step {
14671467 \\ assert(foo == p);
14681468 \\}
14691469 , &.{});
1470 exe.linkLibrary(dso);
1471 exe.linkLibC();
1472 exe.linkSystemLibrary2("dl", .{});
1470 exe.root_module.linkLibrary(dso);
1471 exe.root_module.link_libc = true;
1472 exe.root_module.linkSystemLibrary("dl", .{});
14731473 exe.root_module.pic = false;
14741474 exe.pie = false;
14751475
......@@ -1498,7 +1498,7 @@ fn testIFuncDso(b: *Build, opts: Options) *Step {
14981498 \\}
14991499 ,
15001500 });
1501 dso.linkLibC();
1501 dso.root_module.link_libc = true;
15021502
15031503 const exe = addExecutable(b, opts, .{
15041504 .name = "main",
......@@ -1509,7 +1509,7 @@ fn testIFuncDso(b: *Build, opts: Options) *Step {
15091509 \\}
15101510 ,
15111511 });
1512 exe.linkLibrary(dso);
1512 exe.root_module.linkLibrary(dso);
15131513
15141514 const run = addRunArtifact(exe);
15151515 run.expectStdOutEqual("Hello world\n");
......@@ -1540,7 +1540,7 @@ fn testIFuncDynamic(b: *Build, opts: Options) *Step {
15401540 {
15411541 const exe = addExecutable(b, opts, .{ .name = "main" });
15421542 addCSourceBytes(exe, main_c, &.{});
1543 exe.linkLibC();
1543 exe.root_module.link_libc = true;
15441544 exe.link_z_lazy = true;
15451545
15461546 const run = addRunArtifact(exe);
......@@ -1550,7 +1550,7 @@ fn testIFuncDynamic(b: *Build, opts: Options) *Step {
15501550 {
15511551 const exe = addExecutable(b, opts, .{ .name = "other" });
15521552 addCSourceBytes(exe, main_c, &.{});
1553 exe.linkLibC();
1553 exe.root_module.link_libc = true;
15541554
15551555 const run = addRunArtifact(exe);
15561556 run.expectStdOutEqual("Hello world\n");
......@@ -1576,7 +1576,7 @@ fn testIFuncExport(b: *Build, opts: Options) *Step {
15761576 \\ return real_foobar;
15771577 \\}
15781578 , &.{});
1579 dso.linkLibC();
1579 dso.root_module.link_libc = true;
15801580
15811581 const check = dso.checkObject();
15821582 check.checkInDynamicSymtab();
......@@ -1613,7 +1613,7 @@ fn testIFuncFuncPtr(b: *Build, opts: Options) *Step {
16131613 \\}
16141614 , &.{});
16151615 exe.root_module.pic = true;
1616 exe.linkLibC();
1616 exe.root_module.link_libc = true;
16171617
16181618 const run = addRunArtifact(exe);
16191619 run.expectStdOutEqual("3\n");
......@@ -1642,7 +1642,7 @@ fn testIFuncNoPlt(b: *Build, opts: Options) *Step {
16421642 \\}
16431643 , &.{"-fno-plt"});
16441644 exe.root_module.pic = true;
1645 exe.linkLibC();
1645 exe.root_module.link_libc = true;
16461646
16471647 const run = addRunArtifact(exe);
16481648 run.expectStdOutEqual("Hello world\n");
......@@ -1669,7 +1669,7 @@ fn testIFuncStatic(b: *Build, opts: Options) *Step {
16691669 \\ return 0;
16701670 \\}
16711671 , &.{});
1672 exe.linkLibC();
1672 exe.root_module.link_libc = true;
16731673 exe.linkage = .static;
16741674
16751675 const run = addRunArtifact(exe);
......@@ -1700,7 +1700,7 @@ fn testIFuncStaticPie(b: *Build, opts: Options) *Step {
17001700 exe.linkage = .static;
17011701 exe.root_module.pic = true;
17021702 exe.pie = true;
1703 exe.linkLibC();
1703 exe.root_module.link_libc = true;
17041704
17051705 const run = addRunArtifact(exe);
17061706 run.expectStdOutEqual("Hello world\n");
......@@ -1733,7 +1733,7 @@ fn testImageBase(b: *Build, opts: Options) *Step {
17331733 \\ return 0;
17341734 \\}
17351735 , &.{});
1736 exe.linkLibC();
1736 exe.root_module.link_libc = true;
17371737 exe.image_base = 0x8000000;
17381738
17391739 const run = addRunArtifact(exe);
......@@ -1779,7 +1779,7 @@ fn testImportingDataDynamic(b: *Build, opts: Options) *Step {
17791779 \\void printFoo() { fprintf(stderr, "lib foo=%d\n", foo); }
17801780 ,
17811781 });
1782 dso.linkLibC();
1782 dso.root_module.link_libc = true;
17831783
17841784 const main = addExecutable(b, opts, .{
17851785 .name = "main",
......@@ -1798,7 +1798,7 @@ fn testImportingDataDynamic(b: *Build, opts: Options) *Step {
17981798 .strip = true, // TODO temp hack
17991799 });
18001800 main.pie = true;
1801 main.linkLibrary(dso);
1801 main.root_module.linkLibrary(dso);
18021802
18031803 const run = addRunArtifact(main);
18041804 run.expectStdErrEqual(
......@@ -1832,7 +1832,7 @@ fn testImportingDataStatic(b: *Build, opts: Options) *Step {
18321832 }, .{
18331833 .name = "a",
18341834 });
1835 lib.addObject(obj);
1835 lib.root_module.addObject(obj);
18361836
18371837 const main = addExecutable(b, opts, .{
18381838 .name = "main",
......@@ -1844,8 +1844,8 @@ fn testImportingDataStatic(b: *Build, opts: Options) *Step {
18441844 ,
18451845 .strip = true, // TODO temp hack
18461846 });
1847 main.linkLibrary(lib);
1848 main.linkLibC();
1847 main.root_module.linkLibrary(lib);
1848 main.root_module.link_libc = true;
18491849
18501850 const run = addRunArtifact(main);
18511851 run.expectStdErrEqual("42\n");
......@@ -1864,7 +1864,7 @@ fn testInitArrayOrder(b: *Build, opts: Options) *Step {
18641864 \\__attribute__((constructor(10000))) void init4() { printf("1"); }
18651865 ,
18661866 });
1867 a_o.linkLibC();
1867 a_o.root_module.link_libc = true;
18681868
18691869 const b_o = addObject(b, opts, .{
18701870 .name = "b",
......@@ -1873,7 +1873,7 @@ fn testInitArrayOrder(b: *Build, opts: Options) *Step {
18731873 \\__attribute__((constructor(1000))) void init3() { printf("2"); }
18741874 ,
18751875 });
1876 b_o.linkLibC();
1876 b_o.root_module.link_libc = true;
18771877
18781878 const c_o = addObject(b, opts, .{
18791879 .name = "c",
......@@ -1882,7 +1882,7 @@ fn testInitArrayOrder(b: *Build, opts: Options) *Step {
18821882 \\__attribute__((constructor)) void init1() { printf("3"); }
18831883 ,
18841884 });
1885 c_o.linkLibC();
1885 c_o.root_module.link_libc = true;
18861886
18871887 const d_o = addObject(b, opts, .{
18881888 .name = "d",
......@@ -1891,7 +1891,7 @@ fn testInitArrayOrder(b: *Build, opts: Options) *Step {
18911891 \\__attribute__((constructor)) void init2() { printf("4"); }
18921892 ,
18931893 });
1894 d_o.linkLibC();
1894 d_o.root_module.link_libc = true;
18951895
18961896 const e_o = addObject(b, opts, .{
18971897 .name = "e",
......@@ -1900,7 +1900,7 @@ fn testInitArrayOrder(b: *Build, opts: Options) *Step {
19001900 \\__attribute__((destructor(10000))) void fini4() { printf("5"); }
19011901 ,
19021902 });
1903 e_o.linkLibC();
1903 e_o.root_module.link_libc = true;
19041904
19051905 const f_o = addObject(b, opts, .{
19061906 .name = "f",
......@@ -1909,7 +1909,7 @@ fn testInitArrayOrder(b: *Build, opts: Options) *Step {
19091909 \\__attribute__((destructor(1000))) void fini3() { printf("6"); }
19101910 ,
19111911 });
1912 f_o.linkLibC();
1912 f_o.root_module.link_libc = true;
19131913
19141914 const g_o = addObject(b, opts, .{
19151915 .name = "g",
......@@ -1918,24 +1918,24 @@ fn testInitArrayOrder(b: *Build, opts: Options) *Step {
19181918 \\__attribute__((destructor)) void fini1() { printf("7"); }
19191919 ,
19201920 });
1921 g_o.linkLibC();
1921 g_o.root_module.link_libc = true;
19221922
19231923 const h_o = addObject(b, opts, .{ .name = "h", .c_source_bytes =
19241924 \\#include <stdio.h>
19251925 \\__attribute__((destructor)) void fini2() { printf("8"); }
19261926 });
1927 h_o.linkLibC();
1927 h_o.root_module.link_libc = true;
19281928
19291929 const exe = addExecutable(b, opts, .{ .name = "main" });
19301930 addCSourceBytes(exe, "int main() { return 0; }", &.{});
1931 exe.addObject(a_o);
1932 exe.addObject(b_o);
1933 exe.addObject(c_o);
1934 exe.addObject(d_o);
1935 exe.addObject(e_o);
1936 exe.addObject(f_o);
1937 exe.addObject(g_o);
1938 exe.addObject(h_o);
1931 exe.root_module.addObject(a_o);
1932 exe.root_module.addObject(b_o);
1933 exe.root_module.addObject(c_o);
1934 exe.root_module.addObject(d_o);
1935 exe.root_module.addObject(e_o);
1936 exe.root_module.addObject(f_o);
1937 exe.root_module.addObject(g_o);
1938 exe.root_module.addObject(h_o);
19391939
19401940 if (opts.target.result.isGnuLibC()) {
19411941 // 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 {
19701970 \\}
19711971 , &.{});
19721972 dso.link_function_sections = true;
1973 dso.linkLibC();
1973 dso.root_module.link_libc = true;
19741974
19751975 const check = dso.checkObject();
19761976 check.checkInSymtab();
......@@ -1986,8 +1986,8 @@ fn testLargeAlignmentDso(b: *Build, opts: Options) *Step {
19861986 \\void greet();
19871987 \\int main() { greet(); }
19881988 , &.{});
1989 exe.linkLibrary(dso);
1990 exe.linkLibC();
1989 exe.root_module.linkLibrary(dso);
1990 exe.root_module.link_libc = true;
19911991
19921992 const run = addRunArtifact(exe);
19931993 run.expectStdOutEqual("Hello world");
......@@ -2021,7 +2021,7 @@ fn testLargeAlignmentExe(b: *Build, opts: Options) *Step {
20212021 \\}
20222022 , &.{});
20232023 exe.link_function_sections = true;
2024 exe.linkLibC();
2024 exe.root_module.link_libc = true;
20252025
20262026 const check = exe.checkObject();
20272027 check.checkInSymtab();
......@@ -2049,7 +2049,7 @@ fn testLargeBss(b: *Build, opts: Options) *Step {
20492049 \\ return arr[2000];
20502050 \\}
20512051 , &.{});
2052 exe.linkLibC();
2052 exe.root_module.link_libc = true;
20532053 // Disabled to work around the ELF linker crashing.
20542054 // Can be reproduced on a x86_64-linux host by commenting out the line below.
20552055 exe.root_module.sanitize_c = .off;
......@@ -2071,10 +2071,10 @@ fn testLinkOrder(b: *Build, opts: Options) *Step {
20712071 });
20722072
20732073 const dso = addSharedLibrary(b, opts, .{ .name = "a" });
2074 dso.addObject(obj);
2074 dso.root_module.addObject(obj);
20752075
20762076 const lib = addStaticLibrary(b, opts, .{ .name = "b" });
2077 lib.addObject(obj);
2077 lib.root_module.addObject(obj);
20782078
20792079 const main_o = addObject(b, opts, .{
20802080 .name = "main",
......@@ -2089,14 +2089,14 @@ fn testLinkOrder(b: *Build, opts: Options) *Step {
20892089 // https://github.com/ziglang/zig/issues/17450
20902090 // {
20912091 // const exe = addExecutable(b, opts, .{ .name = "main1"});
2092 // exe.addObject(main_o);
2093 // exe.linkSystemLibrary2("a", .{});
2094 // exe.addLibraryPath(dso.getEmittedBinDirectory());
2095 // exe.addRPath(dso.getEmittedBinDirectory());
2096 // exe.linkSystemLibrary2("b", .{});
2097 // exe.addLibraryPath(lib.getEmittedBinDirectory());
2098 // exe.addRPath(lib.getEmittedBinDirectory());
2099 // exe.linkLibC();
2092 // exe.root_module.addObject(main_o);
2093 // exe.root_module.linkSystemLibrary("a", .{});
2094 // exe.root_module.addLibraryPath(dso.getEmittedBinDirectory());
2095 // exe.root_module.addRPath(dso.getEmittedBinDirectory());
2096 // exe.root_module.linkSystemLibrary("b", .{});
2097 // exe.root_module.addLibraryPath(lib.getEmittedBinDirectory());
2098 // exe.root_module.addRPath(lib.getEmittedBinDirectory());
2099 // exe.root_module.link_libc = true;
21002100
21012101 // const check = exe.checkObject();
21022102 // check.checkInDynamicSection();
......@@ -2106,14 +2106,14 @@ fn testLinkOrder(b: *Build, opts: Options) *Step {
21062106
21072107 {
21082108 const exe = addExecutable(b, opts, .{ .name = "main2" });
2109 exe.addObject(main_o);
2110 exe.linkSystemLibrary2("b", .{});
2111 exe.addLibraryPath(lib.getEmittedBinDirectory());
2112 exe.addRPath(lib.getEmittedBinDirectory());
2113 exe.linkSystemLibrary2("a", .{});
2114 exe.addLibraryPath(dso.getEmittedBinDirectory());
2115 exe.addRPath(dso.getEmittedBinDirectory());
2116 exe.linkLibC();
2109 exe.root_module.addObject(main_o);
2110 exe.root_module.linkSystemLibrary("b", .{});
2111 exe.root_module.addLibraryPath(lib.getEmittedBinDirectory());
2112 exe.root_module.addRPath(lib.getEmittedBinDirectory());
2113 exe.root_module.linkSystemLibrary("a", .{});
2114 exe.root_module.addLibraryPath(dso.getEmittedBinDirectory());
2115 exe.root_module.addRPath(dso.getEmittedBinDirectory());
2116 exe.root_module.link_libc = true;
21172117
21182118 const check = exe.checkObject();
21192119 check.checkInDynamicSection();
......@@ -2149,14 +2149,14 @@ fn testLdScript(b: *Build, opts: Options) *Step {
21492149 \\ return bar() - baz();
21502150 \\}
21512151 , &.{});
2152 exe.linkSystemLibrary2("a", .{});
2153 exe.addLibraryPath(scripts.getDirectory());
2154 exe.addLibraryPath(scripts2.getDirectory());
2155 exe.addLibraryPath(bar.getEmittedBinDirectory());
2156 exe.addLibraryPath(baz.getEmittedBinDirectory());
2157 exe.addRPath(bar.getEmittedBinDirectory());
2158 exe.addRPath(baz.getEmittedBinDirectory());
2159 exe.linkLibC();
2152 exe.root_module.linkSystemLibrary("a", .{});
2153 exe.root_module.addLibraryPath(scripts.getDirectory());
2154 exe.root_module.addLibraryPath(scripts2.getDirectory());
2155 exe.root_module.addLibraryPath(bar.getEmittedBinDirectory());
2156 exe.root_module.addLibraryPath(baz.getEmittedBinDirectory());
2157 exe.root_module.addRPath(bar.getEmittedBinDirectory());
2158 exe.root_module.addRPath(baz.getEmittedBinDirectory());
2159 exe.root_module.link_libc = true;
21602160 exe.allow_so_scripts = true;
21612161
21622162 const run = addRunArtifact(exe);
......@@ -2174,9 +2174,9 @@ fn testLdScriptPathError(b: *Build, opts: Options) *Step {
21742174
21752175 const exe = addExecutable(b, opts, .{ .name = "main" });
21762176 addCSourceBytes(exe, "int main() { return 0; }", &.{});
2177 exe.linkSystemLibrary2("a", .{});
2178 exe.addLibraryPath(scripts.getDirectory());
2179 exe.linkLibC();
2177 exe.root_module.linkSystemLibrary("a", .{});
2178 exe.root_module.addLibraryPath(scripts.getDirectory());
2179 exe.root_module.link_libc = true;
21802180 exe.allow_so_scripts = true;
21812181
21822182 // TODO: A future enhancement could make this error message also mention
......@@ -2213,8 +2213,8 @@ fn testLdScriptAllowUndefinedVersion(b: *Build, opts: Options) *Step {
22132213 \\}
22142214 ,
22152215 });
2216 exe.linkLibrary(so);
2217 exe.linkLibC();
2216 exe.root_module.linkLibrary(so);
2217 exe.root_module.link_libc = true;
22182218 exe.allow_so_scripts = true;
22192219
22202220 const run = addRunArtifact(exe);
......@@ -2269,8 +2269,8 @@ fn testMismatchedCpuArchitectureError(b: *Build, opts: Options) *Step {
22692269 \\ return foo;
22702270 \\}
22712271 , &.{});
2272 exe.addObject(obj);
2273 exe.linkLibC();
2272 exe.root_module.addObject(obj);
2273 exe.root_module.link_libc = true;
22742274
22752275 expectLinkErrors(exe, test_step, .{ .exact = &.{
22762276 "invalid ELF machine type: AARCH64",
......@@ -2291,7 +2291,7 @@ fn testLinkingC(b: *Build, opts: Options) *Step {
22912291 \\ return 0;
22922292 \\}
22932293 , &.{});
2294 exe.linkLibC();
2294 exe.root_module.link_libc = true;
22952295
22962296 const run = addRunArtifact(exe);
22972297 run.expectStdOutEqual("Hello World!\n");
......@@ -2320,8 +2320,8 @@ fn testLinkingCpp(b: *Build, opts: Options) *Step {
23202320 \\ return 0;
23212321 \\}
23222322 , &.{});
2323 exe.linkLibC();
2324 exe.linkLibCpp();
2323 exe.root_module.link_libc = true;
2324 exe.root_module.link_libcpp = true;
23252325
23262326 const run = addRunArtifact(exe);
23272327 run.expectStdOutEqual("Hello World!\n");
......@@ -2364,7 +2364,7 @@ fn testLinkingObj(b: *Build, opts: Options) *Step {
23642364 \\}
23652365 ,
23662366 });
2367 exe.addObject(obj);
2367 exe.root_module.addObject(obj);
23682368
23692369 const run = addRunArtifact(exe);
23702370 run.expectStdErrEqual("84\n");
......@@ -2389,7 +2389,7 @@ fn testLinkingStaticLib(b: *Build, opts: Options) *Step {
23892389 \\}
23902390 ,
23912391 });
2392 lib.addObject(obj);
2392 lib.root_module.addObject(obj);
23932393
23942394 const exe = addExecutable(b, opts, .{
23952395 .name = "testlib",
......@@ -2402,7 +2402,7 @@ fn testLinkingStaticLib(b: *Build, opts: Options) *Step {
24022402 \\}
24032403 ,
24042404 });
2405 exe.linkLibrary(lib);
2405 exe.root_module.linkLibrary(lib);
24062406
24072407 const run = addRunArtifact(exe);
24082408 run.expectStdErrEqual("0\n");
......@@ -2452,7 +2452,7 @@ fn testMergeStrings(b: *Build, opts: Options) *Step {
24522452 \\char16_t *utf16_1 = u"foo";
24532453 \\char32_t *utf32_1 = U"foo";
24542454 , &.{"-O2"});
2455 obj1.linkLibC();
2455 obj1.root_module.link_libc = true;
24562456
24572457 const obj2 = addObject(b, opts, .{ .name = "b.o" });
24582458 addCSourceBytes(obj2,
......@@ -2481,12 +2481,12 @@ fn testMergeStrings(b: *Build, opts: Options) *Step {
24812481 \\ assert((void*)wide1 != (void*)utf16_1);
24822482 \\}
24832483 , &.{"-O2"});
2484 obj2.linkLibC();
2484 obj2.root_module.link_libc = true;
24852485
24862486 const exe = addExecutable(b, opts, .{ .name = "main" });
2487 exe.addObject(obj1);
2488 exe.addObject(obj2);
2489 exe.linkLibC();
2487 exe.root_module.addObject(obj1);
2488 exe.root_module.addObject(obj2);
2489 exe.root_module.link_libc = true;
24902490
24912491 const run = addRunArtifact(exe);
24922492 run.expectExitCode(0);
......@@ -2520,8 +2520,8 @@ fn testMergeStrings2(b: *Build, opts: Options) *Step {
25202520
25212521 {
25222522 const exe = addExecutable(b, opts, .{ .name = "main1" });
2523 exe.addObject(obj1);
2524 exe.addObject(obj2);
2523 exe.root_module.addObject(obj1);
2524 exe.root_module.addObject(obj2);
25252525
25262526 const run = addRunArtifact(exe);
25272527 run.expectExitCode(0);
......@@ -2537,11 +2537,11 @@ fn testMergeStrings2(b: *Build, opts: Options) *Step {
25372537
25382538 {
25392539 const obj3 = addObject(b, opts, .{ .name = "c" });
2540 obj3.addObject(obj1);
2541 obj3.addObject(obj2);
2540 obj3.root_module.addObject(obj1);
2541 obj3.root_module.addObject(obj2);
25422542
25432543 const exe = addExecutable(b, opts, .{ .name = "main2" });
2544 exe.addObject(obj3);
2544 exe.root_module.addObject(obj3);
25452545
25462546 const run = addRunArtifact(exe);
25472547 run.expectExitCode(0);
......@@ -2564,7 +2564,7 @@ fn testNoEhFrameHdr(b: *Build, opts: Options) *Step {
25642564 const exe = addExecutable(b, opts, .{ .name = "main" });
25652565 addCSourceBytes(exe, "int main() { return 0; }", &.{});
25662566 exe.link_eh_frame_hdr = false;
2567 exe.linkLibC();
2567 exe.root_module.link_libc = true;
25682568
25692569 const check = exe.checkObject();
25702570 check.checkInHeaders();
......@@ -2586,7 +2586,7 @@ fn testPie(b: *Build, opts: Options) *Step {
25862586 \\ return 0;
25872587 \\}
25882588 , &.{});
2589 exe.linkLibC();
2589 exe.root_module.link_libc = true;
25902590 exe.root_module.pic = true;
25912591 exe.pie = true;
25922592
......@@ -2617,7 +2617,7 @@ fn testPltGot(b: *Build, opts: Options) *Step {
26172617 \\ printf("Hello world\n");
26182618 \\}
26192619 , &.{});
2620 dso.linkLibC();
2620 dso.root_module.link_libc = true;
26212621
26222622 const exe = addExecutable(b, opts, .{ .name = "main" });
26232623 addCSourceBytes(exe,
......@@ -2626,9 +2626,9 @@ fn testPltGot(b: *Build, opts: Options) *Step {
26262626 \\void foo() { ignore(hello); }
26272627 \\int main() { hello(); }
26282628 , &.{});
2629 exe.linkLibrary(dso);
2629 exe.root_module.linkLibrary(dso);
26302630 exe.root_module.pic = true;
2631 exe.linkLibC();
2631 exe.root_module.link_libc = true;
26322632
26332633 const run = addRunArtifact(exe);
26342634 run.expectStdOutEqual("Hello world\n");
......@@ -2647,7 +2647,7 @@ fn testPreinitArray(b: *Build, opts: Options) *Step {
26472647 });
26482648
26492649 const exe = addExecutable(b, opts, .{ .name = "main1" });
2650 exe.addObject(obj);
2650 exe.root_module.addObject(obj);
26512651
26522652 const check = exe.checkObject();
26532653 check.checkInDynamicSection();
......@@ -2662,7 +2662,7 @@ fn testPreinitArray(b: *Build, opts: Options) *Step {
26622662 \\__attribute__((section(".preinit_array")))
26632663 \\void *preinit[] = { preinit_fn };
26642664 , &.{});
2665 exe.linkLibC();
2665 exe.root_module.link_libc = true;
26662666
26672667 const check = exe.checkObject();
26682668 check.checkInDynamicSection();
......@@ -2710,15 +2710,15 @@ fn testRelocatableArchive(b: *Build, opts: Options) *Step {
27102710 });
27112711
27122712 const lib = addStaticLibrary(b, opts, .{ .name = "lib" });
2713 lib.addObject(obj1);
2714 lib.addObject(obj2);
2715 lib.addObject(obj3);
2713 lib.root_module.addObject(obj1);
2714 lib.root_module.addObject(obj2);
2715 lib.root_module.addObject(obj3);
27162716
27172717 const obj5 = addObject(b, opts, .{
27182718 .name = "obj5",
27192719 });
2720 obj5.addObject(obj4);
2721 obj5.linkLibrary(lib);
2720 obj5.root_module.addObject(obj4);
2721 obj5.root_module.linkLibrary(lib);
27222722
27232723 const check = obj5.checkObject();
27242724 check.checkInSymtab();
......@@ -2744,7 +2744,7 @@ fn testRelocatableEhFrame(b: *Build, opts: Options) *Step {
27442744 \\}
27452745 ,
27462746 });
2747 obj1.linkLibCpp();
2747 obj1.root_module.link_libcpp = true;
27482748 const obj2 = addObject(b, opts, .{
27492749 .name = "obj2",
27502750 .cpp_source_bytes =
......@@ -2754,7 +2754,7 @@ fn testRelocatableEhFrame(b: *Build, opts: Options) *Step {
27542754 \\}
27552755 ,
27562756 });
2757 obj2.linkLibCpp();
2757 obj2.root_module.link_libcpp = true;
27582758 const obj3 = addObject(b, opts, .{ .name = "obj3", .cpp_source_bytes =
27592759 \\#include <iostream>
27602760 \\#include <stdexcept>
......@@ -2768,18 +2768,18 @@ fn testRelocatableEhFrame(b: *Build, opts: Options) *Step {
27682768 \\ return 0;
27692769 \\}
27702770 });
2771 obj3.linkLibCpp();
2771 obj3.root_module.link_libcpp = true;
27722772
27732773 {
27742774 const obj = addObject(b, opts, .{ .name = "obj" });
2775 obj.addObject(obj1);
2776 obj.addObject(obj2);
2777 obj.linkLibCpp();
2775 obj.root_module.addObject(obj1);
2776 obj.root_module.addObject(obj2);
2777 obj.root_module.link_libcpp = true;
27782778
27792779 const exe = addExecutable(b, opts, .{ .name = "test1" });
2780 exe.addObject(obj3);
2781 exe.addObject(obj);
2782 exe.linkLibCpp();
2780 exe.root_module.addObject(obj3);
2781 exe.root_module.addObject(obj);
2782 exe.root_module.link_libcpp = true;
27832783
27842784 const run = addRunArtifact(exe);
27852785 run.expectStdOutEqual("exception=Oh no!");
......@@ -2788,14 +2788,14 @@ fn testRelocatableEhFrame(b: *Build, opts: Options) *Step {
27882788 {
27892789 // Flipping the order should not influence the end result.
27902790 const obj = addObject(b, opts, .{ .name = "obj" });
2791 obj.addObject(obj2);
2792 obj.addObject(obj1);
2793 obj.linkLibCpp();
2791 obj.root_module.addObject(obj2);
2792 obj.root_module.addObject(obj1);
2793 obj.root_module.link_libcpp = true;
27942794
27952795 const exe = addExecutable(b, opts, .{ .name = "test2" });
2796 exe.addObject(obj3);
2797 exe.addObject(obj);
2798 exe.linkLibCpp();
2796 exe.root_module.addObject(obj3);
2797 exe.root_module.addObject(obj);
2798 exe.root_module.link_libcpp = true;
27992799
28002800 const run = addRunArtifact(exe);
28012801 run.expectStdOutEqual("exception=Oh no!");
......@@ -2817,7 +2817,7 @@ fn testRelocatableEhFrameComdatHeavy(b: *Build, opts: Options) *Step {
28172817 \\}
28182818 ,
28192819 });
2820 obj1.linkLibCpp();
2820 obj1.root_module.link_libcpp = true;
28212821 const obj2 = addObject(b, opts, .{
28222822 .name = "obj2",
28232823 .cpp_source_bytes =
......@@ -2827,7 +2827,7 @@ fn testRelocatableEhFrameComdatHeavy(b: *Build, opts: Options) *Step {
28272827 \\}
28282828 ,
28292829 });
2830 obj2.linkLibCpp();
2830 obj2.root_module.link_libcpp = true;
28312831 const obj3 = addObject(b, opts, .{
28322832 .name = "obj3",
28332833 .cpp_source_bytes =
......@@ -2844,17 +2844,17 @@ fn testRelocatableEhFrameComdatHeavy(b: *Build, opts: Options) *Step {
28442844 \\}
28452845 ,
28462846 });
2847 obj3.linkLibCpp();
2847 obj3.root_module.link_libcpp = true;
28482848
28492849 const obj = addObject(b, opts, .{ .name = "obj" });
2850 obj.addObject(obj1);
2851 obj.addObject(obj2);
2852 obj.addObject(obj3);
2853 obj.linkLibCpp();
2850 obj.root_module.addObject(obj1);
2851 obj.root_module.addObject(obj2);
2852 obj.root_module.addObject(obj3);
2853 obj.root_module.link_libcpp = true;
28542854
28552855 const exe = addExecutable(b, opts, .{ .name = "test2" });
2856 exe.addObject(obj);
2857 exe.linkLibCpp();
2856 exe.root_module.addObject(obj);
2857 exe.root_module.link_libcpp = true;
28582858
28592859 const run = addRunArtifact(exe);
28602860 run.expectStdOutEqual("exception=Oh no!");
......@@ -2880,7 +2880,7 @@ fn testRelocatableMergeStrings(b: *Build, opts: Options) *Step {
28802880 });
28812881
28822882 const obj2 = addObject(b, opts, .{ .name = "b" });
2883 obj2.addObject(obj1);
2883 obj2.root_module.addObject(obj1);
28842884
28852885 const check = obj2.checkObject();
28862886 check.dumpSection(".rodata.str1.1");
......@@ -2905,7 +2905,7 @@ fn testRelocatableNoEhFrame(b: *Build, opts: Options) *Step {
29052905 const obj2 = addObject(b, opts, .{
29062906 .name = "obj2",
29072907 });
2908 obj2.addObject(obj1);
2908 obj2.root_module.addObject(obj1);
29092909
29102910 const check1 = obj1.checkObject();
29112911 check1.checkInHeaders();
......@@ -2940,12 +2940,12 @@ fn testSharedAbsSymbol(b: *Build, opts: Options) *Step {
29402940 ,
29412941 .pic = true,
29422942 });
2943 obj.linkLibC();
2943 obj.root_module.link_libc = true;
29442944
29452945 {
29462946 const exe = addExecutable(b, opts, .{ .name = "main1" });
2947 exe.addObject(obj);
2948 exe.linkLibrary(dso);
2947 exe.root_module.addObject(obj);
2948 exe.root_module.linkLibrary(dso);
29492949 exe.pie = true;
29502950
29512951 const run = addRunArtifact(exe);
......@@ -2965,8 +2965,8 @@ fn testSharedAbsSymbol(b: *Build, opts: Options) *Step {
29652965 // https://github.com/ziglang/zig/issues/17430
29662966 // {
29672967 // const exe = addExecutable(b, opts, .{ .name = "main2"});
2968 // exe.addObject(obj);
2969 // exe.linkLibrary(dso);
2968 // exe.root_module.addObject(obj);
2969 // exe.root_module.linkLibrary(dso);
29702970 // exe.pie = false;
29712971
29722972 // const run = addRunArtifact(exe);
......@@ -2999,13 +2999,13 @@ fn testStrip(b: *Build, opts: Options) *Step {
29992999 \\}
30003000 ,
30013001 });
3002 obj.linkLibC();
3002 obj.root_module.link_libc = true;
30033003
30043004 {
30053005 const exe = addExecutable(b, opts, .{ .name = "main1" });
3006 exe.addObject(obj);
3006 exe.root_module.addObject(obj);
30073007 exe.root_module.strip = false;
3008 exe.linkLibC();
3008 exe.root_module.link_libc = true;
30093009
30103010 const check = exe.checkObject();
30113011 check.checkInHeaders();
......@@ -3016,9 +3016,9 @@ fn testStrip(b: *Build, opts: Options) *Step {
30163016
30173017 {
30183018 const exe = addExecutable(b, opts, .{ .name = "main2" });
3019 exe.addObject(obj);
3019 exe.root_module.addObject(obj);
30203020 exe.root_module.strip = true;
3021 exe.linkLibC();
3021 exe.root_module.link_libc = true;
30223022
30233023 const check = exe.checkObject();
30243024 check.checkInHeaders();
......@@ -3074,7 +3074,7 @@ fn testTlsDfStaticTls(b: *Build, opts: Options) *Step {
30743074
30753075 {
30763076 const dso = addSharedLibrary(b, opts, .{ .name = "a" });
3077 dso.addObject(obj);
3077 dso.root_module.addObject(obj);
30783078 // dso.link_relax = true;
30793079
30803080 const check = dso.checkObject();
......@@ -3086,7 +3086,7 @@ fn testTlsDfStaticTls(b: *Build, opts: Options) *Step {
30863086 // TODO add -Wl,--no-relax
30873087 // {
30883088 // const dso = addSharedLibrary(b, opts, .{ .name = "a"});
3089 // dso.addObject(obj);
3089 // dso.root_module.addObject(obj);
30903090 // dso.link_relax = false;
30913091
30923092 // const check = dso.checkObject();
......@@ -3128,8 +3128,8 @@ fn testTlsDso(b: *Build, opts: Options) *Step {
31283128 \\ return 0;
31293129 \\}
31303130 , &.{});
3131 exe.linkLibrary(dso);
3132 exe.linkLibC();
3131 exe.root_module.linkLibrary(dso);
3132 exe.root_module.link_libc = true;
31333133
31343134 const run = addRunArtifact(exe);
31353135 run.expectStdOutEqual("5 3 5 3 5 3\n");
......@@ -3159,7 +3159,7 @@ fn testTlsGd(b: *Build, opts: Options) *Step {
31593159 ,
31603160 .pic = true,
31613161 });
3162 main_o.linkLibC();
3162 main_o.root_module.link_libc = true;
31633163
31643164 const a_o = addObject(b, opts, .{
31653165 .name = "a",
......@@ -3184,17 +3184,17 @@ fn testTlsGd(b: *Build, opts: Options) *Step {
31843184 const exp_stdout = "1 2 3 4 5 6\n";
31853185
31863186 const dso1 = addSharedLibrary(b, opts, .{ .name = "a" });
3187 dso1.addObject(a_o);
3187 dso1.root_module.addObject(a_o);
31883188
31893189 const dso2 = addSharedLibrary(b, opts, .{ .name = "b" });
3190 dso2.addObject(b_o);
3190 dso2.root_module.addObject(b_o);
31913191 // dso2.link_relax = false; // TODO
31923192
31933193 {
31943194 const exe = addExecutable(b, opts, .{ .name = "main1" });
3195 exe.addObject(main_o);
3196 exe.linkLibrary(dso1);
3197 exe.linkLibrary(dso2);
3195 exe.root_module.addObject(main_o);
3196 exe.root_module.linkLibrary(dso1);
3197 exe.root_module.linkLibrary(dso2);
31983198
31993199 const run = addRunArtifact(exe);
32003200 run.expectStdOutEqual(exp_stdout);
......@@ -3203,10 +3203,10 @@ fn testTlsGd(b: *Build, opts: Options) *Step {
32033203
32043204 {
32053205 const exe = addExecutable(b, opts, .{ .name = "main2" });
3206 exe.addObject(main_o);
3206 exe.root_module.addObject(main_o);
32073207 // exe.link_relax = false; // TODO
3208 exe.linkLibrary(dso1);
3209 exe.linkLibrary(dso2);
3208 exe.root_module.linkLibrary(dso1);
3209 exe.root_module.linkLibrary(dso2);
32103210
32113211 const run = addRunArtifact(exe);
32123212 run.expectStdOutEqual(exp_stdout);
......@@ -3216,9 +3216,9 @@ fn testTlsGd(b: *Build, opts: Options) *Step {
32163216 // https://github.com/ziglang/zig/issues/17430 ??
32173217 // {
32183218 // const exe = addExecutable(b, opts, .{ .name = "main3"});
3219 // exe.addObject(main_o);
3220 // exe.linkLibrary(dso1);
3221 // exe.linkLibrary(dso2);
3219 // exe.root_module.addObject(main_o);
3220 // exe.root_module.linkLibrary(dso1);
3221 // exe.root_module.linkLibrary(dso2);
32223222 // exe.linkage = .static;
32233223
32243224 // const run = addRunArtifact(exe);
......@@ -3228,10 +3228,10 @@ fn testTlsGd(b: *Build, opts: Options) *Step {
32283228
32293229 // {
32303230 // const exe = addExecutable(b, opts, .{ .name = "main4"});
3231 // exe.addObject(main_o);
3231 // exe.root_module.addObject(main_o);
32323232 // // exe.link_relax = false; // TODO
3233 // exe.linkLibrary(dso1);
3234 // exe.linkLibrary(dso2);
3233 // exe.root_module.linkLibrary(dso1);
3234 // exe.root_module.linkLibrary(dso2);
32353235 // exe.linkage = .static;
32363236
32373237 // const run = addRunArtifact(exe);
......@@ -3265,7 +3265,7 @@ fn testTlsGdNoPlt(b: *Build, opts: Options) *Step {
32653265 .c_source_flags = &.{"-fno-plt"},
32663266 .pic = true,
32673267 });
3268 obj.linkLibC();
3268 obj.root_module.link_libc = true;
32693269
32703270 const a_so = addSharedLibrary(b, opts, .{ .name = "a" });
32713271 addCSourceBytes(a_so,
......@@ -3284,10 +3284,10 @@ fn testTlsGdNoPlt(b: *Build, opts: Options) *Step {
32843284
32853285 {
32863286 const exe = addExecutable(b, opts, .{ .name = "main1" });
3287 exe.addObject(obj);
3288 exe.linkLibrary(a_so);
3289 exe.linkLibrary(b_so);
3290 exe.linkLibC();
3287 exe.root_module.addObject(obj);
3288 exe.root_module.linkLibrary(a_so);
3289 exe.root_module.linkLibrary(b_so);
3290 exe.root_module.link_libc = true;
32913291
32923292 const run = addRunArtifact(exe);
32933293 run.expectStdOutEqual("1 2 3 4 5 6\n");
......@@ -3296,10 +3296,10 @@ fn testTlsGdNoPlt(b: *Build, opts: Options) *Step {
32963296
32973297 {
32983298 const exe = addExecutable(b, opts, .{ .name = "main2" });
3299 exe.addObject(obj);
3300 exe.linkLibrary(a_so);
3301 exe.linkLibrary(b_so);
3302 exe.linkLibC();
3299 exe.root_module.addObject(obj);
3300 exe.root_module.linkLibrary(a_so);
3301 exe.root_module.linkLibrary(b_so);
3302 exe.root_module.link_libc = true;
33033303 // exe.link_relax = false; // TODO
33043304
33053305 const run = addRunArtifact(exe);
......@@ -3329,7 +3329,7 @@ fn testTlsGdToIe(b: *Build, opts: Options) *Step {
33293329 ,
33303330 .pic = true,
33313331 });
3332 a_o.linkLibC();
3332 a_o.root_module.link_libc = true;
33333333
33343334 const b_o = addObject(b, opts, .{
33353335 .name = "b",
......@@ -3342,12 +3342,12 @@ fn testTlsGdToIe(b: *Build, opts: Options) *Step {
33423342
33433343 {
33443344 const dso = addSharedLibrary(b, opts, .{ .name = "a1" });
3345 dso.addObject(a_o);
3345 dso.root_module.addObject(a_o);
33463346
33473347 const exe = addExecutable(b, opts, .{ .name = "main1" });
3348 exe.addObject(b_o);
3349 exe.linkLibrary(dso);
3350 exe.linkLibC();
3348 exe.root_module.addObject(b_o);
3349 exe.root_module.linkLibrary(dso);
3350 exe.root_module.link_libc = true;
33513351
33523352 const run = addRunArtifact(exe);
33533353 run.expectStdOutEqual("1 2 3\n");
......@@ -3356,13 +3356,13 @@ fn testTlsGdToIe(b: *Build, opts: Options) *Step {
33563356
33573357 {
33583358 const dso = addSharedLibrary(b, opts, .{ .name = "a2" });
3359 dso.addObject(a_o);
3359 dso.root_module.addObject(a_o);
33603360 // dso.link_relax = false; // TODO
33613361
33623362 const exe = addExecutable(b, opts, .{ .name = "main2" });
3363 exe.addObject(b_o);
3364 exe.linkLibrary(dso);
3365 exe.linkLibC();
3363 exe.root_module.addObject(b_o);
3364 exe.root_module.linkLibrary(dso);
3365 exe.root_module.link_libc = true;
33663366
33673367 const run = addRunArtifact(exe);
33683368 run.expectStdOutEqual("1 2 3\n");
......@@ -3371,12 +3371,12 @@ fn testTlsGdToIe(b: *Build, opts: Options) *Step {
33713371
33723372 // {
33733373 // const dso = addSharedLibrary(b, opts, .{ .name = "a"});
3374 // dso.addObject(a_o);
3374 // dso.root_module.addObject(a_o);
33753375 // dso.link_z_nodlopen = true;
33763376
33773377 // const exe = addExecutable(b, opts, .{ .name = "main"});
3378 // exe.addObject(b_o);
3379 // exe.linkLibrary(dso);
3378 // exe.root_module.addObject(b_o);
3379 // exe.root_module.linkLibrary(dso);
33803380
33813381 // const run = addRunArtifact(exe);
33823382 // run.expectStdOutEqual("1 2 3\n");
......@@ -3385,13 +3385,13 @@ fn testTlsGdToIe(b: *Build, opts: Options) *Step {
33853385
33863386 // {
33873387 // const dso = addSharedLibrary(b, opts, .{ .name = "a"});
3388 // dso.addObject(a_o);
3388 // dso.root_module.addObject(a_o);
33893389 // dso.link_relax = false;
33903390 // dso.link_z_nodlopen = true;
33913391
33923392 // const exe = addExecutable(b, opts, .{ .name = "main"});
3393 // exe.addObject(b_o);
3394 // exe.linkLibrary(dso);
3393 // exe.root_module.addObject(b_o);
3394 // exe.root_module.linkLibrary(dso);
33953395
33963396 // const run = addRunArtifact(exe);
33973397 // run.expectStdOutEqual("1 2 3\n");
......@@ -3417,7 +3417,7 @@ fn testTlsIe(b: *Build, opts: Options) *Step {
34173417 \\ printf("%d %d ", foo, bar);
34183418 \\}
34193419 , &.{});
3420 dso.linkLibC();
3420 dso.root_module.link_libc = true;
34213421
34223422 const main_o = addObject(b, opts, .{
34233423 .name = "main",
......@@ -3435,15 +3435,15 @@ fn testTlsIe(b: *Build, opts: Options) *Step {
34353435 \\}
34363436 ,
34373437 });
3438 main_o.linkLibC();
3438 main_o.root_module.link_libc = true;
34393439
34403440 const exp_stdout = "0 0 3 5 7\n";
34413441
34423442 {
34433443 const exe = addExecutable(b, opts, .{ .name = "main1" });
3444 exe.addObject(main_o);
3445 exe.linkLibrary(dso);
3446 exe.linkLibC();
3444 exe.root_module.addObject(main_o);
3445 exe.root_module.linkLibrary(dso);
3446 exe.root_module.link_libc = true;
34473447
34483448 const run = addRunArtifact(exe);
34493449 run.expectStdOutEqual(exp_stdout);
......@@ -3452,9 +3452,9 @@ fn testTlsIe(b: *Build, opts: Options) *Step {
34523452
34533453 {
34543454 const exe = addExecutable(b, opts, .{ .name = "main2" });
3455 exe.addObject(main_o);
3456 exe.linkLibrary(dso);
3457 exe.linkLibC();
3455 exe.root_module.addObject(main_o);
3456 exe.root_module.linkLibrary(dso);
3457 exe.root_module.link_libc = true;
34583458 // exe.link_relax = false; // TODO
34593459
34603460 const run = addRunArtifact(exe);
......@@ -3500,17 +3500,17 @@ fn testTlsLargeAlignment(b: *Build, opts: Options) *Step {
35003500 ,
35013501 .pic = true,
35023502 });
3503 c_o.linkLibC();
3503 c_o.root_module.link_libc = true;
35043504
35053505 {
35063506 const dso = addSharedLibrary(b, opts, .{ .name = "a" });
3507 dso.addObject(a_o);
3508 dso.addObject(b_o);
3507 dso.root_module.addObject(a_o);
3508 dso.root_module.addObject(b_o);
35093509
35103510 const exe = addExecutable(b, opts, .{ .name = "main" });
3511 exe.addObject(c_o);
3512 exe.linkLibrary(dso);
3513 exe.linkLibC();
3511 exe.root_module.addObject(c_o);
3512 exe.root_module.linkLibrary(dso);
3513 exe.root_module.link_libc = true;
35143514
35153515 const run = addRunArtifact(exe);
35163516 run.expectStdOutEqual("42 1 2 3\n");
......@@ -3519,10 +3519,10 @@ fn testTlsLargeAlignment(b: *Build, opts: Options) *Step {
35193519
35203520 {
35213521 const exe = addExecutable(b, opts, .{ .name = "main" });
3522 exe.addObject(a_o);
3523 exe.addObject(b_o);
3524 exe.addObject(c_o);
3525 exe.linkLibC();
3522 exe.root_module.addObject(a_o);
3523 exe.root_module.addObject(b_o);
3524 exe.root_module.addObject(c_o);
3525 exe.root_module.link_libc = true;
35263526
35273527 const run = addRunArtifact(exe);
35283528 run.expectStdOutEqual("42 1 2 3\n");
......@@ -3555,7 +3555,7 @@ fn testTlsLargeTbss(b: *Build, opts: Options) *Step {
35553555 \\ printf("%d %d %d %d %d %d\n", x[0], x[1], x[1023], y[0], y[1], y[1023]);
35563556 \\}
35573557 , &.{});
3558 exe.linkLibC();
3558 exe.root_module.link_libc = true;
35593559 // Disabled to work around the ELF linker crashing.
35603560 // Can be reproduced on a x86_64-linux host by commenting out the line below.
35613561 exe.root_module.sanitize_c = .off;
......@@ -3580,7 +3580,7 @@ fn testTlsLargeStaticImage(b: *Build, opts: Options) *Step {
35803580 \\}
35813581 , &.{});
35823582 exe.root_module.pic = true;
3583 exe.linkLibC();
3583 exe.root_module.link_libc = true;
35843584
35853585 const run = addRunArtifact(exe);
35863586 run.expectStdOutEqual("1 2 3 0 5\n");
......@@ -3609,7 +3609,7 @@ fn testTlsLd(b: *Build, opts: Options) *Step {
36093609 .c_source_flags = &.{"-ftls-model=local-dynamic"},
36103610 .pic = true,
36113611 });
3612 main_o.linkLibC();
3612 main_o.root_module.link_libc = true;
36133613
36143614 const a_o = addObject(b, opts, .{
36153615 .name = "a",
......@@ -3622,9 +3622,9 @@ fn testTlsLd(b: *Build, opts: Options) *Step {
36223622
36233623 {
36243624 const exe = addExecutable(b, opts, .{ .name = "main1" });
3625 exe.addObject(main_o);
3626 exe.addObject(a_o);
3627 exe.linkLibC();
3625 exe.root_module.addObject(main_o);
3626 exe.root_module.addObject(a_o);
3627 exe.root_module.link_libc = true;
36283628
36293629 const run = addRunArtifact(exe);
36303630 run.expectStdOutEqual(exp_stdout);
......@@ -3633,9 +3633,9 @@ fn testTlsLd(b: *Build, opts: Options) *Step {
36333633
36343634 {
36353635 const exe = addExecutable(b, opts, .{ .name = "main2" });
3636 exe.addObject(main_o);
3637 exe.addObject(a_o);
3638 exe.linkLibC();
3636 exe.root_module.addObject(main_o);
3637 exe.root_module.addObject(a_o);
3638 exe.root_module.link_libc = true;
36393639 // exe.link_relax = false; // TODO
36403640
36413641 const run = addRunArtifact(exe);
......@@ -3668,8 +3668,8 @@ fn testTlsLdDso(b: *Build, opts: Options) *Step {
36683668 \\ return 0;
36693669 \\}
36703670 , &.{});
3671 exe.linkLibrary(dso);
3672 exe.linkLibC();
3671 exe.root_module.linkLibrary(dso);
3672 exe.root_module.link_libc = true;
36733673
36743674 const run = addRunArtifact(exe);
36753675 run.expectStdOutEqual("1 2\n");
......@@ -3699,7 +3699,7 @@ fn testTlsLdNoPlt(b: *Build, opts: Options) *Step {
36993699 .c_source_flags = &.{ "-ftls-model=local-dynamic", "-fno-plt" },
37003700 .pic = true,
37013701 });
3702 a_o.linkLibC();
3702 a_o.root_module.link_libc = true;
37033703
37043704 const b_o = addObject(b, opts, .{
37053705 .name = "b",
......@@ -3710,9 +3710,9 @@ fn testTlsLdNoPlt(b: *Build, opts: Options) *Step {
37103710
37113711 {
37123712 const exe = addExecutable(b, opts, .{ .name = "main1" });
3713 exe.addObject(a_o);
3714 exe.addObject(b_o);
3715 exe.linkLibC();
3713 exe.root_module.addObject(a_o);
3714 exe.root_module.addObject(b_o);
3715 exe.root_module.link_libc = true;
37163716
37173717 const run = addRunArtifact(exe);
37183718 run.expectStdOutEqual("3 5 3 5\n");
......@@ -3721,9 +3721,9 @@ fn testTlsLdNoPlt(b: *Build, opts: Options) *Step {
37213721
37223722 {
37233723 const exe = addExecutable(b, opts, .{ .name = "main2" });
3724 exe.addObject(a_o);
3725 exe.addObject(b_o);
3726 exe.linkLibC();
3724 exe.root_module.addObject(a_o);
3725 exe.root_module.addObject(b_o);
3726 exe.root_module.link_libc = true;
37273727 // exe.link_relax = false; // TODO
37283728
37293729 const run = addRunArtifact(exe);
......@@ -3756,7 +3756,7 @@ fn testTlsNoPic(b: *Build, opts: Options) *Step {
37563756 \\__attribute__((tls_model("global-dynamic"))) _Thread_local int foo;
37573757 , &.{});
37583758 exe.root_module.pic = false;
3759 exe.linkLibC();
3759 exe.root_module.link_libc = true;
37603760
37613761 const run = addRunArtifact(exe);
37623762 run.expectStdOutEqual("3 5 3 5\n");
......@@ -3784,7 +3784,7 @@ fn testTlsOffsetAlignment(b: *Build, opts: Options) *Step {
37843784 \\ return NULL;
37853785 \\}
37863786 , &.{});
3787 dso.linkLibC();
3787 dso.root_module.link_libc = true;
37883788
37893789 const exe = addExecutable(b, opts, .{ .name = "main" });
37903790 addCSourceBytes(exe,
......@@ -3811,8 +3811,8 @@ fn testTlsOffsetAlignment(b: *Build, opts: Options) *Step {
38113811 \\ pthread_join(thread, NULL);
38123812 \\}
38133813 , &.{});
3814 exe.addRPath(dso.getEmittedBinDirectory());
3815 exe.linkLibC();
3814 exe.root_module.addRPath(dso.getEmittedBinDirectory());
3815 exe.root_module.link_libc = true;
38163816 exe.root_module.pic = true;
38173817
38183818 const run = addRunArtifact(exe);
......@@ -3842,14 +3842,14 @@ fn testTlsPic(b: *Build, opts: Options) *Step {
38423842 ,
38433843 .pic = true,
38443844 });
3845 obj.linkLibC();
3845 obj.root_module.link_libc = true;
38463846
38473847 const exe = addExecutable(b, opts, .{ .name = "main" });
38483848 addCSourceBytes(exe,
38493849 \\__attribute__((tls_model("global-dynamic"))) _Thread_local int foo = 3;
38503850 , &.{});
3851 exe.addObject(obj);
3852 exe.linkLibC();
3851 exe.root_module.addObject(obj);
3852 exe.root_module.link_libc = true;
38533853
38543854 const run = addRunArtifact(exe);
38553855 run.expectStdOutEqual("3 5 3 5\n");
......@@ -3889,14 +3889,14 @@ fn testTlsSmallAlignment(b: *Build, opts: Options) *Step {
38893889 ,
38903890 .pic = true,
38913891 });
3892 c_o.linkLibC();
3892 c_o.root_module.link_libc = true;
38933893
38943894 {
38953895 const exe = addExecutable(b, opts, .{ .name = "main" });
3896 exe.addObject(a_o);
3897 exe.addObject(b_o);
3898 exe.addObject(c_o);
3899 exe.linkLibC();
3896 exe.root_module.addObject(a_o);
3897 exe.root_module.addObject(b_o);
3898 exe.root_module.addObject(c_o);
3899 exe.root_module.link_libc = true;
39003900
39013901 const run = addRunArtifact(exe);
39023902 run.expectStdOutEqual("42\n");
......@@ -3905,13 +3905,13 @@ fn testTlsSmallAlignment(b: *Build, opts: Options) *Step {
39053905
39063906 {
39073907 const dso = addSharedLibrary(b, opts, .{ .name = "a" });
3908 dso.addObject(a_o);
3909 dso.addObject(b_o);
3908 dso.root_module.addObject(a_o);
3909 dso.root_module.addObject(b_o);
39103910
39113911 const exe = addExecutable(b, opts, .{ .name = "main" });
3912 exe.addObject(c_o);
3913 exe.linkLibrary(dso);
3914 exe.linkLibC();
3912 exe.root_module.addObject(c_o);
3913 exe.root_module.linkLibrary(dso);
3914 exe.root_module.link_libc = true;
39153915
39163916 const run = addRunArtifact(exe);
39173917 run.expectStdOutEqual("42\n");
......@@ -3939,7 +3939,7 @@ fn testTlsStatic(b: *Build, opts: Options) *Step {
39393939 \\ return 0;
39403940 \\}
39413941 , &.{});
3942 exe.linkLibC();
3942 exe.root_module.link_libc = true;
39433943
39443944 const run = addRunArtifact(exe);
39453945 run.expectStdOutEqual(
......@@ -3969,8 +3969,8 @@ fn testUnknownFileTypeError(b: *Build, opts: Options) *Step {
39693969 \\ return foo;
39703970 \\}
39713971 , &.{});
3972 exe.linkLibrary(dylib);
3973 exe.linkLibC();
3972 exe.root_module.linkLibrary(dylib);
3973 exe.root_module.link_libc = true;
39743974
39753975 expectLinkErrors(exe, test_step, .{
39763976 .contains = "error: failed to parse shared library: BadMagic",
......@@ -3993,7 +3993,7 @@ fn testUnresolvedError(b: *Build, opts: Options) *Step {
39933993 ,
39943994 .c_source_flags = &.{"-ffunction-sections"},
39953995 });
3996 obj1.linkLibC();
3996 obj1.root_module.link_libc = true;
39973997
39983998 const obj2 = addObject(b, opts, .{
39993999 .name = "b",
......@@ -4007,12 +4007,12 @@ fn testUnresolvedError(b: *Build, opts: Options) *Step {
40074007 ,
40084008 .c_source_flags = &.{"-ffunction-sections"},
40094009 });
4010 obj2.linkLibC();
4010 obj2.root_module.link_libc = true;
40114011
40124012 const exe = addExecutable(b, opts, .{ .name = "main" });
4013 exe.addObject(obj1);
4014 exe.addObject(obj2);
4015 exe.linkLibC();
4013 exe.root_module.addObject(obj1);
4014 exe.root_module.addObject(obj2);
4015 exe.root_module.link_libc = true;
40164016
40174017 expectLinkErrors(exe, test_step, .{ .exact = &.{
40184018 "error: undefined symbol: foo",
......@@ -4037,12 +4037,12 @@ fn testWeakExports(b: *Build, opts: Options) *Step {
40374037 ,
40384038 .pic = true,
40394039 });
4040 obj.linkLibC();
4040 obj.root_module.link_libc = true;
40414041
40424042 {
40434043 const dso = addSharedLibrary(b, opts, .{ .name = "a" });
4044 dso.addObject(obj);
4045 dso.linkLibC();
4044 dso.root_module.addObject(obj);
4045 dso.root_module.link_libc = true;
40464046
40474047 const check = dso.checkObject();
40484048 check.checkInDynamicSymtab();
......@@ -4052,8 +4052,8 @@ fn testWeakExports(b: *Build, opts: Options) *Step {
40524052
40534053 {
40544054 const exe = addExecutable(b, opts, .{ .name = "main" });
4055 exe.addObject(obj);
4056 exe.linkLibC();
4055 exe.root_module.addObject(obj);
4056 exe.root_module.link_libc = true;
40574057
40584058 const check = exe.checkObject();
40594059 check.checkInDynamicSymtab();
......@@ -4084,8 +4084,8 @@ fn testWeakUndefsDso(b: *Build, opts: Options) *Step {
40844084 \\int bar();
40854085 \\int main() { printf("bar=%d\n", bar()); }
40864086 , &.{});
4087 exe.linkLibrary(dso);
4088 exe.linkLibC();
4087 exe.root_module.linkLibrary(dso);
4088 exe.root_module.link_libc = true;
40894089
40904090 const run = addRunArtifact(exe);
40914091 run.expectStdOutEqual("bar=-1\n");
......@@ -4100,8 +4100,8 @@ fn testWeakUndefsDso(b: *Build, opts: Options) *Step {
41004100 \\int bar();
41014101 \\int main() { printf("bar=%d\n", bar()); }
41024102 , &.{});
4103 exe.linkLibrary(dso);
4104 exe.linkLibC();
4103 exe.root_module.linkLibrary(dso);
4104 exe.root_module.link_libc = true;
41054105
41064106 const run = addRunArtifact(exe);
41074107 run.expectStdOutEqual("bar=5\n");
......@@ -4122,7 +4122,7 @@ fn testZNow(b: *Build, opts: Options) *Step {
41224122
41234123 {
41244124 const dso = addSharedLibrary(b, opts, .{ .name = "a" });
4125 dso.addObject(obj);
4125 dso.root_module.addObject(obj);
41264126
41274127 const check = dso.checkObject();
41284128 check.checkInDynamicSection();
......@@ -4132,7 +4132,7 @@ fn testZNow(b: *Build, opts: Options) *Step {
41324132
41334133 {
41344134 const dso = addSharedLibrary(b, opts, .{ .name = "a" });
4135 dso.addObject(obj);
4135 dso.root_module.addObject(obj);
41364136 dso.link_z_lazy = true;
41374137
41384138 const check = dso.checkObject();
......@@ -4150,7 +4150,7 @@ fn testZStackSize(b: *Build, opts: Options) *Step {
41504150 const exe = addExecutable(b, opts, .{ .name = "main" });
41514151 addCSourceBytes(exe, "int main() { return 0; }", &.{});
41524152 exe.stack_size = 0x800000;
4153 exe.linkLibC();
4153 exe.root_module.link_libc = true;
41544154
41554155 const check = exe.checkObject();
41564156 check.checkInHeaders();
......@@ -4202,8 +4202,8 @@ fn testZText(b: *Build, opts: Options) *Step {
42024202 });
42034203
42044204 const dso = addSharedLibrary(b, opts, .{ .name = "a" });
4205 dso.addObject(a_o);
4206 dso.addObject(b_o);
4205 dso.root_module.addObject(a_o);
4206 dso.root_module.addObject(b_o);
42074207 dso.link_z_notext = true;
42084208
42094209 const exe = addExecutable(b, opts, .{ .name = "main" });
......@@ -4214,8 +4214,8 @@ fn testZText(b: *Build, opts: Options) *Step {
42144214 \\ printf("%d\n", fnn());
42154215 \\}
42164216 , &.{});
4217 exe.linkLibrary(dso);
4218 exe.linkLibC();
4217 exe.root_module.linkLibrary(dso);
4218 exe.root_module.link_libc = true;
42194219
42204220 const run = addRunArtifact(exe);
42214221 run.expectStdOutEqual("3\n");
test/link/link.zig+3-3
......@@ -140,20 +140,20 @@ pub fn addRunArtifact(comp: *Compile) *Run {
140140pub fn addCSourceBytes(comp: *Compile, bytes: []const u8, flags: []const []const u8) void {
141141 const b = comp.step.owner;
142142 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 });
144144}
145145
146146pub fn addCppSourceBytes(comp: *Compile, bytes: []const u8, flags: []const []const u8) void {
147147 const b = comp.step.owner;
148148 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 });
150150}
151151
152152pub fn addAsmSourceBytes(comp: *Compile, bytes: []const u8) void {
153153 const b = comp.step.owner;
154154 const actual_bytes = std.fmt.allocPrint(b.allocator, "{s}\n", .{bytes}) catch @panic("OOM");
155155 const file = WriteFile.create(b).add("a.s", actual_bytes);
156 comp.addAssemblyFile(file);
156 comp.root_module.addAssemblyFile(file);
157157}
158158
159159pub 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 {
127127
128128 {
129129 const exe = addExecutable(b, opts, .{ .name = "no_dead_strip" });
130 exe.addObject(obj);
130 exe.root_module.addObject(obj);
131131 exe.link_gc_sections = false;
132132
133133 const check = exe.checkObject();
......@@ -156,7 +156,7 @@ fn testDeadStrip(b: *Build, opts: Options) *Step {
156156
157157 {
158158 const exe = addExecutable(b, opts, .{ .name = "yes_dead_strip" });
159 exe.addObject(obj);
159 exe.root_module.addObject(obj);
160160 exe.link_gc_sections = true;
161161
162162 const check = exe.checkObject();
......@@ -206,7 +206,7 @@ fn testDuplicateDefinitions(b: *Build, opts: Options) *Step {
206206 \\ strong();
207207 \\}
208208 });
209 exe.addObject(obj);
209 exe.root_module.addObject(obj);
210210
211211 expectLinkErrors(exe, test_step, .{ .exact = &.{
212212 "error: duplicate symbol definition: _strong",
......@@ -235,7 +235,7 @@ fn testDeadStripDylibs(b: *Build, opts: Options) *Step {
235235
236236 {
237237 const exe = addExecutable(b, opts, .{ .name = "main1" });
238 exe.addObject(main_o);
238 exe.root_module.addObject(main_o);
239239 exe.root_module.linkFramework("Cocoa", .{});
240240
241241 const check = exe.checkObject();
......@@ -254,7 +254,7 @@ fn testDeadStripDylibs(b: *Build, opts: Options) *Step {
254254
255255 {
256256 const exe = addExecutable(b, opts, .{ .name = "main2" });
257 exe.addObject(main_o);
257 exe.root_module.addObject(main_o);
258258 exe.root_module.linkFramework("Cocoa", .{});
259259 exe.dead_strip_dylibs = true;
260260
......@@ -350,7 +350,7 @@ fn testEmptyObject(b: *Build, opts: Options) *Step {
350350 \\ printf("Hello world!");
351351 \\}
352352 });
353 exe.addObject(empty);
353 exe.root_module.addObject(empty);
354354
355355 const run = addRunArtifact(exe);
356356 run.expectStdOutEqual("Hello world!");
......@@ -451,7 +451,7 @@ fn testEntryPointDylib(b: *Build, opts: Options) *Step {
451451 \\ return 0;
452452 \\}
453453 , &.{});
454 exe.linkLibrary(dylib);
454 exe.root_module.linkLibrary(dylib);
455455 exe.entry = .{ .symbol_name = "_bootstrap" };
456456 exe.forceUndefinedSymbol("_my_main");
457457
......@@ -604,11 +604,11 @@ fn testHeaderWeakFlags(b: *Build, opts: Options) *Step {
604604 });
605605
606606 const lib = addSharedLibrary(b, opts, .{ .name = "a" });
607 lib.addObject(obj1);
607 lib.root_module.addObject(obj1);
608608
609609 {
610610 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
613613 const check = exe.checkObject();
614614 check.checkInHeaders();
......@@ -642,8 +642,8 @@ fn testHeaderWeakFlags(b: *Build, opts: Options) *Step {
642642 }
643643
644644 const exe = addExecutable(b, opts, .{ .name = "main2" });
645 exe.linkLibrary(lib);
646 exe.addObject(obj);
645 exe.root_module.linkLibrary(lib);
646 exe.root_module.addObject(obj);
647647
648648 const check = exe.checkObject();
649649 check.checkInHeaders();
......@@ -665,7 +665,7 @@ fn testHeaderWeakFlags(b: *Build, opts: Options) *Step {
665665 \\_main:
666666 \\ ret
667667 });
668 exe.linkLibrary(lib);
668 exe.root_module.linkLibrary(lib);
669669
670670 const check = exe.checkObject();
671671 check.checkInHeaders();
......@@ -910,7 +910,7 @@ fn testLinkingStaticLib(b: *Build, opts: Options) *Step {
910910 \\}
911911 ,
912912 });
913 lib.addObject(obj);
913 lib.root_module.addObject(obj);
914914
915915 const exe = addExecutable(b, opts, .{
916916 .name = "testlib",
......@@ -923,7 +923,7 @@ fn testLinkingStaticLib(b: *Build, opts: Options) *Step {
923923 \\}
924924 ,
925925 });
926 exe.linkLibrary(lib);
926 exe.root_module.linkLibrary(lib);
927927
928928 const run = addRunArtifact(exe);
929929 run.expectStdErrEqual("0\n");
......@@ -1051,28 +1051,28 @@ fn testMergeLiteralsX64(b: *Build, opts: Options) *Step {
10511051
10521052 {
10531053 const exe = addExecutable(b, opts, .{ .name = "main1" });
1054 exe.addObject(a_o);
1055 exe.addObject(b_o);
1056 exe.addObject(main_o);
1054 exe.root_module.addObject(a_o);
1055 exe.root_module.addObject(b_o);
1056 exe.root_module.addObject(main_o);
10571057 runWithChecks(test_step, exe);
10581058 }
10591059
10601060 {
10611061 const exe = addExecutable(b, opts, .{ .name = "main2" });
1062 exe.addObject(b_o);
1063 exe.addObject(a_o);
1064 exe.addObject(main_o);
1062 exe.root_module.addObject(b_o);
1063 exe.root_module.addObject(a_o);
1064 exe.root_module.addObject(main_o);
10651065 runWithChecks(test_step, exe);
10661066 }
10671067
10681068 {
10691069 const c_o = addObject(b, opts, .{ .name = "c" });
1070 c_o.addObject(a_o);
1071 c_o.addObject(b_o);
1072 c_o.addObject(main_o);
1070 c_o.root_module.addObject(a_o);
1071 c_o.root_module.addObject(b_o);
1072 c_o.root_module.addObject(main_o);
10731073
10741074 const exe = addExecutable(b, opts, .{ .name = "main3" });
1075 exe.addObject(c_o);
1075 exe.root_module.addObject(c_o);
10761076 runWithChecks(test_step, exe);
10771077 }
10781078
......@@ -1167,28 +1167,28 @@ fn testMergeLiteralsArm64(b: *Build, opts: Options) *Step {
11671167
11681168 {
11691169 const exe = addExecutable(b, opts, .{ .name = "main1" });
1170 exe.addObject(a_o);
1171 exe.addObject(b_o);
1172 exe.addObject(main_o);
1170 exe.root_module.addObject(a_o);
1171 exe.root_module.addObject(b_o);
1172 exe.root_module.addObject(main_o);
11731173 runWithChecks(test_step, exe);
11741174 }
11751175
11761176 {
11771177 const exe = addExecutable(b, opts, .{ .name = "main2" });
1178 exe.addObject(b_o);
1179 exe.addObject(a_o);
1180 exe.addObject(main_o);
1178 exe.root_module.addObject(b_o);
1179 exe.root_module.addObject(a_o);
1180 exe.root_module.addObject(main_o);
11811181 runWithChecks(test_step, exe);
11821182 }
11831183
11841184 {
11851185 const c_o = addObject(b, opts, .{ .name = "c" });
1186 c_o.addObject(a_o);
1187 c_o.addObject(b_o);
1188 c_o.addObject(main_o);
1186 c_o.root_module.addObject(a_o);
1187 c_o.root_module.addObject(b_o);
1188 c_o.root_module.addObject(main_o);
11891189
11901190 const exe = addExecutable(b, opts, .{ .name = "main3" });
1191 exe.addObject(c_o);
1191 exe.root_module.addObject(c_o);
11921192 runWithChecks(test_step, exe);
11931193 }
11941194
......@@ -1259,9 +1259,9 @@ fn testMergeLiteralsArm642(b: *Build, opts: Options) *Step {
12591259 });
12601260
12611261 const exe = addExecutable(b, opts, .{ .name = "main1" });
1262 exe.addObject(a_o);
1263 exe.addObject(b_o);
1264 exe.addObject(main_o);
1262 exe.root_module.addObject(a_o);
1263 exe.root_module.addObject(b_o);
1264 exe.root_module.addObject(main_o);
12651265
12661266 const check = exe.checkObject();
12671267 check.dumpSection("__TEXT,__const");
......@@ -1335,17 +1335,17 @@ fn testMergeLiteralsAlignment(b: *Build, opts: Options) *Step {
13351335
13361336 {
13371337 const exe = addExecutable(b, opts, .{ .name = "main1" });
1338 exe.addObject(a_o);
1339 exe.addObject(b_o);
1340 exe.addObject(main_o);
1338 exe.root_module.addObject(a_o);
1339 exe.root_module.addObject(b_o);
1340 exe.root_module.addObject(main_o);
13411341 runWithChecks(test_step, exe);
13421342 }
13431343
13441344 {
13451345 const exe = addExecutable(b, opts, .{ .name = "main2" });
1346 exe.addObject(b_o);
1347 exe.addObject(a_o);
1348 exe.addObject(main_o);
1346 exe.root_module.addObject(b_o);
1347 exe.root_module.addObject(a_o);
1348 exe.root_module.addObject(main_o);
13491349 runWithChecks(test_step, exe);
13501350 }
13511351
......@@ -1414,27 +1414,27 @@ fn testMergeLiteralsObjc(b: *Build, opts: Options) *Step {
14141414
14151415 {
14161416 const exe = addExecutable(b, opts, .{ .name = "main1" });
1417 exe.addObject(main_o);
1418 exe.addObject(a_o);
1417 exe.root_module.addObject(main_o);
1418 exe.root_module.addObject(a_o);
14191419 exe.root_module.linkFramework("Foundation", .{});
14201420 runWithChecks(test_step, exe);
14211421 }
14221422
14231423 {
14241424 const exe = addExecutable(b, opts, .{ .name = "main2" });
1425 exe.addObject(a_o);
1426 exe.addObject(main_o);
1425 exe.root_module.addObject(a_o);
1426 exe.root_module.addObject(main_o);
14271427 exe.root_module.linkFramework("Foundation", .{});
14281428 runWithChecks(test_step, exe);
14291429 }
14301430
14311431 {
14321432 const b_o = addObject(b, opts, .{ .name = "b" });
1433 b_o.addObject(a_o);
1434 b_o.addObject(main_o);
1433 b_o.root_module.addObject(a_o);
1434 b_o.root_module.addObject(main_o);
14351435
14361436 const exe = addExecutable(b, opts, .{ .name = "main3" });
1437 exe.addObject(b_o);
1437 exe.root_module.addObject(b_o);
14381438 exe.root_module.linkFramework("Foundation", .{});
14391439 runWithChecks(test_step, exe);
14401440 }
......@@ -1610,7 +1610,7 @@ fn testObjcpp(b: *Build, opts: Options) *Step {
16101610 \\@end
16111611 });
16121612 foo_o.root_module.addIncludePath(foo_h.dirname());
1613 foo_o.linkLibCpp();
1613 foo_o.root_module.link_libcpp = true;
16141614
16151615 const exe = addExecutable(b, opts, .{ .name = "main", .objcpp_source_bytes =
16161616 \\#import "Foo.h"
......@@ -1628,8 +1628,8 @@ fn testObjcpp(b: *Build, opts: Options) *Step {
16281628 \\}
16291629 });
16301630 exe.root_module.addIncludePath(foo_h.dirname());
1631 exe.addObject(foo_o);
1632 exe.linkLibCpp();
1631 exe.root_module.addObject(foo_o);
1632 exe.root_module.link_libcpp = true;
16331633 exe.root_module.linkFramework("Foundation", .{});
16341634
16351635 const run = addRunArtifact(exe);
......@@ -1693,7 +1693,7 @@ fn testReexportsZig(b: *Build, opts: Options) *Step {
16931693 \\ return bar() - foo();
16941694 \\}
16951695 });
1696 exe.linkLibrary(lib);
1696 exe.root_module.linkLibrary(lib);
16971697
16981698 const run = addRunArtifact(exe);
16991699 run.expectExitCode(0);
......@@ -1711,7 +1711,7 @@ fn testRelocatable(b: *Build, opts: Options) *Step {
17111711 \\ throw std::runtime_error("Oh no!");
17121712 \\}
17131713 });
1714 a_o.linkLibCpp();
1714 a_o.root_module.link_libcpp = true;
17151715
17161716 const b_o = addObject(b, opts, .{ .name = "b", .cpp_source_bytes =
17171717 \\extern int try_me();
......@@ -1733,19 +1733,19 @@ fn testRelocatable(b: *Build, opts: Options) *Step {
17331733 \\ return 0;
17341734 \\}
17351735 });
1736 main_o.linkLibCpp();
1736 main_o.root_module.link_libcpp = true;
17371737
17381738 const exp_stdout = "exception=Oh no!";
17391739
17401740 {
17411741 const c_o = addObject(b, opts, .{ .name = "c" });
1742 c_o.addObject(a_o);
1743 c_o.addObject(b_o);
1742 c_o.root_module.addObject(a_o);
1743 c_o.root_module.addObject(b_o);
17441744
17451745 const exe = addExecutable(b, opts, .{ .name = "main1" });
1746 exe.addObject(main_o);
1747 exe.addObject(c_o);
1748 exe.linkLibCpp();
1746 exe.root_module.addObject(main_o);
1747 exe.root_module.addObject(c_o);
1748 exe.root_module.link_libcpp = true;
17491749
17501750 const run = addRunArtifact(exe);
17511751 run.expectStdOutEqual(exp_stdout);
......@@ -1754,13 +1754,13 @@ fn testRelocatable(b: *Build, opts: Options) *Step {
17541754
17551755 {
17561756 const d_o = addObject(b, opts, .{ .name = "d" });
1757 d_o.addObject(a_o);
1758 d_o.addObject(b_o);
1759 d_o.addObject(main_o);
1757 d_o.root_module.addObject(a_o);
1758 d_o.root_module.addObject(b_o);
1759 d_o.root_module.addObject(main_o);
17601760
17611761 const exe = addExecutable(b, opts, .{ .name = "main2" });
1762 exe.addObject(d_o);
1763 exe.linkLibCpp();
1762 exe.root_module.addObject(d_o);
1763 exe.root_module.link_libcpp = true;
17641764
17651765 const run = addRunArtifact(exe);
17661766 run.expectStdOutEqual(exp_stdout);
......@@ -1805,12 +1805,12 @@ fn testRelocatableZig(b: *Build, opts: Options) *Step {
18051805 });
18061806
18071807 const c_o = addObject(b, opts, .{ .name = "c" });
1808 c_o.addObject(a_o);
1809 c_o.addObject(b_o);
1810 c_o.addObject(main_o);
1808 c_o.root_module.addObject(a_o);
1809 c_o.root_module.addObject(b_o);
1810 c_o.root_module.addObject(main_o);
18111811
18121812 const exe = addExecutable(b, opts, .{ .name = "main" });
1813 exe.addObject(c_o);
1813 exe.root_module.addObject(c_o);
18141814
18151815 const run = addRunArtifact(exe);
18161816 run.addCheck(.{ .expect_stderr_match = b.dupe("incrFoo=1") });
......@@ -1833,10 +1833,10 @@ fn testSearchStrategy(b: *Build, opts: Options) *Step {
18331833 });
18341834
18351835 const liba = addStaticLibrary(b, opts, .{ .name = "a" });
1836 liba.addObject(obj);
1836 liba.root_module.addObject(obj);
18371837
18381838 const dylib = addSharedLibrary(b, opts, .{ .name = "a" });
1839 dylib.addObject(obj);
1839 dylib.root_module.addObject(obj);
18401840
18411841 const main_o = addObject(b, opts, .{ .name = "main", .c_source_bytes =
18421842 \\#include<stdio.h>
......@@ -1850,7 +1850,7 @@ fn testSearchStrategy(b: *Build, opts: Options) *Step {
18501850
18511851 {
18521852 const exe = addExecutable(b, opts, .{ .name = "main" });
1853 exe.addObject(main_o);
1853 exe.root_module.addObject(main_o);
18541854 exe.root_module.linkSystemLibrary("a", .{ .use_pkg_config = .no, .search_strategy = .mode_first });
18551855 exe.root_module.addLibraryPath(liba.getEmittedBinDirectory());
18561856 exe.root_module.addLibraryPath(dylib.getEmittedBinDirectory());
......@@ -1869,7 +1869,7 @@ fn testSearchStrategy(b: *Build, opts: Options) *Step {
18691869
18701870 {
18711871 const exe = addExecutable(b, opts, .{ .name = "main" });
1872 exe.addObject(main_o);
1872 exe.root_module.addObject(main_o);
18731873 exe.root_module.linkSystemLibrary("a", .{ .use_pkg_config = .no, .search_strategy = .paths_first });
18741874 exe.root_module.addLibraryPath(liba.getEmittedBinDirectory());
18751875 exe.root_module.addLibraryPath(dylib.getEmittedBinDirectory());
......@@ -1924,9 +1924,9 @@ fn testSectionBoundarySymbols(b: *Build, opts: Options) *Step {
19241924 });
19251925
19261926 const exe = addExecutable(b, opts, .{ .name = "test" });
1927 exe.addObject(obj1);
1928 exe.addObject(obj2);
1929 exe.addObject(main_o);
1927 exe.root_module.addObject(obj1);
1928 exe.root_module.addObject(obj2);
1929 exe.root_module.addObject(main_o);
19301930
19311931 const run = b.addRunArtifact(exe);
19321932 run.skip_foreign_checks = true;
......@@ -1951,9 +1951,9 @@ fn testSectionBoundarySymbols(b: *Build, opts: Options) *Step {
19511951 });
19521952
19531953 const exe = addExecutable(b, opts, .{ .name = "test" });
1954 exe.addObject(obj1);
1955 exe.addObject(obj3);
1956 exe.addObject(main_o);
1954 exe.root_module.addObject(obj1);
1955 exe.root_module.addObject(obj3);
1956 exe.root_module.addObject(main_o);
19571957
19581958 const run = b.addRunArtifact(exe);
19591959 run.skip_foreign_checks = true;
......@@ -2031,9 +2031,9 @@ fn testSegmentBoundarySymbols(b: *Build, opts: Options) *Step {
20312031 });
20322032
20332033 const exe = addExecutable(b, opts, .{ .name = "main" });
2034 exe.addObject(obj1);
2035 exe.addObject(obj2);
2036 exe.addObject(main_o);
2034 exe.root_module.addObject(obj1);
2035 exe.root_module.addObject(obj2);
2036 exe.root_module.addObject(main_o);
20372037
20382038 const run = addRunArtifact(exe);
20392039 run.expectStdOutEqual("All your codebase are belong to us.\n");
......@@ -2054,9 +2054,9 @@ fn testSegmentBoundarySymbols(b: *Build, opts: Options) *Step {
20542054 });
20552055
20562056 const exe = addExecutable(b, opts, .{ .name = "main2" });
2057 exe.addObject(obj1);
2058 exe.addObject(obj2);
2059 exe.addObject(main_o);
2057 exe.root_module.addObject(obj1);
2058 exe.root_module.addObject(obj2);
2059 exe.root_module.addObject(main_o);
20602060
20612061 const check = exe.checkObject();
20622062 check.checkInHeaders();
......@@ -2102,9 +2102,9 @@ fn testSymbolStabs(b: *Build, opts: Options) *Step {
21022102 });
21032103
21042104 const exe = addExecutable(b, opts, .{ .name = "main" });
2105 exe.addObject(a_o);
2106 exe.addObject(b_o);
2107 exe.addObject(main_o);
2105 exe.root_module.addObject(a_o);
2106 exe.root_module.addObject(b_o);
2107 exe.root_module.addObject(main_o);
21082108
21092109 const run = addRunArtifact(exe);
21102110 run.expectStdOutEqual("foo=42,bar=24");
......@@ -2299,7 +2299,7 @@ fn testTlsPointers(b: *Build, opts: Options) *Step {
22992299 \\}
23002300 });
23012301 bar_o.root_module.addIncludePath(foo_h.dirname());
2302 bar_o.linkLibCpp();
2302 bar_o.root_module.link_libcpp = true;
23032303
23042304 const baz_o = addObject(b, opts, .{ .name = "baz", .cpp_source_bytes =
23052305 \\#include "foo.h"
......@@ -2309,7 +2309,7 @@ fn testTlsPointers(b: *Build, opts: Options) *Step {
23092309 \\}
23102310 });
23112311 baz_o.root_module.addIncludePath(foo_h.dirname());
2312 baz_o.linkLibCpp();
2312 baz_o.root_module.link_libcpp = true;
23132313
23142314 const main_o = addObject(b, opts, .{ .name = "main", .cpp_source_bytes =
23152315 \\extern int bar();
......@@ -2321,13 +2321,13 @@ fn testTlsPointers(b: *Build, opts: Options) *Step {
23212321 \\}
23222322 });
23232323 main_o.root_module.addIncludePath(foo_h.dirname());
2324 main_o.linkLibCpp();
2324 main_o.root_module.link_libcpp = true;
23252325
23262326 const exe = addExecutable(b, opts, .{ .name = "main" });
2327 exe.addObject(bar_o);
2328 exe.addObject(baz_o);
2329 exe.addObject(main_o);
2330 exe.linkLibCpp();
2327 exe.root_module.addObject(bar_o);
2328 exe.root_module.addObject(baz_o);
2329 exe.root_module.addObject(main_o);
2330 exe.root_module.link_libcpp = true;
23312331
23322332 const run = addRunArtifact(exe);
23332333 run.expectExitCode(0);
......@@ -2445,7 +2445,7 @@ fn testTwoLevelNamespace(b: *Build, opts: Options) *Step {
24452445
24462446 {
24472447 const exe = addExecutable(b, opts, .{ .name = "main1" });
2448 exe.addObject(main_o);
2448 exe.root_module.addObject(main_o);
24492449 exe.root_module.linkSystemLibrary("a", .{});
24502450 exe.root_module.linkSystemLibrary("b", .{});
24512451 exe.root_module.addLibraryPath(liba.getEmittedBinDirectory());
......@@ -2474,7 +2474,7 @@ fn testTwoLevelNamespace(b: *Build, opts: Options) *Step {
24742474
24752475 {
24762476 const exe = addExecutable(b, opts, .{ .name = "main2" });
2477 exe.addObject(main_o);
2477 exe.root_module.addObject(main_o);
24782478 exe.root_module.linkSystemLibrary("b", .{});
24792479 exe.root_module.linkSystemLibrary("a", .{});
24802480 exe.root_module.addLibraryPath(liba.getEmittedBinDirectory());
......@@ -2510,14 +2510,14 @@ fn testDiscardLocalSymbols(b: *Build, opts: Options) *Step {
25102510 const obj = addObject(b, opts, .{ .name = "a", .c_source_bytes = "static int foo = 42;" });
25112511
25122512 const lib = addStaticLibrary(b, opts, .{ .name = "a" });
2513 lib.addObject(obj);
2513 lib.root_module.addObject(obj);
25142514
25152515 const main_o = addObject(b, opts, .{ .name = "main", .c_source_bytes = "int main() { return 0; }" });
25162516
25172517 {
25182518 const exe = addExecutable(b, opts, .{ .name = "main3" });
2519 exe.addObject(main_o);
2520 exe.addObject(obj);
2519 exe.root_module.addObject(main_o);
2520 exe.root_module.addObject(obj);
25212521 exe.discard_local_symbols = true;
25222522
25232523 const run = addRunArtifact(exe);
......@@ -2532,8 +2532,8 @@ fn testDiscardLocalSymbols(b: *Build, opts: Options) *Step {
25322532
25332533 {
25342534 const exe = addExecutable(b, opts, .{ .name = "main4" });
2535 exe.addObject(main_o);
2536 exe.linkLibrary(lib);
2535 exe.root_module.addObject(main_o);
2536 exe.root_module.linkLibrary(lib);
25372537 exe.discard_local_symbols = true;
25382538
25392539 const run = addRunArtifact(exe);
......@@ -2555,14 +2555,14 @@ fn testUndefinedFlag(b: *Build, opts: Options) *Step {
25552555 const obj = addObject(b, opts, .{ .name = "a", .c_source_bytes = "int foo = 42;" });
25562556
25572557 const lib = addStaticLibrary(b, opts, .{ .name = "a" });
2558 lib.addObject(obj);
2558 lib.root_module.addObject(obj);
25592559
25602560 const main_o = addObject(b, opts, .{ .name = "main", .c_source_bytes = "int main() { return 0; }" });
25612561
25622562 {
25632563 const exe = addExecutable(b, opts, .{ .name = "main1" });
2564 exe.addObject(main_o);
2565 exe.linkLibrary(lib);
2564 exe.root_module.addObject(main_o);
2565 exe.root_module.linkLibrary(lib);
25662566 exe.forceUndefinedSymbol("_foo");
25672567
25682568 const run = addRunArtifact(exe);
......@@ -2577,8 +2577,8 @@ fn testUndefinedFlag(b: *Build, opts: Options) *Step {
25772577
25782578 {
25792579 const exe = addExecutable(b, opts, .{ .name = "main2" });
2580 exe.addObject(main_o);
2581 exe.linkLibrary(lib);
2580 exe.root_module.addObject(main_o);
2581 exe.root_module.linkLibrary(lib);
25822582 exe.forceUndefinedSymbol("_foo");
25832583 exe.link_gc_sections = true;
25842584
......@@ -2594,8 +2594,8 @@ fn testUndefinedFlag(b: *Build, opts: Options) *Step {
25942594
25952595 {
25962596 const exe = addExecutable(b, opts, .{ .name = "main3" });
2597 exe.addObject(main_o);
2598 exe.addObject(obj);
2597 exe.root_module.addObject(main_o);
2598 exe.root_module.addObject(obj);
25992599
26002600 const run = addRunArtifact(exe);
26012601 run.expectExitCode(0);
......@@ -2609,8 +2609,8 @@ fn testUndefinedFlag(b: *Build, opts: Options) *Step {
26092609
26102610 {
26112611 const exe = addExecutable(b, opts, .{ .name = "main4" });
2612 exe.addObject(main_o);
2613 exe.addObject(obj);
2612 exe.root_module.addObject(main_o);
2613 exe.root_module.addObject(obj);
26142614 exe.link_gc_sections = true;
26152615
26162616 const run = addRunArtifact(exe);
......@@ -2642,7 +2642,7 @@ fn testUnresolvedError(b: *Build, opts: Options) *Step {
26422642 \\ std.debug.print("foo() + bar() = {d}", .{foo() + bar()});
26432643 \\}
26442644 });
2645 exe.addObject(obj);
2645 exe.root_module.addObject(obj);
26462646
26472647 // TODO order should match across backends if possible
26482648 if (opts.use_llvm) {
......@@ -2764,7 +2764,7 @@ fn testUnwindInfo(b: *Build, opts: Options) *Step {
27642764 \\}
27652765 });
27662766 main_o.root_module.addIncludePath(all_h.dirname());
2767 main_o.linkLibCpp();
2767 main_o.root_module.link_libcpp = true;
27682768
27692769 const simple_string_o = addObject(b, opts, .{ .name = "simple_string", .cpp_source_bytes =
27702770 \\#include "all.h"
......@@ -2799,7 +2799,7 @@ fn testUnwindInfo(b: *Build, opts: Options) *Step {
27992799 \\}
28002800 });
28012801 simple_string_o.root_module.addIncludePath(all_h.dirname());
2802 simple_string_o.linkLibCpp();
2802 simple_string_o.root_module.link_libcpp = true;
28032803
28042804 const simple_string_owner_o = addObject(b, opts, .{ .name = "simple_string_owner", .cpp_source_bytes =
28052805 \\#include "all.h"
......@@ -2816,7 +2816,7 @@ fn testUnwindInfo(b: *Build, opts: Options) *Step {
28162816 \\}
28172817 });
28182818 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
28212821 const exp_stdout =
28222822 \\Constructed: a
......@@ -2828,10 +2828,10 @@ fn testUnwindInfo(b: *Build, opts: Options) *Step {
28282828 ;
28292829
28302830 const exe = addExecutable(b, opts, .{ .name = "main" });
2831 exe.addObject(main_o);
2832 exe.addObject(simple_string_o);
2833 exe.addObject(simple_string_owner_o);
2834 exe.linkLibCpp();
2831 exe.root_module.addObject(main_o);
2832 exe.root_module.addObject(simple_string_o);
2833 exe.root_module.addObject(simple_string_owner_o);
2834 exe.root_module.link_libcpp = true;
28352835
28362836 const run = addRunArtifact(exe);
28372837 run.expectStdOutEqual(exp_stdout);
......@@ -2896,7 +2896,7 @@ fn testUnwindInfoNoSubsectionsArm64(b: *Build, opts: Options) *Step {
28962896 \\ return 0;
28972897 \\}
28982898 });
2899 exe.addObject(a_o);
2899 exe.root_module.addObject(a_o);
29002900
29012901 const run = addRunArtifact(exe);
29022902 run.expectStdOutEqual("4\n");
......@@ -2948,7 +2948,7 @@ fn testUnwindInfoNoSubsectionsX64(b: *Build, opts: Options) *Step {
29482948 \\ return 0;
29492949 \\}
29502950 });
2951 exe.addObject(a_o);
2951 exe.root_module.addObject(a_o);
29522952
29532953 const run = addRunArtifact(exe);
29542954 run.expectStdOutEqual("4\n");
......@@ -3052,7 +3052,7 @@ fn testWeakBind(b: *Build, opts: Options) *Step {
30523052 \\ .quad 0
30533053 \\ .quad _weak_internal_tlv$tlv$init
30543054 });
3055 exe.linkLibrary(lib);
3055 exe.root_module.linkLibrary(lib);
30563056
30573057 {
30583058 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
1616 .target = b.resolveTargetQuery(.{ .cpu_arch = .wasm32, .os_tag = .wasi }),
1717 }),
1818 });
19 exe.addCSourceFile(.{ .file = b.path("foo.c"), .flags = &.{} });
19 exe.root_module.addCSourceFile(.{ .file = b.path("foo.c"), .flags = &.{} });
2020 exe.use_llvm = false;
2121 exe.use_lld = false;
2222
test/src/Cases.zig+4-6
......@@ -436,7 +436,7 @@ fn addFromDirInner(
436436 const target = &resolved_target.result;
437437 for (backends) |backend| {
438438 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)
440440 {
441441 // Other backends don't support new liveness format
442442 continue;
......@@ -447,10 +447,6 @@ fn addFromDirInner(
447447 // Rosetta has issues with ZLD
448448 continue;
449449 }
450 if (backend == .stage2 and target.ofmt == .coff) {
451 // COFF linker has bitrotted
452 continue;
453 }
454450
455451 const next = ctx.cases.items.len;
456452 try ctx.cases.append(.{
......@@ -560,7 +556,7 @@ pub fn lowerToTranslateCSteps(
560556 .root_module = translate_c.createModule(),
561557 });
562558 run_exe.step.name = b.fmt("{s} build-exe", .{annotated_case_name});
563 run_exe.linkLibC();
559 run_exe.root_module.link_libc = true;
564560 const run = b.addRunArtifact(run_exe);
565561 run.step.name = b.fmt("{s} run", .{annotated_case_name});
566562 run.expectStdOutEqual(output);
......@@ -800,6 +796,8 @@ const TestManifestConfigDefaults = struct {
800796 }
801797 // Windows
802798 defaults = defaults ++ "x86_64-windows" ++ ",";
799 // Wasm
800 defaults = defaults ++ "wasm32-wasi";
803801 break :blk defaults;
804802 };
805803 } 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 {
8989 .root_module = translate_c.createModule(),
9090 });
9191 exe.step.name = b.fmt("{s} build-exe", .{annotated_case_name});
92 exe.linkLibC();
92 exe.root_module.link_libc = true;
9393 const run = b.addRunArtifact(exe);
9494 run.step.name = b.fmt("{s} run", .{annotated_case_name});
9595 if (!case.allow_warnings) {
test/standalone/build.zig.zon+4-1
......@@ -1,6 +1,6 @@
11.{
22 .name = .standalone_test_cases,
3 .fingerprint = 0xc0dbdf9c818957be,
3 .fingerprint = 0xc0dbdf9c3b92810b,
44 .version = "0.0.0",
55 .dependencies = .{
66 .simple = .{
......@@ -181,6 +181,9 @@
181181 .install_headers = .{
182182 .path = "install_headers",
183183 },
184 .dependency_options = .{
185 .path = "dependency_options",
186 },
184187 .dependencyFromBuildZig = .{
185188 .path = "dependencyFromBuildZig",
186189 },
test/standalone/c_embed_path/build.zig+3-3
......@@ -13,12 +13,12 @@ pub fn build(b: *std.Build) void {
1313 .optimize = optimize,
1414 }),
1515 });
16 exe.addCSourceFile(.{
16 exe.root_module.addCSourceFile(.{
1717 .file = b.path("test.c"),
1818 .flags = &.{"-std=c23"},
1919 });
20 exe.linkLibC();
21 exe.addEmbedPath(b.path("data"));
20 exe.root_module.link_libc = true;
21 exe.root_module.addEmbedPath(b.path("data"));
2222
2323 const run_c_cmd = b.addRunArtifact(exe);
2424 run_c_cmd.expectExitCode(0);
test/standalone/dependencyFromBuildZig/build.zig.zon+2-1
......@@ -1,5 +1,6 @@
11.{
2 .name = "dependencyFromBuildZig",
2 .name = .dependencyFromBuildZig,
3 .fingerprint = 0xfd939a1eb8169080,
34 .version = "0.0.0",
45 .dependencies = .{
56 .other = .{
test/standalone/dependencyFromBuildZig/other/build.zig.zon+2-1
......@@ -1,5 +1,6 @@
11.{
2 .name = "other",
2 .name = .other,
3 .fingerprint = 0xd9583520a2405f6c,
34 .version = "0.0.0",
45 .dependencies = .{},
56 .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 {
3131 .target = b.graph.host,
3232 .optimize = optimize,
3333 }) });
34 test_exe.addObject(obj);
35 test_exe.linkLibrary(shared);
34 test_exe.root_module.addObject(obj);
35 test_exe.root_module.linkLibrary(shared);
3636
3737 test_step.dependOn(&b.addRunArtifact(test_exe).step);
3838}
test/standalone/issue_794/build.zig+1-1
......@@ -8,7 +8,7 @@ pub fn build(b: *std.Build) void {
88 .root_source_file = b.path("main.zig"),
99 .target = b.graph.host,
1010 }) });
11 test_artifact.addIncludePath(b.path("a_directory"));
11 test_artifact.root_module.addIncludePath(b.path("a_directory"));
1212
1313 // TODO: actually check the output
1414 _ = test_artifact.getEmittedBin();
test/standalone/stack_iterator/build.zig+64-63
......@@ -65,69 +65,70 @@ pub fn build(b: *std.Build) void {
6565 test_step.dependOn(&run_cmd.step);
6666 }
6767
68 // Unwinding through a C shared library without a frame pointer (libc)
69 //
70 // getcontext version: libc
71 //
72 // Unwind info type:
73 // - ELF: DWARF .eh_frame + .debug_frame
74 // - MachO: __unwind_info encodings:
75 // - x86_64: STACK_IMMD, STACK_IND
76 // - aarch64: FRAMELESS, DWARF
77 {
78 const c_shared_lib = b.addLibrary(.{
79 .linkage = .dynamic,
80 .name = "c_shared_lib",
81 .root_module = b.createModule(.{
82 .root_source_file = null,
83 .target = target,
84 .optimize = optimize,
85 .link_libc = true,
86 .strip = false,
87 }),
88 });
89
90 if (target.result.os.tag == .windows)
91 c_shared_lib.root_module.addCMacro("LIB_API", "__declspec(dllexport)");
92
93 c_shared_lib.root_module.addCSourceFile(.{
94 .file = b.path("shared_lib.c"),
95 .flags = &.{"-fomit-frame-pointer"},
96 });
97
98 const exe = b.addExecutable(.{
99 .name = "shared_lib_unwind",
100 .root_module = b.createModule(.{
101 .root_source_file = b.path("shared_lib_unwind.zig"),
102 .target = target,
103 .optimize = optimize,
104 .unwind_tables = if (target.result.os.tag.isDarwin()) .async else null,
105 .omit_frame_pointer = true,
106 }),
107 // zig objcopy doesn't support incremental binaries
108 .use_llvm = true,
109 });
110
111 exe.linkLibrary(c_shared_lib);
112
113 const run_cmd = b.addRunArtifact(exe);
114 test_step.dependOn(&run_cmd.step);
115
116 // Separate debug info ELF file
117 if (target.result.ofmt == .elf) {
118 const filename = b.fmt("{s}_stripped", .{exe.out_filename});
119 const stripped_exe = b.addObjCopy(exe.getEmittedBin(), .{
120 .basename = filename, // set the name for the debuglink
121 .compress_debug = true,
122 .strip = .debug,
123 .extract_to_separate_file = true,
124 });
125
126 const run_stripped = std.Build.Step.Run.create(b, b.fmt("run {s}", .{filename}));
127 run_stripped.addFileArg(stripped_exe.getOutput());
128 test_step.dependOn(&run_stripped.step);
129 }
130 }
68 // https://github.com/ziglang/zig/issues/24522
69 //// Unwinding through a C shared library without a frame pointer (libc)
70 ////
71 //// getcontext version: libc
72 ////
73 //// Unwind info type:
74 //// - ELF: DWARF .eh_frame + .debug_frame
75 //// - MachO: __unwind_info encodings:
76 //// - x86_64: STACK_IMMD, STACK_IND
77 //// - aarch64: FRAMELESS, DWARF
78 //{
79 // const c_shared_lib = b.addLibrary(.{
80 // .linkage = .dynamic,
81 // .name = "c_shared_lib",
82 // .root_module = b.createModule(.{
83 // .root_source_file = null,
84 // .target = target,
85 // .optimize = optimize,
86 // .link_libc = true,
87 // .strip = false,
88 // }),
89 // });
90
91 // if (target.result.os.tag == .windows)
92 // c_shared_lib.root_module.addCMacro("LIB_API", "__declspec(dllexport)");
93
94 // c_shared_lib.root_module.addCSourceFile(.{
95 // .file = b.path("shared_lib.c"),
96 // .flags = &.{"-fomit-frame-pointer"},
97 // });
98
99 // const exe = b.addExecutable(.{
100 // .name = "shared_lib_unwind",
101 // .root_module = b.createModule(.{
102 // .root_source_file = b.path("shared_lib_unwind.zig"),
103 // .target = target,
104 // .optimize = optimize,
105 // .unwind_tables = if (target.result.os.tag.isDarwin()) .async else null,
106 // .omit_frame_pointer = true,
107 // }),
108 // // zig objcopy doesn't support incremental binaries
109 // .use_llvm = true,
110 // });
111
112 // exe.root_module.linkLibrary(c_shared_lib);
113
114 // const run_cmd = b.addRunArtifact(exe);
115 // test_step.dependOn(&run_cmd.step);
116
117 // // Separate debug info ELF file
118 // if (target.result.ofmt == .elf) {
119 // const filename = b.fmt("{s}_stripped", .{exe.out_filename});
120 // const stripped_exe = b.addObjCopy(exe.getEmittedBin(), .{
121 // .basename = filename, // set the name for the debuglink
122 // .compress_debug = true,
123 // .strip = .debug,
124 // .extract_to_separate_file = true,
125 // });
126
127 // const run_stripped = std.Build.Step.Run.create(b, b.fmt("run {s}", .{filename}));
128 // run_stripped.addFileArg(stripped_exe.getOutput());
129 // test_step.dependOn(&run_stripped.step);
130 // }
131 //}
131132
132133 // Unwinding without libc/posix
133134 //
test/tests.zig+58-15
......@@ -116,8 +116,6 @@ const test_targets = blk: {
116116 .abi = .eabihf,
117117 },
118118 .link_libc = true,
119 // https://github.com/ziglang/zig/issues/23949
120 .skip_modules = &.{"std"},
121119 },
122120
123121 .{
......@@ -191,6 +189,30 @@ const test_targets = blk: {
191189 .link_libc = true,
192190 },
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
194216 .{
195217 .target = .{
196218 .cpu_arch = .aarch64_be,
......@@ -1182,6 +1204,18 @@ const test_targets = blk: {
11821204 },
11831205 },
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
11851219 .{
11861220 .target = .{
11871221 .cpu_arch = .x86_64,
......@@ -1335,16 +1369,15 @@ const test_targets = blk: {
13351369
13361370 // WASI Targets
13371371
1338 // TODO: lowerTry for pointers
1339 //.{
1340 // .target = .{
1341 // .cpu_arch = .wasm32,
1342 // .os_tag = .wasi,
1343 // .abi = .none,
1344 // },
1345 // .use_llvm = false,
1346 // .use_lld = false,
1347 //},
1372 .{
1373 .target = .{
1374 .cpu_arch = .wasm32,
1375 .os_tag = .wasi,
1376 .abi = .none,
1377 },
1378 .use_llvm = false,
1379 .use_lld = false,
1380 },
13481381 .{
13491382 .target = .{
13501383 .cpu_arch = .wasm32,
......@@ -1983,6 +2016,16 @@ pub fn addCliTests(b: *std.Build) *Step {
19832016 step.dependOn(&cleanup.step);
19842017 }
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
19862029 // Test Godbolt API
19872030 if (builtin.os.tag == .linux and builtin.cpu.arch == .x86_64) {
19882031 const tmp_path = b.makeTempPath();
......@@ -2260,7 +2303,7 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step {
22602303 continue;
22612304
22622305 // TODO get compiler-rt tests passing for self-hosted backends.
2263 if ((target.cpu.arch != .x86_64 or target.ofmt != .elf) and
2306 if (((target.cpu.arch != .x86_64 and target.cpu.arch != .aarch64) or target.ofmt == .coff) and
22642307 test_target.use_llvm == false and mem.eql(u8, options.name, "compiler-rt"))
22652308 continue;
22662309
......@@ -2328,10 +2371,10 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step {
23282371 } else "";
23292372 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
23332376 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, .{});
23352378 }
23362379
23372380 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");
33const io = std.io;
44const fs = std.fs;
55const process = std.process;
6const ChildProcess = std.process.Child;
76const Progress = std.Progress;
87const print = std.debug.print;
98const mem = std.mem;
tools/gen_stubs.zig+2-1
......@@ -310,7 +310,8 @@ pub fn main() !void {
310310 build_all_path, libc_so_path, @errorName(err),
311311 });
312312 };
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
315316 const parse: Parse = .{
316317 .arena = arena,
tools/incr-check.zig+24-39
......@@ -186,7 +186,7 @@ pub fn main() !void {
186186
187187 try child.spawn();
188188
189 var poller = std.io.poll(arena, Eval.StreamEnum, .{
189 var poller = std.Io.poll(arena, Eval.StreamEnum, .{
190190 .stdout = child.stdout.?,
191191 .stderr = child.stderr.?,
192192 });
......@@ -247,19 +247,15 @@ const Eval = struct {
247247
248248 fn check(eval: *Eval, poller: *Poller, update: Case.Update, prog_node: std.Progress.Node) !void {
249249 const arena = eval.arena;
250 const Header = std.zig.Server.Message.Header;
251 const stdout = poller.fifo(.stdout);
252 const stderr = poller.fifo(.stderr);
250 const stdout = poller.reader(.stdout);
251 const stderr = poller.reader(.stderr);
253252
254253 poll: while (true) {
255 while (stdout.readableLength() < @sizeOf(Header)) {
256 if (!(try poller.poll())) break :poll;
257 }
258 const header = stdout.reader().readStruct(Header) catch unreachable;
259 while (stdout.readableLength() < header.bytes_len) {
260 if (!(try poller.poll())) break :poll;
261 }
262 const body = stdout.readableSliceOfLen(header.bytes_len);
254 const Header = std.zig.Server.Message.Header;
255 while (stdout.buffered().len < @sizeOf(Header)) if (!try poller.poll()) break :poll;
256 const header = stdout.takeStruct(Header, .little) catch unreachable;
257 while (stdout.buffered().len < header.bytes_len) if (!try poller.poll()) break :poll;
258 const body = stdout.take(header.bytes_len) catch unreachable;
263259
264260 switch (header.tag) {
265261 .error_bundle => {
......@@ -277,8 +273,8 @@ const Eval = struct {
277273 .string_bytes = try arena.dupe(u8, string_bytes),
278274 .extra = extra_array,
279275 };
280 if (stderr.readableLength() > 0) {
281 const stderr_data = try stderr.toOwnedSlice();
276 if (stderr.bufferedLen() > 0) {
277 const stderr_data = try poller.toOwnedSlice(.stderr);
282278 if (eval.allow_stderr) {
283279 std.log.info("error_bundle included stderr:\n{s}", .{stderr_data});
284280 } else {
......@@ -289,15 +285,14 @@ const Eval = struct {
289285 try eval.checkErrorOutcome(update, result_error_bundle);
290286 }
291287 // This message indicates the end of the update.
292 stdout.discard(body.len);
293288 return;
294289 },
295290 .emit_digest => {
296291 const EbpHdr = std.zig.Server.Message.EmitDigest;
297292 const ebp_hdr = @as(*align(1) const EbpHdr, @ptrCast(body));
298293 _ = ebp_hdr;
299 if (stderr.readableLength() > 0) {
300 const stderr_data = try stderr.toOwnedSlice();
294 if (stderr.bufferedLen() > 0) {
295 const stderr_data = try poller.toOwnedSlice(.stderr);
301296 if (eval.allow_stderr) {
302297 std.log.info("emit_digest included stderr:\n{s}", .{stderr_data});
303298 } else {
......@@ -308,7 +303,6 @@ const Eval = struct {
308303 if (eval.target.backend == .sema) {
309304 try eval.checkSuccessOutcome(update, null, prog_node);
310305 // This message indicates the end of the update.
311 stdout.discard(body.len);
312306 }
313307
314308 const digest = body[@sizeOf(EbpHdr)..][0..Cache.bin_digest_len];
......@@ -323,21 +317,18 @@ const Eval = struct {
323317
324318 try eval.checkSuccessOutcome(update, bin_path, prog_node);
325319 // This message indicates the end of the update.
326 stdout.discard(body.len);
327320 },
328321 else => {
329322 // Ignore other messages.
330 stdout.discard(body.len);
331323 },
332324 }
333325 }
334326
335 if (stderr.readableLength() > 0) {
336 const stderr_data = try stderr.toOwnedSlice();
327 if (stderr.bufferedLen() > 0) {
337328 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() });
339330 } 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() });
341332 }
342333 }
343334
......@@ -537,25 +528,19 @@ const Eval = struct {
537528 fn end(eval: *Eval, poller: *Poller) !void {
538529 requestExit(eval.child, eval);
539530
540 const Header = std.zig.Server.Message.Header;
541 const stdout = poller.fifo(.stdout);
542 const stderr = poller.fifo(.stderr);
531 const stdout = poller.reader(.stdout);
532 const stderr = poller.reader(.stderr);
543533
544534 poll: while (true) {
545 while (stdout.readableLength() < @sizeOf(Header)) {
546 if (!(try poller.poll())) break :poll;
547 }
548 const header = stdout.reader().readStruct(Header) catch unreachable;
549 while (stdout.readableLength() < header.bytes_len) {
550 if (!(try poller.poll())) break :poll;
551 }
552 const body = stdout.readableSliceOfLen(header.bytes_len);
553 stdout.discard(body.len);
535 const Header = std.zig.Server.Message.Header;
536 while (stdout.buffered().len < @sizeOf(Header)) if (!try poller.poll()) break :poll;
537 const header = stdout.takeStruct(Header, .little) catch unreachable;
538 while (stdout.buffered().len < header.bytes_len) if (!try poller.poll()) break :poll;
539 stdout.toss(header.bytes_len);
554540 }
555541
556 if (stderr.readableLength() > 0) {
557 const stderr_data = try stderr.toOwnedSlice();
558 eval.fatal("unexpected stderr:\n{s}", .{stderr_data});
542 if (stderr.bufferedLen() > 0) {
543 eval.fatal("unexpected stderr:\n{s}", .{stderr.buffered()});
559544 }
560545 }
561546