authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-07-25 18:15:24-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-07-25 18:15:24-07:00
log45a35d448e85351756fe18e901748c4446a1b56a
tree21d079e9d889054e1697f0f18c18021aa08c5c37
parent8c4482ed78fb651c0288f0cd2bdaf328564c6a49
parent733b2082565a86daac6f2b22a1a27f0b60621b4e

Merge remote-tracking branch 'origin/zstd' into wrangle-writer-buffering


24 files changed, 1062 insertions(+), 489 deletions(-)

lib/compiler/std-docs.zig+3-2
...@@ -348,8 +348,9 @@ fn buildWasmBinary(...@@ -348,8 +348,9 @@ fn buildWasmBinary(
348 };348 };
349 }349 }
350350
351 if (poller.reader(.stderr).buffer.len > 0) {351 const stderr = poller.reader(.stderr);
352 std.debug.print("{s}", .{poller.reader(.stderr).buffered()});352 if (stderr.bufferedLen() > 0) {
353 std.debug.print("{s}", .{stderr.buffered()});
353 }354 }
354355
355 // Send EOF to stdin.356 // Send EOF to stdin.
lib/init/build.zig-1
...@@ -1,4 +1,3 @@...@@ -1,4 +1,3 @@
1//! Use `zig init --strip` next time to generate a project without comments.
2const std = @import("std");1const std = @import("std");
32
4// Although this function looks imperative, it does not perform the build3// Although this function looks imperative, it does not perform the build
lib/std/Io/DeprecatedReader.zig+2-2
...@@ -373,11 +373,11 @@ pub fn discard(self: Self) anyerror!u64 {...@@ -373,11 +373,11 @@ pub fn discard(self: Self) anyerror!u64 {
373}373}
374374
375/// Helper for bridging to the new `Reader` API while upgrading.375/// Helper for bridging to the new `Reader` API while upgrading.
376pub fn adaptToNewApi(self: *const Self) Adapter {376pub fn adaptToNewApi(self: *const Self, buffer: []u8) Adapter {
377 return .{377 return .{
378 .derp_reader = self.*,378 .derp_reader = self.*,
379 .new_interface = .{379 .new_interface = .{
380 .buffer = &.{},380 .buffer = buffer,
381 .vtable = &.{ .stream = Adapter.stream },381 .vtable = &.{ .stream = Adapter.stream },
382 .seek = 0,382 .seek = 0,
383 .end = 0,383 .end = 0,
lib/std/Io/Reader.zig+28-2
...@@ -185,6 +185,32 @@ pub fn streamExact64(r: *Reader, w: *Writer, n: u64) StreamError!void {...@@ -185,6 +185,32 @@ pub fn streamExact64(r: *Reader, w: *Writer, n: u64) StreamError!void {
185 while (remaining != 0) remaining -= try r.stream(w, .limited64(remaining));185 while (remaining != 0) remaining -= try r.stream(w, .limited64(remaining));
186}186}
187187
188/// "Pump" exactly `n` bytes from the reader to the writer.
189///
190/// When draining `w`, ensures that at least `preserve_len` bytes remain
191/// buffered.
192///
193/// Asserts `Writer.buffer` capacity exceeds `preserve_len`.
194pub fn streamExactPreserve(r: *Reader, w: *Writer, preserve_len: usize, n: usize) StreamError!void {
195 if (w.end + n <= w.buffer.len) {
196 @branchHint(.likely);
197 return streamExact(r, w, n);
198 }
199 // If `n` is large, we can ignore `preserve_len` up to a point.
200 var remaining = n;
201 while (remaining > preserve_len) {
202 assert(remaining != 0);
203 remaining -= try r.stream(w, .limited(remaining - preserve_len));
204 if (w.end + remaining <= w.buffer.len) return streamExact(r, w, remaining);
205 }
206 // All the next bytes received must be preserved.
207 if (preserve_len < w.end) {
208 @memmove(w.buffer[0..preserve_len], w.buffer[w.end - preserve_len ..][0..preserve_len]);
209 w.end = preserve_len;
210 }
211 return streamExact(r, w, remaining);
212}
213
188/// "Pump" data from the reader to the writer, handling `error.EndOfStream` as214/// "Pump" data from the reader to the writer, handling `error.EndOfStream` as
189/// a success case.215/// a success case.
190///216///
...@@ -240,7 +266,7 @@ pub fn allocRemaining(r: *Reader, gpa: Allocator, limit: Limit) LimitedAllocErro...@@ -240,7 +266,7 @@ pub fn allocRemaining(r: *Reader, gpa: Allocator, limit: Limit) LimitedAllocErro
240/// such case, the next byte that would be read will be the first one to exceed266/// such case, the next byte that would be read will be the first one to exceed
241/// `limit`, and all preceeding bytes have been appended to `list`.267/// `limit`, and all preceeding bytes have been appended to `list`.
242///268///
243/// Asserts `buffer` has nonzero capacity.269/// If `limit` is not `Limit.unlimited`, asserts `buffer` has nonzero capacity.
244///270///
245/// See also:271/// See also:
246/// * `allocRemaining`272/// * `allocRemaining`
...@@ -251,7 +277,7 @@ pub fn appendRemaining(...@@ -251,7 +277,7 @@ pub fn appendRemaining(
251 list: *std.ArrayListAlignedUnmanaged(u8, alignment),277 list: *std.ArrayListAlignedUnmanaged(u8, alignment),
252 limit: Limit,278 limit: Limit,
253) LimitedAllocError!void {279) LimitedAllocError!void {
254 assert(r.buffer.len != 0); // Needed to detect limit exceeded without losing data.280 if (limit != .unlimited) assert(r.buffer.len != 0); // Needed to detect limit exceeded without losing data.
255 const buffer_contents = r.buffer[r.seek..r.end];281 const buffer_contents = r.buffer[r.seek..r.end];
256 const copy_len = limit.minInt(buffer_contents.len);282 const copy_len = limit.minInt(buffer_contents.len);
257 try list.appendSlice(gpa, r.buffer[0..copy_len]);283 try list.appendSlice(gpa, r.buffer[0..copy_len]);
lib/std/Io/Writer.zig+70-23
...@@ -256,10 +256,10 @@ test "fixed buffer flush" {...@@ -256,10 +256,10 @@ test "fixed buffer flush" {
256 try testing.expectEqual(10, buffer[0]);256 try testing.expectEqual(10, buffer[0]);
257}257}
258258
259/// Calls `VTable.drain` but hides the last `preserve_length` bytes from the259/// Calls `VTable.drain` but hides the last `preserve_len` bytes from the
260/// implementation, keeping them buffered.260/// implementation, keeping them buffered.
261pub fn drainPreserve(w: *Writer, preserve_length: usize) Error!void {261pub fn drainPreserve(w: *Writer, preserve_len: usize) Error!void {
262 const temp_end = w.end -| preserve_length;262 const temp_end = w.end -| preserve_len;
263 const preserved = w.buffer[temp_end..w.end];263 const preserved = w.buffer[temp_end..w.end];
264 w.end = temp_end;264 w.end = temp_end;
265 defer w.end += preserved.len;265 defer w.end += preserved.len;
...@@ -310,24 +310,38 @@ pub fn writableSliceGreedy(w: *Writer, minimum_length: usize) Error![]u8 {...@@ -310,24 +310,38 @@ pub fn writableSliceGreedy(w: *Writer, minimum_length: usize) Error![]u8 {
310}310}
311311
312/// Asserts the provided buffer has total capacity enough for `minimum_length`312/// Asserts the provided buffer has total capacity enough for `minimum_length`
313/// and `preserve_length` combined.313/// and `preserve_len` combined.
314///314///
315/// Does not `advance` the buffer end position.315/// Does not `advance` the buffer end position.
316///316///
317/// When draining the buffer, ensures that at least `preserve_length` bytes317/// When draining the buffer, ensures that at least `preserve_len` bytes
318/// remain buffered.318/// remain buffered.
319///319///
320/// If `preserve_length` is zero, this is equivalent to `writableSliceGreedy`.320/// If `preserve_len` is zero, this is equivalent to `writableSliceGreedy`.
321pub fn writableSliceGreedyPreserve(w: *Writer, preserve_length: usize, minimum_length: usize) Error![]u8 {321pub fn writableSliceGreedyPreserve(w: *Writer, preserve_len: usize, minimum_length: usize) Error![]u8 {
322 assert(w.buffer.len >= preserve_length + minimum_length);322 assert(w.buffer.len >= preserve_len + minimum_length);
323 while (w.buffer.len - w.end < minimum_length) {323 while (w.buffer.len - w.end < minimum_length) {
324 try drainPreserve(w, preserve_length);324 try drainPreserve(w, preserve_len);
325 } else {325 } else {
326 @branchHint(.likely);326 @branchHint(.likely);
327 return w.buffer[w.end..];327 return w.buffer[w.end..];
328 }328 }
329}329}
330330
331/// Asserts the provided buffer has total capacity enough for `len`.
332///
333/// Advances the buffer end position by `len`.
334///
335/// When draining the buffer, ensures that at least `preserve_len` bytes
336/// remain buffered.
337///
338/// If `preserve_len` is zero, this is equivalent to `writableSlice`.
339pub fn writableSlicePreserve(w: *Writer, preserve_len: usize, len: usize) Error![]u8 {
340 const big_slice = try w.writableSliceGreedyPreserve(preserve_len, len);
341 advance(w, len);
342 return big_slice[0..len];
343}
344
331pub const WritableVectorIterator = struct {345pub const WritableVectorIterator = struct {
332 first: []u8,346 first: []u8,
333 middle: []const []u8 = &.{},347 middle: []const []u8 = &.{},
...@@ -523,16 +537,16 @@ pub fn write(w: *Writer, bytes: []const u8) Error!usize {...@@ -523,16 +537,16 @@ pub fn write(w: *Writer, bytes: []const u8) Error!usize {
523 return w.vtable.drain(w, &.{bytes}, 1);537 return w.vtable.drain(w, &.{bytes}, 1);
524}538}
525539
526/// Asserts `buffer` capacity exceeds `preserve_length`.540/// Asserts `buffer` capacity exceeds `preserve_len`.
527pub fn writePreserve(w: *Writer, preserve_length: usize, bytes: []const u8) Error!usize {541pub fn writePreserve(w: *Writer, preserve_len: usize, bytes: []const u8) Error!usize {
528 assert(preserve_length <= w.buffer.len);542 assert(preserve_len <= w.buffer.len);
529 if (w.end + bytes.len <= w.buffer.len) {543 if (w.end + bytes.len <= w.buffer.len) {
530 @branchHint(.likely);544 @branchHint(.likely);
531 @memcpy(w.buffer[w.end..][0..bytes.len], bytes);545 @memcpy(w.buffer[w.end..][0..bytes.len], bytes);
532 w.end += bytes.len;546 w.end += bytes.len;
533 return bytes.len;547 return bytes.len;
534 }548 }
535 const temp_end = w.end -| preserve_length;549 const temp_end = w.end -| preserve_len;
536 const preserved = w.buffer[temp_end..w.end];550 const preserved = w.buffer[temp_end..w.end];
537 w.end = temp_end;551 w.end = temp_end;
538 defer w.end += preserved.len;552 defer w.end += preserved.len;
...@@ -552,13 +566,13 @@ pub fn writeAll(w: *Writer, bytes: []const u8) Error!void {...@@ -552,13 +566,13 @@ pub fn writeAll(w: *Writer, bytes: []const u8) Error!void {
552/// Calls `drain` as many times as necessary such that all of `bytes` are566/// Calls `drain` as many times as necessary such that all of `bytes` are
553/// transferred.567/// transferred.
554///568///
555/// When draining the buffer, ensures that at least `preserve_length` bytes569/// When draining the buffer, ensures that at least `preserve_len` bytes
556/// remain buffered.570/// remain buffered.
557///571///
558/// Asserts `buffer` capacity exceeds `preserve_length`.572/// Asserts `buffer` capacity exceeds `preserve_len`.
559pub fn writeAllPreserve(w: *Writer, preserve_length: usize, bytes: []const u8) Error!void {573pub fn writeAllPreserve(w: *Writer, preserve_len: usize, bytes: []const u8) Error!void {
560 var index: usize = 0;574 var index: usize = 0;
561 while (index < bytes.len) index += try w.writePreserve(preserve_length, bytes[index..]);575 while (index < bytes.len) index += try w.writePreserve(preserve_len, bytes[index..]);
562}576}
563577
564/// Renders fmt string with args, calling `writer` with slices of bytes.578/// Renders fmt string with args, calling `writer` with slices of bytes.
...@@ -761,11 +775,11 @@ pub fn writeByte(w: *Writer, byte: u8) Error!void {...@@ -761,11 +775,11 @@ pub fn writeByte(w: *Writer, byte: u8) Error!void {
761 }775 }
762}776}
763777
764/// When draining the buffer, ensures that at least `preserve_length` bytes778/// When draining the buffer, ensures that at least `preserve_len` bytes
765/// remain buffered.779/// remain buffered.
766pub fn writeBytePreserve(w: *Writer, preserve_length: usize, byte: u8) Error!void {780pub fn writeBytePreserve(w: *Writer, preserve_len: usize, byte: u8) Error!void {
767 while (w.buffer.len - w.end == 0) {781 while (w.buffer.len - w.end == 0) {
768 try drainPreserve(w, preserve_length);782 try drainPreserve(w, preserve_len);
769 } else {783 } else {
770 @branchHint(.likely);784 @branchHint(.likely);
771 w.buffer[w.end] = byte;785 w.buffer[w.end] = byte;
...@@ -788,10 +802,42 @@ test splatByteAll {...@@ -788,10 +802,42 @@ test splatByteAll {
788 try testing.expectEqualStrings("7" ** 45, aw.writer.buffered());802 try testing.expectEqualStrings("7" ** 45, aw.writer.buffered());
789}803}
790804
805pub fn splatBytePreserve(w: *Writer, preserve_len: usize, byte: u8, n: usize) Error!void {
806 const new_end = w.end + n;
807 if (new_end <= w.buffer.len) {
808 @memset(w.buffer[w.end..][0..n], byte);
809 w.end = new_end;
810 return;
811 }
812 // If `n` is large, we can ignore `preserve_len` up to a point.
813 var remaining = n;
814 while (remaining > preserve_len) {
815 assert(remaining != 0);
816 remaining -= try splatByte(w, byte, remaining - preserve_len);
817 if (w.end + remaining <= w.buffer.len) {
818 @memset(w.buffer[w.end..][0..remaining], byte);
819 w.end += remaining;
820 return;
821 }
822 }
823 // All the next bytes received must be preserved.
824 if (preserve_len < w.end) {
825 @memmove(w.buffer[0..preserve_len], w.buffer[w.end - preserve_len ..][0..preserve_len]);
826 w.end = preserve_len;
827 }
828 while (remaining > 0) remaining -= try w.splatByte(byte, remaining);
829}
830
791/// Writes the same byte many times, allowing short writes.831/// Writes the same byte many times, allowing short writes.
792///832///
793/// Does maximum of one underlying `VTable.drain`.833/// Does maximum of one underlying `VTable.drain`.
794pub fn splatByte(w: *Writer, byte: u8, n: usize) Error!usize {834pub fn splatByte(w: *Writer, byte: u8, n: usize) Error!usize {
835 if (w.end + n <= w.buffer.len) {
836 @branchHint(.likely);
837 @memset(w.buffer[w.end..][0..n], byte);
838 w.end += n;
839 return n;
840 }
795 return writeSplat(w, &.{&.{byte}}, n);841 return writeSplat(w, &.{&.{byte}}, n);
796}842}
797843
...@@ -801,9 +847,10 @@ pub fn splatBytesAll(w: *Writer, bytes: []const u8, splat: usize) Error!void {...@@ -801,9 +847,10 @@ pub fn splatBytesAll(w: *Writer, bytes: []const u8, splat: usize) Error!void {
801 var remaining_bytes: usize = bytes.len * splat;847 var remaining_bytes: usize = bytes.len * splat;
802 remaining_bytes -= try w.splatBytes(bytes, splat);848 remaining_bytes -= try w.splatBytes(bytes, splat);
803 while (remaining_bytes > 0) {849 while (remaining_bytes > 0) {
804 const leftover = remaining_bytes % bytes.len;850 const leftover_splat = remaining_bytes / bytes.len;
805 const buffers: [2][]const u8 = .{ bytes[bytes.len - leftover ..], bytes };851 const leftover_bytes = remaining_bytes % bytes.len;
806 remaining_bytes -= try w.writeSplat(&buffers, splat);852 const buffers: [2][]const u8 = .{ bytes[bytes.len - leftover_bytes ..], bytes };
853 remaining_bytes -= try w.writeSplat(&buffers, leftover_splat);
807 }854 }
808}855}
809856
lib/std/compress/xz.zig+30-3
...@@ -47,7 +47,7 @@ pub fn Decompress(comptime ReaderType: type) type {...@@ -47,7 +47,7 @@ pub fn Decompress(comptime ReaderType: type) type {
4747
48 var check: Check = undefined;48 var check: Check = undefined;
49 const hash_a = blk: {49 const hash_a = blk: {
50 var hasher = std.compress.hashedReader(source, Crc32.init());50 var hasher = hashedReader(source, Crc32.init());
51 try readStreamFlags(hasher.reader(), &check);51 try readStreamFlags(hasher.reader(), &check);
52 break :blk hasher.hasher.final();52 break :blk hasher.hasher.final();
53 };53 };
...@@ -80,7 +80,7 @@ pub fn Decompress(comptime ReaderType: type) type {...@@ -80,7 +80,7 @@ pub fn Decompress(comptime ReaderType: type) type {
80 return r;80 return r;
8181
82 const index_size = blk: {82 const index_size = blk: {
83 var hasher = std.compress.hashedReader(self.in_reader, Crc32.init());83 var hasher = hashedReader(self.in_reader, Crc32.init());
84 hasher.hasher.update(&[1]u8{0x00});84 hasher.hasher.update(&[1]u8{0x00});
8585
86 var counter = std.io.countingReader(hasher.reader());86 var counter = std.io.countingReader(hasher.reader());
...@@ -115,7 +115,7 @@ pub fn Decompress(comptime ReaderType: type) type {...@@ -115,7 +115,7 @@ pub fn Decompress(comptime ReaderType: type) type {
115 const hash_a = try self.in_reader.readInt(u32, .little);115 const hash_a = try self.in_reader.readInt(u32, .little);
116116
117 const hash_b = blk: {117 const hash_b = blk: {
118 var hasher = std.compress.hashedReader(self.in_reader, Crc32.init());118 var hasher = hashedReader(self.in_reader, Crc32.init());
119 const hashed_reader = hasher.reader();119 const hashed_reader = hasher.reader();
120120
121 const backward_size = (@as(u64, try hashed_reader.readInt(u32, .little)) + 1) * 4;121 const backward_size = (@as(u64, try hashed_reader.readInt(u32, .little)) + 1) * 4;
...@@ -140,6 +140,33 @@ pub fn Decompress(comptime ReaderType: type) type {...@@ -140,6 +140,33 @@ pub fn Decompress(comptime ReaderType: type) type {
140 };140 };
141}141}
142142
143pub fn HashedReader(ReaderType: type, HasherType: type) type {
144 return struct {
145 child_reader: ReaderType,
146 hasher: HasherType,
147
148 pub const Error = ReaderType.Error;
149 pub const Reader = std.io.GenericReader(*@This(), Error, read);
150
151 pub fn read(self: *@This(), buf: []u8) Error!usize {
152 const amt = try self.child_reader.read(buf);
153 self.hasher.update(buf[0..amt]);
154 return amt;
155 }
156
157 pub fn reader(self: *@This()) Reader {
158 return .{ .context = self };
159 }
160 };
161}
162
163pub fn hashedReader(
164 reader: anytype,
165 hasher: anytype,
166) HashedReader(@TypeOf(reader), @TypeOf(hasher)) {
167 return .{ .child_reader = reader, .hasher = hasher };
168}
169
143test {170test {
144 _ = @import("xz/test.zig");171 _ = @import("xz/test.zig");
145}172}
lib/std/compress/xz/block.zig+1-1
...@@ -91,7 +91,7 @@ pub fn Decoder(comptime ReaderType: type) type {...@@ -91,7 +91,7 @@ pub fn Decoder(comptime ReaderType: type) type {
9191
92 // Block Header92 // Block Header
93 {93 {
94 var header_hasher = std.compress.hashedReader(block_reader, Crc32.init());94 var header_hasher = xz.hashedReader(block_reader, Crc32.init());
95 const header_reader = header_hasher.reader();95 const header_reader = header_hasher.reader();
9696
97 const header_size = @as(u64, try header_reader.readByte()) * 4;97 const header_size = @as(u64, try header_reader.readByte()) * 4;
lib/std/compress/zstd.zig+4-5
...@@ -1,12 +1,11 @@...@@ -1,12 +1,11 @@
1const std = @import("../std.zig");1const std = @import("../std.zig");
2const assert = std.debug.assert;2const assert = std.debug.assert;
33
4pub const Decompress = @import("zstd/Decompress.zig");
5
4/// Recommended amount by the standard. Lower than this may result in inability6/// Recommended amount by the standard. Lower than this may result in inability
5/// to decompress common streams.7/// to decompress common streams.
6pub const default_window_len = 8 * 1024 * 1024;8pub const default_window_len = 8 * 1024 * 1024;
7
8pub const Decompress = @import("zstd/Decompress.zig");
9
10pub const block_size_max = 1 << 17;9pub const block_size_max = 1 << 17;
1110
12pub const literals_length_default_distribution = [36]i16{11pub const literals_length_default_distribution = [36]i16{
...@@ -85,7 +84,7 @@ fn testDecompress(gpa: std.mem.Allocator, compressed: []const u8) ![]u8 {...@@ -85,7 +84,7 @@ fn testDecompress(gpa: std.mem.Allocator, compressed: []const u8) ![]u8 {
8584
86 var in: std.io.Reader = .fixed(compressed);85 var in: std.io.Reader = .fixed(compressed);
87 var zstd_stream: Decompress = .init(&in, &.{}, .{});86 var zstd_stream: Decompress = .init(&in, &.{}, .{});
88 try zstd_stream.interface.appendRemaining(gpa, null, &out, .unlimited);87 try zstd_stream.reader.appendRemaining(gpa, null, &out, .unlimited);
8988
90 return out.toOwnedSlice(gpa);89 return out.toOwnedSlice(gpa);
91}90}
...@@ -108,7 +107,7 @@ fn testExpectDecompressError(err: anyerror, compressed: []const u8) !void {...@@ -108,7 +107,7 @@ fn testExpectDecompressError(err: anyerror, compressed: []const u8) !void {
108 var zstd_stream: Decompress = .init(&in, &.{}, .{});107 var zstd_stream: Decompress = .init(&in, &.{}, .{});
109 try std.testing.expectError(108 try std.testing.expectError(
110 error.ReadFailed,109 error.ReadFailed,
111 zstd_stream.interface.appendRemaining(gpa, null, &out, .unlimited),110 zstd_stream.reader.appendRemaining(gpa, null, &out, .unlimited),
112 );111 );
113 try std.testing.expectError(err, zstd_stream.err orelse {});112 try std.testing.expectError(err, zstd_stream.err orelse {});
114}113}
lib/std/compress/zstd/Decompress.zig+69-68
...@@ -10,6 +10,7 @@ input: *Reader,...@@ -10,6 +10,7 @@ input: *Reader,
10reader: Reader,10reader: Reader,
11state: State,11state: State,
12verify_checksum: bool,12verify_checksum: bool,
13window_len: u32,
13err: ?Error = null,14err: ?Error = null,
1415
15const State = union(enum) {16const State = union(enum) {
...@@ -22,11 +23,16 @@ const State = union(enum) {...@@ -22,11 +23,16 @@ const State = union(enum) {
22 frame: Frame,23 frame: Frame,
23 checksum: ?u32,24 checksum: ?u32,
24 decompressed_size: usize,25 decompressed_size: usize,
26 decode: Frame.Zstandard.Decode,
25 };27 };
26};28};
2729
28pub const Options = struct {30pub const Options = struct {
29 verify_checksum: bool = true,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 /// Affects the minimum capacity of the provided buffer.
35 window_len: u32 = zstd.default_window_len,
30};36};
3137
32pub const Error = error{38pub const Error = error{
...@@ -63,11 +69,14 @@ pub const Error = error{...@@ -63,11 +69,14 @@ pub const Error = error{
63 WindowSizeUnknown,69 WindowSizeUnknown,
64};70};
6571
72/// If buffer that is written to is not big enough, some streams will fail with
73/// `error.OutputBufferUndersize`. A safe value is `zstd.default_window_len * 2`.
66pub fn init(input: *Reader, buffer: []u8, options: Options) Decompress {74pub fn init(input: *Reader, buffer: []u8, options: Options) Decompress {
67 return .{75 return .{
68 .input = input,76 .input = input,
69 .state = .new_frame,77 .state = .new_frame,
70 .verify_checksum = options.verify_checksum,78 .verify_checksum = options.verify_checksum,
79 .window_len = options.window_len,
71 .reader = .{80 .reader = .{
72 .vtable = &.{ .stream = stream },81 .vtable = &.{ .stream = stream },
73 .buffer = buffer,82 .buffer = buffer,
...@@ -130,6 +139,7 @@ fn initFrame(d: *Decompress, window_size_max: usize, magic: Frame.Magic) !void {...@@ -130,6 +139,7 @@ fn initFrame(d: *Decompress, window_size_max: usize, magic: Frame.Magic) !void {
130 .frame = try Frame.init(header, window_size_max, d.verify_checksum),139 .frame = try Frame.init(header, window_size_max, d.verify_checksum),
131 .checksum = null,140 .checksum = null,
132 .decompressed_size = 0,141 .decompressed_size = 0,
142 .decode = .init,
133 } };143 } };
134 },144 },
135 .skippable => {145 .skippable => {
...@@ -139,11 +149,11 @@ fn initFrame(d: *Decompress, window_size_max: usize, magic: Frame.Magic) !void {...@@ -139,11 +149,11 @@ fn initFrame(d: *Decompress, window_size_max: usize, magic: Frame.Magic) !void {
139 }149 }
140}150}
141151
142fn readInFrame(d: *Decompress, bw: *Writer, limit: Limit, state: *State.InFrame) !usize {152fn readInFrame(d: *Decompress, w: *Writer, limit: Limit, state: *State.InFrame) !usize {
143 const in = d.input;153 const in = d.input;
154 const window_len = d.window_len;
144155
145 const header_bytes = try in.takeArray(3);156 const block_header = try in.takeStruct(Frame.Zstandard.Block.Header, .little);
146 const block_header: Frame.Zstandard.Block.Header = @bitCast(header_bytes.*);
147 const block_size = block_header.size;157 const block_size = block_header.size;
148 const frame_block_size_max = state.frame.block_size_max;158 const frame_block_size_max = state.frame.block_size_max;
149 if (frame_block_size_max < block_size) return error.BlockOversize;159 if (frame_block_size_max < block_size) return error.BlockOversize;
...@@ -151,49 +161,47 @@ fn readInFrame(d: *Decompress, bw: *Writer, limit: Limit, state: *State.InFrame)...@@ -151,49 +161,47 @@ fn readInFrame(d: *Decompress, bw: *Writer, limit: Limit, state: *State.InFrame)
151 var bytes_written: usize = 0;161 var bytes_written: usize = 0;
152 switch (block_header.type) {162 switch (block_header.type) {
153 .raw => {163 .raw => {
154 try in.readAll(bw, .limited(block_size));164 try in.streamExactPreserve(w, window_len, block_size);
155 bytes_written = block_size;165 bytes_written = block_size;
156 },166 },
157 .rle => {167 .rle => {
158 const byte = try in.takeByte();168 const byte = try in.takeByte();
159 try bw.splatByteAll(byte, block_size);169 try w.splatBytePreserve(window_len, byte, block_size);
160 bytes_written = block_size;170 bytes_written = block_size;
161 },171 },
162 .compressed => {172 .compressed => {
163 var literal_fse_buffer: [zstd.table_size_max.literal]Table.Fse = undefined;
164 var match_fse_buffer: [zstd.table_size_max.match]Table.Fse = undefined;
165 var offset_fse_buffer: [zstd.table_size_max.offset]Table.Fse = undefined;
166 var literals_buffer: [zstd.block_size_max]u8 = undefined;173 var literals_buffer: [zstd.block_size_max]u8 = undefined;
167 var sequence_buffer: [zstd.block_size_max]u8 = undefined;174 var sequence_buffer: [zstd.block_size_max]u8 = undefined;
168 var decode: Frame.Zstandard.Decode = .init(&literal_fse_buffer, &match_fse_buffer, &offset_fse_buffer);
169 var remaining: Limit = .limited(block_size);175 var remaining: Limit = .limited(block_size);
170 const literals = try LiteralsSection.decode(in, &remaining, &literals_buffer);176 const literals = try LiteralsSection.decode(in, &remaining, &literals_buffer);
171 const sequences_header = try SequencesSection.Header.decode(in, &remaining);177 const sequences_header = try SequencesSection.Header.decode(in, &remaining);
172178
179 const decode = &state.decode;
173 try decode.prepare(in, &remaining, literals, sequences_header);180 try decode.prepare(in, &remaining, literals, sequences_header);
174181
175 {182 {
176 if (sequence_buffer.len < @intFromEnum(remaining))183 if (sequence_buffer.len < @intFromEnum(remaining))
177 return error.SequenceBufferUndersize;184 return error.SequenceBufferUndersize;
178 const seq_slice = remaining.slice(&sequence_buffer);185 const seq_slice = remaining.slice(&sequence_buffer);
179 try in.readSlice(seq_slice);186 try in.readSliceAll(seq_slice);
180 var bit_stream = try ReverseBitReader.init(seq_slice);187 var bit_stream = try ReverseBitReader.init(seq_slice);
181188
182 if (sequences_header.sequence_count > 0) {189 if (sequences_header.sequence_count > 0) {
183 try decode.readInitialFseState(&bit_stream);190 try decode.readInitialFseState(&bit_stream);
184191
185 // Ensures the following calls to `decodeSequence` will not flush.192 // Ensures the following calls to `decodeSequence` will not flush.
186 if (frame_block_size_max > bw.buffer.len) return error.OutputBufferUndersize;193 if (window_len + frame_block_size_max > w.buffer.len) return error.OutputBufferUndersize;
187 const dest = (try bw.writableSliceGreedy(frame_block_size_max))[0..frame_block_size_max];194 const dest = (try w.writableSliceGreedyPreserve(window_len, frame_block_size_max))[0..frame_block_size_max];
195 const write_pos = dest.ptr - w.buffer.ptr;
188 for (0..sequences_header.sequence_count - 1) |_| {196 for (0..sequences_header.sequence_count - 1) |_| {
189 bytes_written += try decode.decodeSequence(dest, bytes_written, &bit_stream);197 bytes_written += try decode.decodeSequence(w.buffer, write_pos + bytes_written, &bit_stream);
190 try decode.updateState(.literal, &bit_stream);198 try decode.updateState(.literal, &bit_stream);
191 try decode.updateState(.match, &bit_stream);199 try decode.updateState(.match, &bit_stream);
192 try decode.updateState(.offset, &bit_stream);200 try decode.updateState(.offset, &bit_stream);
193 }201 }
194 bytes_written += try decode.decodeSequence(dest, bytes_written, &bit_stream);202 bytes_written += try decode.decodeSequence(w.buffer, write_pos + bytes_written, &bit_stream);
195 if (bytes_written > dest.len) return error.MalformedSequence;203 if (bytes_written > dest.len) return error.MalformedSequence;
196 bw.advance(bytes_written);204 w.advance(bytes_written);
197 }205 }
198206
199 if (!bit_stream.isEmpty()) {207 if (!bit_stream.isEmpty()) {
...@@ -203,7 +211,7 @@ fn readInFrame(d: *Decompress, bw: *Writer, limit: Limit, state: *State.InFrame)...@@ -203,7 +211,7 @@ fn readInFrame(d: *Decompress, bw: *Writer, limit: Limit, state: *State.InFrame)
203211
204 if (decode.literal_written_count < literals.header.regenerated_size) {212 if (decode.literal_written_count < literals.header.regenerated_size) {
205 const len = literals.header.regenerated_size - decode.literal_written_count;213 const len = literals.header.regenerated_size - decode.literal_written_count;
206 try decode.decodeLiterals(bw, len);214 try decode.decodeLiterals(w, len);
207 decode.literal_written_count += len;215 decode.literal_written_count += len;
208 bytes_written += len;216 bytes_written += len;
209 }217 }
...@@ -216,11 +224,6 @@ fn readInFrame(d: *Decompress, bw: *Writer, limit: Limit, state: *State.InFrame)...@@ -216,11 +224,6 @@ fn readInFrame(d: *Decompress, bw: *Writer, limit: Limit, state: *State.InFrame)
216 }224 }
217225
218 if (bytes_written > frame_block_size_max) return error.BlockOversize;226 if (bytes_written > frame_block_size_max) return error.BlockOversize;
219
220 state.decompressed_size += bytes_written;
221 if (state.frame.content_size) |size| {
222 if (state.decompressed_size > size) return error.MalformedFrame;
223 }
224 },227 },
225 .reserved => return error.ReservedBlock,228 .reserved => return error.ReservedBlock,
226 }229 }
...@@ -232,6 +235,8 @@ fn readInFrame(d: *Decompress, bw: *Writer, limit: Limit, state: *State.InFrame)...@@ -232,6 +235,8 @@ fn readInFrame(d: *Decompress, bw: *Writer, limit: Limit, state: *State.InFrame)
232 }235 }
233 }236 }
234237
238 state.decompressed_size += bytes_written;
239
235 if (block_header.last) {240 if (block_header.last) {
236 if (state.frame.has_checksum) {241 if (state.frame.has_checksum) {
237 const expected_checksum = try in.takeInt(u32, .little);242 const expected_checksum = try in.takeInt(u32, .little);
...@@ -246,6 +251,8 @@ fn readInFrame(d: *Decompress, bw: *Writer, limit: Limit, state: *State.InFrame)...@@ -246,6 +251,8 @@ fn readInFrame(d: *Decompress, bw: *Writer, limit: Limit, state: *State.InFrame)
246 }251 }
247 }252 }
248 d.state = .new_frame;253 d.state = .new_frame;
254 } else if (state.frame.content_size) |content_size| {
255 if (state.decompressed_size > content_size) return error.MalformedFrame;
249 }256 }
250257
251 return bytes_written;258 return bytes_written;
...@@ -367,9 +374,9 @@ pub const Frame = struct {...@@ -367,9 +374,9 @@ pub const Frame = struct {
367 match: StateData(9),374 match: StateData(9),
368 literal: StateData(9),375 literal: StateData(9),
369376
370 offset_fse_buffer: []Table.Fse,377 literal_fse_buffer: [zstd.table_size_max.literal]Table.Fse,
371 match_fse_buffer: []Table.Fse,378 match_fse_buffer: [zstd.table_size_max.match]Table.Fse,
372 literal_fse_buffer: []Table.Fse,379 offset_fse_buffer: [zstd.table_size_max.offset]Table.Fse,
373380
374 fse_tables_undefined: bool,381 fse_tables_undefined: bool,
375382
...@@ -391,36 +398,30 @@ pub const Frame = struct {...@@ -391,36 +398,30 @@ pub const Frame = struct {
391 };398 };
392 }399 }
393400
394 pub fn init(401 const init: Decode = .{
395 literal_fse_buffer: []Table.Fse,402 .repeat_offsets = .{
396 match_fse_buffer: []Table.Fse,403 zstd.start_repeated_offset_1,
397 offset_fse_buffer: []Table.Fse,404 zstd.start_repeated_offset_2,
398 ) Decode {405 zstd.start_repeated_offset_3,
399 return .{406 },
400 .repeat_offsets = .{
401 zstd.start_repeated_offset_1,
402 zstd.start_repeated_offset_2,
403 zstd.start_repeated_offset_3,
404 },
405407
406 .offset = undefined,408 .offset = undefined,
407 .match = undefined,409 .match = undefined,
408 .literal = undefined,410 .literal = undefined,
409411
410 .literal_fse_buffer = literal_fse_buffer,412 .literal_fse_buffer = undefined,
411 .match_fse_buffer = match_fse_buffer,413 .match_fse_buffer = undefined,
412 .offset_fse_buffer = offset_fse_buffer,414 .offset_fse_buffer = undefined,
413415
414 .fse_tables_undefined = true,416 .fse_tables_undefined = true,
415417
416 .literal_written_count = 0,418 .literal_written_count = 0,
417 .literal_header = undefined,419 .literal_header = undefined,
418 .literal_streams = undefined,420 .literal_streams = undefined,
419 .literal_stream_reader = undefined,421 .literal_stream_reader = undefined,
420 .literal_stream_index = undefined,422 .literal_stream_index = undefined,
421 .huffman_tree = null,423 .huffman_tree = null,
422 };424 };
423 }
424425
425 pub const PrepareError = error{426 pub const PrepareError = error{
426 /// the (reversed) literal bitstream's first byte does not have any bits set427 /// the (reversed) literal bitstream's first byte does not have any bits set
...@@ -502,12 +503,12 @@ pub const Frame = struct {...@@ -502,12 +503,12 @@ pub const Frame = struct {
502 return self.repeat_offsets[0];503 return self.repeat_offsets[0];
503 }504 }
504505
505 const DataType = enum { offset, match, literal };506 const WhichFse = enum { offset, match, literal };
506507
507 /// TODO: don't use `@field`508 /// TODO: don't use `@field`
508 fn updateState(509 fn updateState(
509 self: *Decode,510 self: *Decode,
510 comptime choice: DataType,511 comptime choice: WhichFse,
511 bit_reader: *ReverseBitReader,512 bit_reader: *ReverseBitReader,
512 ) error{ MalformedFseBits, EndOfStream }!void {513 ) error{ MalformedFseBits, EndOfStream }!void {
513 switch (@field(self, @tagName(choice)).table) {514 switch (@field(self, @tagName(choice)).table) {
...@@ -537,7 +538,7 @@ pub const Frame = struct {...@@ -537,7 +538,7 @@ pub const Frame = struct {
537 self: *Decode,538 self: *Decode,
538 in: *Reader,539 in: *Reader,
539 remaining: *Limit,540 remaining: *Limit,
540 comptime choice: DataType,541 comptime choice: WhichFse,
541 mode: SequencesSection.Header.Mode,542 mode: SequencesSection.Header.Mode,
542 ) !void {543 ) !void {
543 const field_name = @tagName(choice);544 const field_name = @tagName(choice);
...@@ -564,10 +565,10 @@ pub const Frame = struct {...@@ -564,10 +565,10 @@ pub const Frame = struct {
564 &bit_reader,565 &bit_reader,
565 @field(zstd.table_symbol_count_max, field_name),566 @field(zstd.table_symbol_count_max, field_name),
566 @field(zstd.table_accuracy_log_max, field_name),567 @field(zstd.table_accuracy_log_max, field_name),
567 @field(self, field_name ++ "_fse_buffer"),568 &@field(self, field_name ++ "_fse_buffer"),
568 );569 );
569 @field(self, field_name).table = .{570 @field(self, field_name).table = .{
570 .fse = @field(self, field_name ++ "_fse_buffer")[0..table_size],571 .fse = (&@field(self, field_name ++ "_fse_buffer"))[0..table_size],
571 };572 };
572 @field(self, field_name).accuracy_log = std.math.log2_int_ceil(usize, table_size);573 @field(self, field_name).accuracy_log = std.math.log2_int_ceil(usize, table_size);
573 in.toss(bit_reader.index);574 in.toss(bit_reader.index);
...@@ -696,19 +697,19 @@ pub const Frame = struct {...@@ -696,19 +697,19 @@ pub const Frame = struct {
696 };697 };
697 }698 }
698699
699 /// Decode `len` bytes of literals into `dest`.700 /// Decode `len` bytes of literals into `w`.
700 fn decodeLiterals(self: *Decode, dest: *Writer, len: usize) !void {701 fn decodeLiterals(d: *Decode, w: *Writer, len: usize) !void {
701 switch (self.literal_header.block_type) {702 switch (d.literal_header.block_type) {
702 .raw => {703 .raw => {
703 try dest.writeAll(self.literal_streams.one[self.literal_written_count..][0..len]);704 try w.writeAll(d.literal_streams.one[d.literal_written_count..][0..len]);
704 },705 },
705 .rle => {706 .rle => {
706 try dest.splatByteAll(self.literal_streams.one[0], len);707 try w.splatByteAll(d.literal_streams.one[0], len);
707 },708 },
708 .compressed, .treeless => {709 .compressed, .treeless => {
709 if (len > dest.buffer.len) return error.OutputBufferUndersize;710 if (len > w.buffer.len) return error.OutputBufferUndersize;
710 const buf = try dest.writableSlice(len);711 const buf = try w.writableSlice(len);
711 const huffman_tree = self.huffman_tree.?;712 const huffman_tree = d.huffman_tree.?;
712 const max_bit_count = huffman_tree.max_bit_count;713 const max_bit_count = huffman_tree.max_bit_count;
713 const starting_bit_count = LiteralsSection.HuffmanTree.weightToBitCount(714 const starting_bit_count = LiteralsSection.HuffmanTree.weightToBitCount(
714 huffman_tree.nodes[huffman_tree.symbol_count_minus_one].weight,715 huffman_tree.nodes[huffman_tree.symbol_count_minus_one].weight,
...@@ -720,7 +721,7 @@ pub const Frame = struct {...@@ -720,7 +721,7 @@ pub const Frame = struct {
720 for (buf) |*out| {721 for (buf) |*out| {
721 var prefix: u16 = 0;722 var prefix: u16 = 0;
722 while (true) {723 while (true) {
723 const new_bits = try self.readLiteralsBits(bit_count_to_read);724 const new_bits = try d.readLiteralsBits(bit_count_to_read);
724 prefix <<= bit_count_to_read;725 prefix <<= bit_count_to_read;
725 prefix |= new_bits;726 prefix |= new_bits;
726 bits_read += bit_count_to_read;727 bits_read += bit_count_to_read;
...@@ -750,7 +751,7 @@ pub const Frame = struct {...@@ -750,7 +751,7 @@ pub const Frame = struct {
750 }751 }
751752
752 /// TODO: don't use `@field`753 /// TODO: don't use `@field`
753 fn getCode(self: *Decode, comptime choice: DataType) u32 {754 fn getCode(self: *Decode, comptime choice: WhichFse) u32 {
754 return switch (@field(self, @tagName(choice)).table) {755 return switch (@field(self, @tagName(choice)).table) {
755 .rle => |value| value,756 .rle => |value| value,
756 .fse => |table| table[@field(self, @tagName(choice)).state].symbol,757 .fse => |table| table[@field(self, @tagName(choice)).state].symbol,
...@@ -1166,7 +1167,7 @@ pub const LiteralsSection = struct {...@@ -1166,7 +1167,7 @@ pub const LiteralsSection = struct {
1166 .raw => {1167 .raw => {
1167 if (buffer.len < header.regenerated_size) return error.MalformedLiteralsSection;1168 if (buffer.len < header.regenerated_size) return error.MalformedLiteralsSection;
1168 remaining.* = remaining.subtract(header.regenerated_size) orelse return error.EndOfStream;1169 remaining.* = remaining.subtract(header.regenerated_size) orelse return error.EndOfStream;
1169 try in.readSlice(buffer[0..header.regenerated_size]);1170 try in.readSliceAll(buffer[0..header.regenerated_size]);
1170 return .{1171 return .{
1171 .header = header,1172 .header = header,
1172 .huffman_tree = null,1173 .huffman_tree = null,
...@@ -1193,7 +1194,7 @@ pub const LiteralsSection = struct {...@@ -1193,7 +1194,7 @@ pub const LiteralsSection = struct {
1193 return error.MalformedLiteralsSection;1194 return error.MalformedLiteralsSection;
1194 if (total_streams_size > buffer.len) return error.MalformedLiteralsSection;1195 if (total_streams_size > buffer.len) return error.MalformedLiteralsSection;
1195 remaining.* = remaining.subtract(total_streams_size) orelse return error.EndOfStream;1196 remaining.* = remaining.subtract(total_streams_size) orelse return error.EndOfStream;
1196 try in.readSlice(buffer[0..total_streams_size]);1197 try in.readSliceAll(buffer[0..total_streams_size]);
1197 const stream_data = buffer[0..total_streams_size];1198 const stream_data = buffer[0..total_streams_size];
1198 const streams = try Streams.decode(header.size_format, stream_data);1199 const streams = try Streams.decode(header.size_format, stream_data);
1199 return .{1200 return .{
lib/std/fs/File.zig+13-1
...@@ -1809,7 +1809,19 @@ pub const Writer = struct {...@@ -1809,7 +1809,19 @@ pub const Writer = struct {
1809 /// along with other write failures.1809 /// along with other write failures.
1810 pub fn end(w: *Writer) EndError!void {1810 pub fn end(w: *Writer) EndError!void {
1811 try w.interface.flush();1811 try w.interface.flush();
1812 return w.file.setEndPos(w.pos);1812 switch (w.mode) {
1813 .positional,
1814 .positional_reading,
1815 => w.file.setEndPos(w.pos) catch |err| switch (err) {
1816 error.NonResizable => return,
1817 else => |e| return e,
1818 },
1819
1820 .streaming,
1821 .streaming_reading,
1822 .failure,
1823 => {},
1824 }
1813 }1825 }
1814};1826};
18151827
lib/std/posix.zig+3-2
...@@ -1052,6 +1052,7 @@ pub const TruncateError = error{...@@ -1052,6 +1052,7 @@ pub const TruncateError = error{
1052 FileBusy,1052 FileBusy,
1053 AccessDenied,1053 AccessDenied,
1054 PermissionDenied,1054 PermissionDenied,
1055 NonResizable,
1055} || UnexpectedError;1056} || UnexpectedError;
10561057
1057/// Length must be positive when treated as an i64.1058/// Length must be positive when treated as an i64.
...@@ -1091,7 +1092,7 @@ pub fn ftruncate(fd: fd_t, length: u64) TruncateError!void {...@@ -1091,7 +1092,7 @@ pub fn ftruncate(fd: fd_t, length: u64) TruncateError!void {
1091 .PERM => return error.PermissionDenied,1092 .PERM => return error.PermissionDenied,
1092 .TXTBSY => return error.FileBusy,1093 .TXTBSY => return error.FileBusy,
1093 .BADF => unreachable, // Handle not open for writing1094 .BADF => unreachable, // Handle not open for writing
1094 .INVAL => unreachable, // Handle not open for writing, negative length, or non-resizable handle1095 .INVAL => return error.NonResizable,
1095 .NOTCAPABLE => return error.AccessDenied,1096 .NOTCAPABLE => return error.AccessDenied,
1096 else => |err| return unexpectedErrno(err),1097 else => |err| return unexpectedErrno(err),
1097 }1098 }
...@@ -1107,7 +1108,7 @@ pub fn ftruncate(fd: fd_t, length: u64) TruncateError!void {...@@ -1107,7 +1108,7 @@ pub fn ftruncate(fd: fd_t, length: u64) TruncateError!void {
1107 .PERM => return error.PermissionDenied,1108 .PERM => return error.PermissionDenied,
1108 .TXTBSY => return error.FileBusy,1109 .TXTBSY => return error.FileBusy,
1109 .BADF => unreachable, // Handle not open for writing1110 .BADF => unreachable, // Handle not open for writing
1110 .INVAL => unreachable, // Handle not open for writing, negative length, or non-resizable handle1111 .INVAL => return error.NonResizable, // This is returned for /dev/null for example.
1111 else => |err| return unexpectedErrno(err),1112 else => |err| return unexpectedErrno(err),
1112 }1113 }
1113 }1114 }
src/Compilation.zig+8
...@@ -4880,6 +4880,14 @@ fn docsCopyFallible(comp: *Compilation) anyerror!void {...@@ -4880,6 +4880,14 @@ fn docsCopyFallible(comp: *Compilation) anyerror!void {
4880 try seen_table.ensureUnusedCapacity(comp.gpa, deps.len);4880 try seen_table.ensureUnusedCapacity(comp.gpa, deps.len);
4881 for (deps) |dep| seen_table.putAssumeCapacity(dep, dep.fully_qualified_name);4881 for (deps) |dep| seen_table.putAssumeCapacity(dep, dep.fully_qualified_name);
4882 }4882 }
4883
4884 tar_file_writer.end() catch |err| {
4885 return comp.lockAndSetMiscFailure(
4886 .docs_copy,
4887 "unable to write '{f}/sources.tar': {t}",
4888 .{ docs_path, err },
4889 );
4890 };
4883}4891}
48844892
4885fn docsCopyModule(4893fn docsCopyModule(
src/Package/Fetch.zig+7-8
...@@ -1198,7 +1198,8 @@ fn unpackResource(...@@ -1198,7 +1198,8 @@ fn unpackResource(
11981198
1199 switch (file_type) {1199 switch (file_type) {
1200 .tar => {1200 .tar => {
1201 var adapter = resource.reader().adaptToNewApi();1201 var adapter_buffer: [1024]u8 = undefined;
1202 var adapter = resource.reader().adaptToNewApi(&adapter_buffer);
1202 return unpackTarball(f, tmp_directory.handle, &adapter.new_interface);1203 return unpackTarball(f, tmp_directory.handle, &adapter.new_interface);
1203 },1204 },
1204 .@"tar.gz" => {1205 .@"tar.gz" => {
...@@ -1227,14 +1228,12 @@ fn unpackResource(...@@ -1227,14 +1228,12 @@ fn unpackResource(
1227 .@"tar.zst" => {1228 .@"tar.zst" => {
1228 const window_size = std.compress.zstd.default_window_len;1229 const window_size = std.compress.zstd.default_window_len;
1229 const window_buffer = try f.arena.allocator().create([window_size]u8);1230 const window_buffer = try f.arena.allocator().create([window_size]u8);
1230 const reader = resource.reader();1231 var adapter_buffer: [std.crypto.tls.max_ciphertext_record_len]u8 = undefined;
1231 var br = std.io.bufferedReaderSize(std.crypto.tls.max_ciphertext_record_len, reader);1232 var adapter = resource.reader().adaptToNewApi(&adapter_buffer);
1232 var dcp = std.compress.zstd.decompressor(br.reader(), .{1233 var decompress: std.compress.zstd.Decompress = .init(&adapter.new_interface, window_buffer, .{
1233 .window_buffer = window_buffer,1234 .verify_checksum = false,
1234 });1235 });
1235 var adapter_buffer: [1024]u8 = undefined;1236 return try unpackTarball(f, tmp_directory.handle, &decompress.reader);
1236 var adapter = dcp.reader().adaptToNewApi(&adapter_buffer);
1237 return try unpackTarball(f, tmp_directory.handle, &adapter.new_interface);
1238 },1237 },
1239 .git_pack => return unpackGitPack(f, tmp_directory.handle, &resource.git) catch |err| switch (err) {1238 .git_pack => return unpackGitPack(f, tmp_directory.handle, &resource.git) catch |err| switch (err) {
1240 error.FetchFailed => return error.FetchFailed,1239 error.FetchFailed => return error.FetchFailed,
src/codegen/aarch64.zig+1-3
...@@ -113,9 +113,7 @@ pub fn generate(...@@ -113,9 +113,7 @@ pub fn generate(
113 },113 },
114 .stack_slot => |stack_slot| {114 .stack_slot => |stack_slot| {
115 assert(stack_slot.base == .sp);115 assert(stack_slot.base == .sp);
116 passed_vi.setParent(&isel, .{116 passed_vi.changeStackSlot(&isel, named_stack_args.withOffset(stack_slot.offset));
117 .stack_slot = named_stack_args.withOffset(stack_slot.offset),
118 });
119 },117 },
120 .address, .value, .constant => unreachable,118 .address, .value, .constant => unreachable,
121 }119 }
src/codegen/aarch64/Assemble.zig+11-2
...@@ -215,6 +215,7 @@ fn nextToken(as: *Assemble, buf: *[token_buf_len]u8, comptime opts: struct {...@@ -215,6 +215,7 @@ fn nextToken(as: *Assemble, buf: *[token_buf_len]u8, comptime opts: struct {
215215
216const SymbolSpec = union(enum) {216const SymbolSpec = union(enum) {
217 reg: struct { format: aarch64.encoding.Register.Format, allow_sp: bool = false },217 reg: struct { format: aarch64.encoding.Register.Format, allow_sp: bool = false },
218 systemreg,
218 imm: struct {219 imm: struct {
219 type: std.builtin.Type.Int,220 type: std.builtin.Type.Int,
220 multiple_of: comptime_int = 1,221 multiple_of: comptime_int = 1,
...@@ -227,6 +228,7 @@ const SymbolSpec = union(enum) {...@@ -227,6 +228,7 @@ const SymbolSpec = union(enum) {
227 fn Storage(comptime spec: SymbolSpec) type {228 fn Storage(comptime spec: SymbolSpec) type {
228 return switch (spec) {229 return switch (spec) {
229 .reg => aarch64.encoding.Register,230 .reg => aarch64.encoding.Register,
231 .systemreg => aarch64.encoding.Register.System,
230 .imm => |imm| @Type(.{ .int = imm.type }),232 .imm => |imm| @Type(.{ .int = imm.type }),
231 .extend => Instruction.DataProcessingRegister.AddSubtractExtendedRegister.Option,233 .extend => Instruction.DataProcessingRegister.AddSubtractExtendedRegister.Option,
232 .shift => Instruction.DataProcessingRegister.Shift.Op,234 .shift => Instruction.DataProcessingRegister.Shift.Op,
...@@ -238,8 +240,7 @@ const SymbolSpec = union(enum) {...@@ -238,8 +240,7 @@ const SymbolSpec = union(enum) {
238 const Result = Storage(spec);240 const Result = Storage(spec);
239 switch (spec) {241 switch (spec) {
240 .reg => |reg_spec| {242 .reg => |reg_spec| {
241 var buf: [token_buf_len]u8 = undefined;243 const reg = Result.parse(token) orelse {
242 const reg = Result.parse(std.ascii.lowerString(&buf, token[0..@min(token.len, buf.len)])) orelse {
243 log.debug("invalid register: \"{f}\"", .{std.zig.fmtString(token)});244 log.debug("invalid register: \"{f}\"", .{std.zig.fmtString(token)});
244 return null;245 return null;
245 };246 };
...@@ -253,6 +254,14 @@ const SymbolSpec = union(enum) {...@@ -253,6 +254,14 @@ const SymbolSpec = union(enum) {
253 }254 }
254 return reg;255 return reg;
255 },256 },
257 .systemreg => {
258 const systemreg = Result.parse(token) orelse {
259 log.debug("invalid system register: \"{f}\"", .{std.zig.fmtString(token)});
260 return null;
261 };
262 assert(systemreg.op0 >= 2);
263 return systemreg;
264 },
256 .imm => |imm_spec| {265 .imm => |imm_spec| {
257 const imm = std.fmt.parseInt(Result, token, 0) catch {266 const imm = std.fmt.parseInt(Result, token, 0) catch {
258 log.debug("invalid immediate: \"{f}\"", .{std.zig.fmtString(token)});267 log.debug("invalid immediate: \"{f}\"", .{std.zig.fmtString(token)});
src/codegen/aarch64/Select.zig+263-263
...@@ -5535,7 +5535,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {...@@ -5535,7 +5535,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
5535 2 => if (elem_is_vector) .ldr(elem_ra.h(), .{ .extended_register = .{5535 2 => if (elem_is_vector) .ldr(elem_ra.h(), .{ .extended_register = .{
5536 .base = base_mat.ra.x(),5536 .base = base_mat.ra.x(),
5537 .index = index_mat.ra.x(),5537 .index = index_mat.ra.x(),
5538 .extend = .{ .lsl = 0 },5538 .extend = .{ .lsl = 1 },
5539 } }) else switch (elem_vi.value.signedness(isel)) {5539 } }) else switch (elem_vi.value.signedness(isel)) {
5540 .signed => .ldrsh(elem_ra.w(), .{ .extended_register = .{5540 .signed => .ldrsh(elem_ra.w(), .{ .extended_register = .{
5541 .base = base_mat.ra.x(),5541 .base = base_mat.ra.x(),
...@@ -5558,15 +5558,14 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {...@@ -5558,15 +5558,14 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
5558 .index = index_mat.ra.x(),5558 .index = index_mat.ra.x(),
5559 .extend = .{ .lsl = 3 },5559 .extend = .{ .lsl = 3 },
5560 } }),5560 } }),
5561 16 => .ldr(elem_ra.q(), .{ .extended_register = .{5561 16 => if (elem_is_vector) .ldr(elem_ra.q(), .{ .extended_register = .{
5562 .base = base_mat.ra.x(),5562 .base = base_mat.ra.x(),
5563 .index = index_mat.ra.x(),5563 .index = index_mat.ra.x(),
5564 .extend = .{ .lsl = 4 },5564 .extend = .{ .lsl = 4 },
5565 } }),5565 } }) else unreachable,
5566 });5566 });
5567 try index_mat.finish(isel);5567 try index_mat.finish(isel);
5568 try base_mat.finish(isel);5568 try base_mat.finish(isel);
5569 break :unused;
5570 } else {5569 } else {
5571 const elem_ptr_ra = try isel.allocIntReg();5570 const elem_ptr_ra = try isel.allocIntReg();
5572 defer isel.freeReg(elem_ptr_ra);5571 defer isel.freeReg(elem_ptr_ra);
...@@ -5611,66 +5610,81 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {...@@ -5611,66 +5610,81 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
5611 const ptr_ty = isel.air.typeOf(bin_op.lhs, ip);5610 const ptr_ty = isel.air.typeOf(bin_op.lhs, ip);
5612 const ptr_info = ptr_ty.ptrInfo(zcu);5611 const ptr_info = ptr_ty.ptrInfo(zcu);
5613 const elem_size = elem_vi.value.size(isel);5612 const elem_size = elem_vi.value.size(isel);
5614 switch (elem_size) {5613 const elem_is_vector = elem_vi.value.isVector(isel);
5614 if (switch (elem_size) {
5615 0 => unreachable,5615 0 => unreachable,
5616 1, 2, 4, 8 => {5616 1, 2, 4, 8 => true,
5617 const elem_ra = try elem_vi.value.defReg(isel) orelse break :unused;5617 16 => elem_is_vector,
5618 const base_vi = try isel.use(bin_op.lhs);5618 else => false,
5619 const index_vi = try isel.use(bin_op.rhs);5619 }) {
5620 const base_mat = try base_vi.matReg(isel);5620 const elem_ra = try elem_vi.value.defReg(isel) orelse break :unused;
5621 const index_mat = try index_vi.matReg(isel);5621 const base_vi = try isel.use(bin_op.lhs);
5622 try isel.emit(switch (elem_size) {5622 const index_vi = try isel.use(bin_op.rhs);
5623 else => unreachable,5623 const base_mat = try base_vi.matReg(isel);
5624 1 => switch (elem_vi.value.signedness(isel)) {5624 const index_mat = try index_vi.matReg(isel);
5625 .signed => .ldrsb(elem_ra.w(), .{ .extended_register = .{5625 try isel.emit(switch (elem_size) {
5626 .base = base_mat.ra.x(),5626 else => unreachable,
5627 .index = index_mat.ra.x(),5627 1 => if (elem_is_vector) .ldr(elem_ra.b(), .{ .extended_register = .{
5628 .extend = .{ .lsl = 0 },5628 .base = base_mat.ra.x(),
5629 } }),5629 .index = index_mat.ra.x(),
5630 .unsigned => .ldrb(elem_ra.w(), .{ .extended_register = .{5630 .extend = .{ .lsl = 0 },
5631 .base = base_mat.ra.x(),5631 } }) else switch (elem_vi.value.signedness(isel)) {
5632 .index = index_mat.ra.x(),5632 .signed => .ldrsb(elem_ra.w(), .{ .extended_register = .{
5633 .extend = .{ .lsl = 0 },
5634 } }),
5635 },
5636 2 => switch (elem_vi.value.signedness(isel)) {
5637 .signed => .ldrsh(elem_ra.w(), .{ .extended_register = .{
5638 .base = base_mat.ra.x(),
5639 .index = index_mat.ra.x(),
5640 .extend = .{ .lsl = 1 },
5641 } }),
5642 .unsigned => .ldrh(elem_ra.w(), .{ .extended_register = .{
5643 .base = base_mat.ra.x(),
5644 .index = index_mat.ra.x(),
5645 .extend = .{ .lsl = 1 },
5646 } }),
5647 },
5648 4 => .ldr(elem_ra.w(), .{ .extended_register = .{
5649 .base = base_mat.ra.x(),5633 .base = base_mat.ra.x(),
5650 .index = index_mat.ra.x(),5634 .index = index_mat.ra.x(),
5651 .extend = .{ .lsl = 2 },5635 .extend = .{ .lsl = 0 },
5652 } }),5636 } }),
5653 8 => .ldr(elem_ra.x(), .{ .extended_register = .{5637 .unsigned => .ldrb(elem_ra.w(), .{ .extended_register = .{
5654 .base = base_mat.ra.x(),5638 .base = base_mat.ra.x(),
5655 .index = index_mat.ra.x(),5639 .index = index_mat.ra.x(),
5656 .extend = .{ .lsl = 3 },5640 .extend = .{ .lsl = 0 },
5657 } }),5641 } }),
5658 });5642 },
5659 try index_mat.finish(isel);5643 2 => if (elem_is_vector) .ldr(elem_ra.h(), .{ .extended_register = .{
5660 try base_mat.finish(isel);5644 .base = base_mat.ra.x(),
5661 },5645 .index = index_mat.ra.x(),
5662 else => {5646 .extend = .{ .lsl = 1 },
5663 const elem_ptr_ra = try isel.allocIntReg();5647 } }) else switch (elem_vi.value.signedness(isel)) {
5664 defer isel.freeReg(elem_ptr_ra);5648 .signed => .ldrsh(elem_ra.w(), .{ .extended_register = .{
5665 if (!try elem_vi.value.load(isel, ptr_ty.elemType2(zcu), elem_ptr_ra, .{5649 .base = base_mat.ra.x(),
5666 .@"volatile" = ptr_info.flags.is_volatile,5650 .index = index_mat.ra.x(),
5667 })) break :unused;5651 .extend = .{ .lsl = 1 },
5668 const base_vi = try isel.use(bin_op.lhs);5652 } }),
5669 const base_mat = try base_vi.matReg(isel);5653 .unsigned => .ldrh(elem_ra.w(), .{ .extended_register = .{
5670 const index_vi = try isel.use(bin_op.rhs);5654 .base = base_mat.ra.x(),
5671 try isel.elemPtr(elem_ptr_ra, base_mat.ra, .add, elem_size, index_vi);5655 .index = index_mat.ra.x(),
5672 try base_mat.finish(isel);5656 .extend = .{ .lsl = 1 },
5673 },5657 } }),
5658 },
5659 4 => .ldr(if (elem_is_vector) elem_ra.s() else elem_ra.w(), .{ .extended_register = .{
5660 .base = base_mat.ra.x(),
5661 .index = index_mat.ra.x(),
5662 .extend = .{ .lsl = 2 },
5663 } }),
5664 8 => .ldr(if (elem_is_vector) elem_ra.d() else elem_ra.x(), .{ .extended_register = .{
5665 .base = base_mat.ra.x(),
5666 .index = index_mat.ra.x(),
5667 .extend = .{ .lsl = 3 },
5668 } }),
5669 16 => if (elem_is_vector) .ldr(elem_ra.q(), .{ .extended_register = .{
5670 .base = base_mat.ra.x(),
5671 .index = index_mat.ra.x(),
5672 .extend = .{ .lsl = 4 },
5673 } }) else unreachable,
5674 });
5675 try index_mat.finish(isel);
5676 try base_mat.finish(isel);
5677 } else {
5678 const elem_ptr_ra = try isel.allocIntReg();
5679 defer isel.freeReg(elem_ptr_ra);
5680 if (!try elem_vi.value.load(isel, ptr_ty.elemType2(zcu), elem_ptr_ra, .{
5681 .@"volatile" = ptr_info.flags.is_volatile,
5682 })) break :unused;
5683 const base_vi = try isel.use(bin_op.lhs);
5684 const base_mat = try base_vi.matReg(isel);
5685 const index_vi = try isel.use(bin_op.rhs);
5686 try isel.elemPtr(elem_ptr_ra, base_mat.ra, .add, elem_size, index_vi);
5687 try base_mat.finish(isel);
5674 }5688 }
5675 }5689 }
5676 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;5690 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
...@@ -6250,11 +6264,12 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {...@@ -6250,11 +6264,12 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
6250 try agg_part_vi.?.move(isel, elems[field_index]);6264 try agg_part_vi.?.move(isel, elems[field_index]);
6251 field_offset += field_size;6265 field_offset += field_size;
6252 }6266 }
6253 assert(field_offset == agg_vi.value.size(isel));6267 assert(loaded_struct.flagsUnordered(ip).alignment.forward(field_offset) == agg_vi.value.size(isel));
6254 },6268 },
6255 .tuple_type => |tuple_type| {6269 .tuple_type => |tuple_type| {
6256 const elems: []const Air.Inst.Ref =6270 const elems: []const Air.Inst.Ref =
6257 @ptrCast(isel.air.extra.items[ty_pl.payload..][0..tuple_type.types.len]);6271 @ptrCast(isel.air.extra.items[ty_pl.payload..][0..tuple_type.types.len]);
6272 var tuple_align: InternPool.Alignment = .@"1";
6258 var field_offset: u64 = 0;6273 var field_offset: u64 = 0;
6259 for (6274 for (
6260 tuple_type.types.get(ip),6275 tuple_type.types.get(ip),
...@@ -6263,7 +6278,9 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {...@@ -6263,7 +6278,9 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
6263 ) |field_ty_index, field_val, elem| {6278 ) |field_ty_index, field_val, elem| {
6264 if (field_val != .none) continue;6279 if (field_val != .none) continue;
6265 const field_ty: ZigType = .fromInterned(field_ty_index);6280 const field_ty: ZigType = .fromInterned(field_ty_index);
6266 field_offset = field_ty.abiAlignment(zcu).forward(field_offset);6281 const field_align = field_ty.abiAlignment(zcu);
6282 tuple_align = tuple_align.maxStrict(field_align);
6283 field_offset = field_align.forward(field_offset);
6267 const field_size = field_ty.abiSize(zcu);6284 const field_size = field_ty.abiSize(zcu);
6268 if (field_size == 0) continue;6285 if (field_size == 0) continue;
6269 var agg_part_it = agg_vi.value.field(agg_ty, field_offset, field_size);6286 var agg_part_it = agg_vi.value.field(agg_ty, field_offset, field_size);
...@@ -6271,7 +6288,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {...@@ -6271,7 +6288,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
6271 try agg_part_vi.?.move(isel, elem);6288 try agg_part_vi.?.move(isel, elem);
6272 field_offset += field_size;6289 field_offset += field_size;
6273 }6290 }
6274 assert(field_offset == agg_vi.value.size(isel));6291 assert(tuple_align.forward(field_offset) == agg_vi.value.size(isel));
6275 },6292 },
6276 else => return isel.fail("aggregate init {f}", .{isel.fmtType(agg_ty)}),6293 else => return isel.fail("aggregate init {f}", .{isel.fmtType(agg_ty)}),
6277 }6294 }
...@@ -7283,6 +7300,175 @@ fn ctzLimb(...@@ -7283,6 +7300,175 @@ fn ctzLimb(
7283 }7300 }
7284}7301}
72857302
7303fn loadReg(
7304 isel: *Select,
7305 ra: Register.Alias,
7306 size: u64,
7307 signedness: std.builtin.Signedness,
7308 base_ra: Register.Alias,
7309 offset: i65,
7310) !void {
7311 switch (size) {
7312 0 => unreachable,
7313 1 => {
7314 if (std.math.cast(u12, offset)) |unsigned_offset| return isel.emit(if (ra.isVector()) .ldr(
7315 ra.b(),
7316 .{ .unsigned_offset = .{
7317 .base = base_ra.x(),
7318 .offset = unsigned_offset,
7319 } },
7320 ) else switch (signedness) {
7321 .signed => .ldrsb(ra.w(), .{ .unsigned_offset = .{
7322 .base = base_ra.x(),
7323 .offset = unsigned_offset,
7324 } }),
7325 .unsigned => .ldrb(ra.w(), .{ .unsigned_offset = .{
7326 .base = base_ra.x(),
7327 .offset = unsigned_offset,
7328 } }),
7329 });
7330 if (std.math.cast(i9, offset)) |signed_offset| return isel.emit(if (ra.isVector())
7331 .ldur(ra.b(), base_ra.x(), signed_offset)
7332 else switch (signedness) {
7333 .signed => .ldursb(ra.w(), base_ra.x(), signed_offset),
7334 .unsigned => .ldurb(ra.w(), base_ra.x(), signed_offset),
7335 });
7336 },
7337 2 => {
7338 if (std.math.cast(u13, offset)) |unsigned_offset| if (unsigned_offset % 2 == 0)
7339 return isel.emit(if (ra.isVector()) .ldr(
7340 ra.h(),
7341 .{ .unsigned_offset = .{
7342 .base = base_ra.x(),
7343 .offset = unsigned_offset,
7344 } },
7345 ) else switch (signedness) {
7346 .signed => .ldrsh(
7347 ra.w(),
7348 .{ .unsigned_offset = .{
7349 .base = base_ra.x(),
7350 .offset = unsigned_offset,
7351 } },
7352 ),
7353 .unsigned => .ldrh(
7354 ra.w(),
7355 .{ .unsigned_offset = .{
7356 .base = base_ra.x(),
7357 .offset = unsigned_offset,
7358 } },
7359 ),
7360 });
7361 if (std.math.cast(i9, offset)) |signed_offset| return isel.emit(if (ra.isVector())
7362 .ldur(ra.h(), base_ra.x(), signed_offset)
7363 else switch (signedness) {
7364 .signed => .ldursh(ra.w(), base_ra.x(), signed_offset),
7365 .unsigned => .ldurh(ra.w(), base_ra.x(), signed_offset),
7366 });
7367 },
7368 3 => {
7369 const lo16_ra = try isel.allocIntReg();
7370 defer isel.freeReg(lo16_ra);
7371 try isel.emit(.orr(ra.w(), lo16_ra.w(), .{ .shifted_register = .{
7372 .register = ra.w(),
7373 .shift = .{ .lsl = 16 },
7374 } }));
7375 try isel.loadReg(ra, 1, signedness, base_ra, offset + 2);
7376 return isel.loadReg(lo16_ra, 2, .unsigned, base_ra, offset);
7377 },
7378 4 => {
7379 if (std.math.cast(u14, offset)) |unsigned_offset| if (unsigned_offset % 4 == 0) return isel.emit(.ldr(
7380 if (ra.isVector()) ra.s() else ra.w(),
7381 .{ .unsigned_offset = .{
7382 .base = base_ra.x(),
7383 .offset = unsigned_offset,
7384 } },
7385 ));
7386 if (std.math.cast(i9, offset)) |signed_offset| return isel.emit(.ldur(
7387 if (ra.isVector()) ra.s() else ra.w(),
7388 base_ra.x(),
7389 signed_offset,
7390 ));
7391 },
7392 5, 6 => {
7393 const lo32_ra = try isel.allocIntReg();
7394 defer isel.freeReg(lo32_ra);
7395 try isel.emit(.orr(ra.x(), lo32_ra.x(), .{ .shifted_register = .{
7396 .register = ra.x(),
7397 .shift = .{ .lsl = 32 },
7398 } }));
7399 try isel.loadReg(ra, size - 4, signedness, base_ra, offset + 4);
7400 return isel.loadReg(lo32_ra, 4, .unsigned, base_ra, offset);
7401 },
7402 7 => {
7403 const lo32_ra = try isel.allocIntReg();
7404 defer isel.freeReg(lo32_ra);
7405 const lo48_ra = try isel.allocIntReg();
7406 defer isel.freeReg(lo48_ra);
7407 try isel.emit(.orr(ra.x(), lo48_ra.x(), .{ .shifted_register = .{
7408 .register = ra.x(),
7409 .shift = .{ .lsl = 32 + 16 },
7410 } }));
7411 try isel.loadReg(ra, 1, signedness, base_ra, offset + 4 + 2);
7412 try isel.emit(.orr(lo48_ra.x(), lo32_ra.x(), .{ .shifted_register = .{
7413 .register = lo48_ra.x(),
7414 .shift = .{ .lsl = 32 },
7415 } }));
7416 try isel.loadReg(lo48_ra, 2, .unsigned, base_ra, offset + 4);
7417 return isel.loadReg(lo32_ra, 4, .unsigned, base_ra, offset);
7418 },
7419 8 => {
7420 if (std.math.cast(u15, offset)) |unsigned_offset| if (unsigned_offset % 8 == 0) return isel.emit(.ldr(
7421 if (ra.isVector()) ra.d() else ra.x(),
7422 .{ .unsigned_offset = .{
7423 .base = base_ra.x(),
7424 .offset = unsigned_offset,
7425 } },
7426 ));
7427 if (std.math.cast(i9, offset)) |signed_offset| return isel.emit(.ldur(
7428 if (ra.isVector()) ra.d() else ra.x(),
7429 base_ra.x(),
7430 signed_offset,
7431 ));
7432 },
7433 16 => {
7434 if (std.math.cast(u16, offset)) |unsigned_offset| if (unsigned_offset % 16 == 0) return isel.emit(.ldr(
7435 ra.q(),
7436 .{ .unsigned_offset = .{
7437 .base = base_ra.x(),
7438 .offset = unsigned_offset,
7439 } },
7440 ));
7441 if (std.math.cast(i9, offset)) |signed_offset| return isel.emit(.ldur(ra.q(), base_ra.x(), signed_offset));
7442 },
7443 else => return isel.fail("bad load size: {d}", .{size}),
7444 }
7445 const ptr_ra = try isel.allocIntReg();
7446 defer isel.freeReg(ptr_ra);
7447 try isel.loadReg(ra, size, signedness, ptr_ra, 0);
7448 if (std.math.cast(u24, offset)) |pos_offset| {
7449 const lo12: u12 = @truncate(pos_offset >> 0);
7450 const hi12: u12 = @intCast(pos_offset >> 12);
7451 if (hi12 > 0) try isel.emit(.add(
7452 ptr_ra.x(),
7453 if (lo12 > 0) ptr_ra.x() else base_ra.x(),
7454 .{ .shifted_immediate = .{ .immediate = hi12, .lsl = .@"12" } },
7455 ));
7456 if (lo12 > 0 or hi12 == 0) try isel.emit(.add(ptr_ra.x(), base_ra.x(), .{ .immediate = lo12 }));
7457 } else if (std.math.cast(u24, -offset)) |neg_offset| {
7458 const lo12: u12 = @truncate(neg_offset >> 0);
7459 const hi12: u12 = @intCast(neg_offset >> 12);
7460 if (hi12 > 0) try isel.emit(.sub(
7461 ptr_ra.x(),
7462 if (lo12 > 0) ptr_ra.x() else base_ra.x(),
7463 .{ .shifted_immediate = .{ .immediate = hi12, .lsl = .@"12" } },
7464 ));
7465 if (lo12 > 0 or hi12 == 0) try isel.emit(.sub(ptr_ra.x(), base_ra.x(), .{ .immediate = lo12 }));
7466 } else {
7467 try isel.emit(.add(ptr_ra.x(), base_ra.x(), .{ .register = ptr_ra.x() }));
7468 try isel.movImmediate(ptr_ra.x(), @truncate(@as(u65, @bitCast(offset))));
7469 }
7470}
7471
7286fn storeReg(7472fn storeReg(
7287 isel: *Select,7473 isel: *Select,
7288 ra: Register.Alias,7474 ra: Register.Alias,
...@@ -7558,6 +7744,13 @@ pub const Value = struct {...@@ -7558,6 +7744,13 @@ pub const Value = struct {
7558 };7744 };
7559 }7745 }
75607746
7747 pub fn changeStackSlot(vi: Value.Index, isel: *Select, new_stack_slot: Indirect) void {
7748 const value = vi.get(isel);
7749 assert(value.flags.parent_tag == .stack_slot);
7750 value.flags.parent_tag = .unallocated;
7751 vi.setParent(isel, .{ .stack_slot = new_stack_slot });
7752 }
7753
7561 pub fn parent(vi: Value.Index, isel: *Select) Parent {7754 pub fn parent(vi: Value.Index, isel: *Select) Parent {
7562 const value = vi.get(isel);7755 const value = vi.get(isel);
7563 return switch (value.flags.parent_tag) {7756 return switch (value.flags.parent_tag) {
...@@ -8070,123 +8263,7 @@ pub const Value = struct {...@@ -8070,123 +8263,7 @@ pub const Value = struct {
8070 }),8263 }),
8071 64 => {},8264 64 => {},
8072 };8265 };
8073 try isel.emit(emit: switch (part_size) {8266 try isel.loadReg(part_ra, part_size, part_vi.signedness(isel), base_ra, opts.offset);
8074 else => return isel.fail("bad load size of {d}", .{part_size}),
8075 1 => if (part_is_vector) .ldr(part_ra.b(), .{ .unsigned_offset = .{
8076 .base = base_ra.x(),
8077 .offset = @intCast(opts.offset),
8078 } }) else switch (part_vi.signedness(isel)) {
8079 .signed => .ldrsb(part_ra.w(), .{ .unsigned_offset = .{
8080 .base = base_ra.x(),
8081 .offset = @intCast(opts.offset),
8082 } }),
8083 .unsigned => .ldrb(part_ra.w(), .{ .unsigned_offset = .{
8084 .base = base_ra.x(),
8085 .offset = @intCast(opts.offset),
8086 } }),
8087 },
8088 2 => if (part_is_vector) .ldr(part_ra.h(), .{ .unsigned_offset = .{
8089 .base = base_ra.x(),
8090 .offset = @intCast(opts.offset),
8091 } }) else switch (part_vi.signedness(isel)) {
8092 .signed => .ldrsh(part_ra.w(), .{ .unsigned_offset = .{
8093 .base = base_ra.x(),
8094 .offset = @intCast(opts.offset),
8095 } }),
8096 .unsigned => .ldrh(part_ra.w(), .{ .unsigned_offset = .{
8097 .base = base_ra.x(),
8098 .offset = @intCast(opts.offset),
8099 } }),
8100 },
8101 3 => {
8102 const lo16_ra = try isel.allocIntReg();
8103 defer isel.freeReg(lo16_ra);
8104 try isel.emit(.orr(part_ra.w(), lo16_ra.w(), .{ .shifted_register = .{
8105 .register = part_ra.w(),
8106 .shift = .{ .lsl = 16 },
8107 } }));
8108 try isel.emit(switch (part_vi.signedness(isel)) {
8109 .signed => .ldrsb(part_ra.w(), .{ .unsigned_offset = .{
8110 .base = base_ra.x(),
8111 .offset = @intCast(opts.offset + 2),
8112 } }),
8113 .unsigned => .ldrb(part_ra.w(), .{ .unsigned_offset = .{
8114 .base = base_ra.x(),
8115 .offset = @intCast(opts.offset + 2),
8116 } }),
8117 });
8118 break :emit .ldrh(lo16_ra.w(), .{ .unsigned_offset = .{
8119 .base = base_ra.x(),
8120 .offset = @intCast(opts.offset),
8121 } });
8122 },
8123 4 => .ldr(if (part_is_vector) part_ra.s() else part_ra.w(), .{ .unsigned_offset = .{
8124 .base = base_ra.x(),
8125 .offset = @intCast(opts.offset),
8126 } }),
8127 5 => {
8128 const lo32_ra = try isel.allocIntReg();
8129 defer isel.freeReg(lo32_ra);
8130 try isel.emit(.orr(part_ra.x(), lo32_ra.x(), .{ .shifted_register = .{
8131 .register = part_ra.x(),
8132 .shift = .{ .lsl = 32 },
8133 } }));
8134 try isel.emit(switch (part_vi.signedness(isel)) {
8135 .signed => .ldrsb(part_ra.w(), .{ .unsigned_offset = .{
8136 .base = base_ra.x(),
8137 .offset = @intCast(opts.offset + 4),
8138 } }),
8139 .unsigned => .ldrb(part_ra.w(), .{ .unsigned_offset = .{
8140 .base = base_ra.x(),
8141 .offset = @intCast(opts.offset + 4),
8142 } }),
8143 });
8144 break :emit .ldr(lo32_ra.w(), .{ .unsigned_offset = .{
8145 .base = base_ra.x(),
8146 .offset = @intCast(opts.offset),
8147 } });
8148 },
8149 7 => {
8150 const lo32_ra = try isel.allocIntReg();
8151 defer isel.freeReg(lo32_ra);
8152 const lo48_ra = try isel.allocIntReg();
8153 defer isel.freeReg(lo48_ra);
8154 try isel.emit(.orr(part_ra.x(), lo48_ra.x(), .{ .shifted_register = .{
8155 .register = part_ra.x(),
8156 .shift = .{ .lsl = 32 + 16 },
8157 } }));
8158 try isel.emit(switch (part_vi.signedness(isel)) {
8159 .signed => .ldrsb(part_ra.w(), .{ .unsigned_offset = .{
8160 .base = base_ra.x(),
8161 .offset = @intCast(opts.offset + 4 + 2),
8162 } }),
8163 .unsigned => .ldrb(part_ra.w(), .{ .unsigned_offset = .{
8164 .base = base_ra.x(),
8165 .offset = @intCast(opts.offset + 4 + 2),
8166 } }),
8167 });
8168 try isel.emit(.orr(lo48_ra.x(), lo32_ra.x(), .{ .shifted_register = .{
8169 .register = lo48_ra.x(),
8170 .shift = .{ .lsl = 32 },
8171 } }));
8172 try isel.emit(.ldrh(lo48_ra.w(), .{ .unsigned_offset = .{
8173 .base = base_ra.x(),
8174 .offset = @intCast(opts.offset + 4),
8175 } }));
8176 break :emit .ldr(lo32_ra.w(), .{ .unsigned_offset = .{
8177 .base = base_ra.x(),
8178 .offset = @intCast(opts.offset),
8179 } });
8180 },
8181 8 => .ldr(if (part_is_vector) part_ra.d() else part_ra.x(), .{ .unsigned_offset = .{
8182 .base = base_ra.x(),
8183 .offset = @intCast(opts.offset),
8184 } }),
8185 16 => .ldr(part_ra.q(), .{ .unsigned_offset = .{
8186 .base = base_ra.x(),
8187 .offset = @intCast(opts.offset),
8188 } }),
8189 });
8190 if (part_ra != .zr) {8267 if (part_ra != .zr) {
8191 const live_vi = isel.live_registers.getPtr(part_ra);8268 const live_vi = isel.live_registers.getPtr(part_ra);
8192 assert(live_vi.* == .allocating);8269 assert(live_vi.* == .allocating);
...@@ -9104,7 +9181,7 @@ pub const Value = struct {...@@ -9104,7 +9181,7 @@ pub const Value = struct {
9104 const live_vi = isel.live_registers.getPtr(mat.ra);9181 const live_vi = isel.live_registers.getPtr(mat.ra);
9105 assert(live_vi.* == .allocating);9182 assert(live_vi.* == .allocating);
9106 var vi = mat.vi;9183 var vi = mat.vi;
9107 var offset: i65 = 0;9184 var offset: u64 = 0;
9108 const size = mat.vi.size(isel);9185 const size = mat.vi.size(isel);
9109 free: while (true) {9186 free: while (true) {
9110 if (vi.register(isel)) |ra| {9187 if (vi.register(isel)) |ra| {
...@@ -9156,93 +9233,16 @@ pub const Value = struct {...@@ -9156,93 +9233,16 @@ pub const Value = struct {
9156 live_vi.* = mat.vi;9233 live_vi.* = mat.vi;
9157 return;9234 return;
9158 },9235 },
9159 .stack_slot => |stack_slot| {9236 .stack_slot => |stack_slot| break :free try isel.loadReg(
9160 offset += stack_slot.offset;9237 mat.ra,
9161 break :free try isel.emit(switch (size) {9238 size,
9162 else => unreachable,9239 mat.vi.signedness(isel),
9163 1 => if (mat.ra.isVector()) .ldr(mat.ra.b(), .{ .unsigned_offset = .{9240 stack_slot.base,
9164 .base = stack_slot.base.x(),9241 @as(i65, stack_slot.offset) + offset,
9165 .offset = @intCast(offset),9242 ),
9166 } }) else switch (mat.vi.signedness(isel)) {
9167 .signed => .ldrsb(mat.ra.w(), .{ .unsigned_offset = .{
9168 .base = stack_slot.base.x(),
9169 .offset = @intCast(offset),
9170 } }),
9171 .unsigned => .ldrb(mat.ra.w(), .{ .unsigned_offset = .{
9172 .base = stack_slot.base.x(),
9173 .offset = @intCast(offset),
9174 } }),
9175 },
9176 2 => if (mat.ra.isVector()) .ldr(mat.ra.h(), .{ .unsigned_offset = .{
9177 .base = stack_slot.base.x(),
9178 .offset = @intCast(offset),
9179 } }) else switch (mat.vi.signedness(isel)) {
9180 .signed => .ldrsh(mat.ra.w(), .{ .unsigned_offset = .{
9181 .base = stack_slot.base.x(),
9182 .offset = @intCast(offset),
9183 } }),
9184 .unsigned => .ldrh(mat.ra.w(), .{ .unsigned_offset = .{
9185 .base = stack_slot.base.x(),
9186 .offset = @intCast(offset),
9187 } }),
9188 },
9189 4 => .ldr(if (mat.ra.isVector()) mat.ra.s() else mat.ra.w(), .{ .unsigned_offset = .{
9190 .base = stack_slot.base.x(),
9191 .offset = @intCast(offset),
9192 } }),
9193 8 => .ldr(if (mat.ra.isVector()) mat.ra.d() else mat.ra.x(), .{ .unsigned_offset = .{
9194 .base = stack_slot.base.x(),
9195 .offset = @intCast(offset),
9196 } }),
9197 16 => .ldr(mat.ra.q(), .{ .unsigned_offset = .{
9198 .base = stack_slot.base.x(),
9199 .offset = @intCast(offset),
9200 } }),
9201 });
9202 },
9203 .address => |base_vi| {9243 .address => |base_vi| {
9204 const base_mat = try base_vi.matReg(isel);9244 const base_mat = try base_vi.matReg(isel);
9205 try isel.emit(switch (size) {9245 try isel.loadReg(mat.ra, size, mat.vi.signedness(isel), base_mat.ra, offset);
9206 else => unreachable,
9207 1 => if (mat.ra.isVector()) .ldr(mat.ra.b(), .{ .unsigned_offset = .{
9208 .base = base_mat.ra.x(),
9209 .offset = @intCast(offset),
9210 } }) else switch (mat.vi.signedness(isel)) {
9211 .signed => .ldrsb(mat.ra.w(), .{ .unsigned_offset = .{
9212 .base = base_mat.ra.x(),
9213 .offset = @intCast(offset),
9214 } }),
9215 .unsigned => .ldrb(mat.ra.w(), .{ .unsigned_offset = .{
9216 .base = base_mat.ra.x(),
9217 .offset = @intCast(offset),
9218 } }),
9219 },
9220 2 => if (mat.ra.isVector()) .ldr(mat.ra.h(), .{ .unsigned_offset = .{
9221 .base = base_mat.ra.x(),
9222 .offset = @intCast(offset),
9223 } }) else switch (mat.vi.signedness(isel)) {
9224 .signed => .ldrsh(mat.ra.w(), .{ .unsigned_offset = .{
9225 .base = base_mat.ra.x(),
9226 .offset = @intCast(offset),
9227 } }),
9228 .unsigned => .ldrh(mat.ra.w(), .{ .unsigned_offset = .{
9229 .base = base_mat.ra.x(),
9230 .offset = @intCast(offset),
9231 } }),
9232 },
9233 4 => .ldr(if (mat.ra.isVector()) mat.ra.s() else mat.ra.w(), .{ .unsigned_offset = .{
9234 .base = base_mat.ra.x(),
9235 .offset = @intCast(offset),
9236 } }),
9237 8 => .ldr(if (mat.ra.isVector()) mat.ra.d() else mat.ra.x(), .{ .unsigned_offset = .{
9238 .base = base_mat.ra.x(),
9239 .offset = @intCast(offset),
9240 } }),
9241 16 => .ldr(mat.ra.q(), .{ .unsigned_offset = .{
9242 .base = base_mat.ra.x(),
9243 .offset = @intCast(offset),
9244 } }),
9245 });
9246 break :free try base_mat.finish(isel);9246 break :free try base_mat.finish(isel);
9247 },9247 },
9248 .value => |parent_vi| vi = parent_vi,9248 .value => |parent_vi| vi = parent_vi,
src/codegen/aarch64/encoding.zig+434-41
...@@ -1072,7 +1072,7 @@ pub const Register = struct {...@@ -1072,7 +1072,7 @@ pub const Register = struct {
1072 }1072 }
10731073
1074 pub fn parse(reg: []const u8) ?Register {1074 pub fn parse(reg: []const u8) ?Register {
1075 return if (reg.len == 0) null else switch (reg[0]) {1075 return if (reg.len == 0) null else switch (std.ascii.toLower(reg[0])) {
1076 else => null,1076 else => null,
1077 'r' => if (std.fmt.parseInt(u5, reg[1..], 10)) |n| switch (n) {1077 'r' => if (std.fmt.parseInt(u5, reg[1..], 10)) |n| switch (n) {
1078 0...30 => .{1078 0...30 => .{
...@@ -1087,27 +1087,27 @@ pub const Register = struct {...@@ -1087,27 +1087,27 @@ pub const Register = struct {
1087 .format = .{ .integer = .doubleword },1087 .format = .{ .integer = .doubleword },
1088 },1088 },
1089 31 => null,1089 31 => null,
1090 } else |_| if (std.mem.eql(u8, reg, "xzr")) .xzr else null,1090 } else |_| if (toLowerEqlAssertLower(reg, "xzr")) .xzr else null,
1091 'w' => if (std.fmt.parseInt(u5, reg[1..], 10)) |n| switch (n) {1091 'w' => if (std.fmt.parseInt(u5, reg[1..], 10)) |n| switch (n) {
1092 0...30 => .{1092 0...30 => .{
1093 .alias = @enumFromInt(@intFromEnum(Alias.r0) + n),1093 .alias = @enumFromInt(@intFromEnum(Alias.r0) + n),
1094 .format = .{ .integer = .word },1094 .format = .{ .integer = .word },
1095 },1095 },
1096 31 => null,1096 31 => null,
1097 } else |_| if (std.mem.eql(u8, reg, "wzr"))1097 } else |_| if (toLowerEqlAssertLower(reg, "wzr"))
1098 .wzr1098 .wzr
1099 else if (std.mem.eql(u8, reg, "wsp"))1099 else if (toLowerEqlAssertLower(reg, "wsp"))
1100 .wsp1100 .wsp
1101 else1101 else
1102 null,1102 null,
1103 'i' => return if (std.mem.eql(u8, reg, "ip") or std.mem.eql(u8, reg, "ip0"))1103 'i' => return if (toLowerEqlAssertLower(reg, "ip") or toLowerEqlAssertLower(reg, "ip0"))
1104 .ip01104 .ip0
1105 else if (std.mem.eql(u8, reg, "ip1"))1105 else if (toLowerEqlAssertLower(reg, "ip1"))
1106 .ip11106 .ip1
1107 else1107 else
1108 null,1108 null,
1109 'f' => return if (std.mem.eql(u8, reg, "fp")) .fp else null,1109 'f' => return if (toLowerEqlAssertLower(reg, "fp")) .fp else null,
1110 'p' => return if (std.mem.eql(u8, reg, "pc")) .pc else null,1110 'p' => return if (toLowerEqlAssertLower(reg, "pc")) .pc else null,
1111 'v' => if (std.fmt.parseInt(u5, reg[1..], 10)) |n| .{1111 'v' => if (std.fmt.parseInt(u5, reg[1..], 10)) |n| .{
1112 .alias = @enumFromInt(@intFromEnum(Alias.v0) + n),1112 .alias = @enumFromInt(@intFromEnum(Alias.v0) + n),
1113 .format = .alias,1113 .format = .alias,
...@@ -1123,7 +1123,7 @@ pub const Register = struct {...@@ -1123,7 +1123,7 @@ pub const Register = struct {
1123 's' => if (std.fmt.parseInt(u5, reg[1..], 10)) |n| .{1123 's' => if (std.fmt.parseInt(u5, reg[1..], 10)) |n| .{
1124 .alias = @enumFromInt(@intFromEnum(Alias.v0) + n),1124 .alias = @enumFromInt(@intFromEnum(Alias.v0) + n),
1125 .format = .{ .scalar = .single },1125 .format = .{ .scalar = .single },
1126 } else |_| if (std.mem.eql(u8, reg, "sp")) .sp else null,1126 } else |_| if (toLowerEqlAssertLower(reg, "sp")) .sp else null,
1127 'h' => if (std.fmt.parseInt(u5, reg[1..], 10)) |n| .{1127 'h' => if (std.fmt.parseInt(u5, reg[1..], 10)) |n| .{
1128 .alias = @enumFromInt(@intFromEnum(Alias.v0) + n),1128 .alias = @enumFromInt(@intFromEnum(Alias.v0) + n),
1129 .format = .{ .scalar = .half },1129 .format = .{ .scalar = .half },
...@@ -1141,6 +1141,422 @@ pub const Register = struct {...@@ -1141,6 +1141,422 @@ pub const Register = struct {
1141 pub fn fmtCase(reg: Register, case: aarch64.Disassemble.Case) aarch64.Disassemble.RegisterFormatter {1141 pub fn fmtCase(reg: Register, case: aarch64.Disassemble.Case) aarch64.Disassemble.RegisterFormatter {
1142 return .{ .reg = reg, .case = case };1142 return .{ .reg = reg, .case = case };
1143 }1143 }
1144
1145 pub const System = packed struct(u16) {
1146 op2: u3,
1147 CRm: u4,
1148 CRn: u4,
1149 op1: u3,
1150 op0: u2,
1151
1152 // D19.2 General system control registers
1153 /// D19.2.1 ACCDATA_EL1, Accelerator Data
1154 pub const accdata_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b101 };
1155 /// D19.2.2 ACTLR_EL1, Auxiliary Control Register (EL1)
1156 pub const actlr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b001 };
1157 /// D19.2.3 ACTLR_EL2, Auxiliary Control Register (EL2)
1158 pub const actlr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b001 };
1159 /// D19.2.4 ACTLR_EL3, Auxiliary Control Register (EL3)
1160 pub const actlr_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b001 };
1161 /// D19.2.5 AFSR0_EL1, Auxiliary Fault Status Register 0 (EL1)
1162 pub const afsr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0101, .CRm = 0b0001, .op2 = 0b000 };
1163 /// D19.2.5 AFSR0_EL12, Auxiliary Fault Status Register 0 (EL12)
1164 pub const afsr0_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0101, .CRm = 0b0001, .op2 = 0b000 };
1165 /// D19.2.6 AFSR0_EL2, Auxiliary Fault Status Register 0 (EL2)
1166 pub const afsr0_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0101, .CRm = 0b0001, .op2 = 0b000 };
1167 /// D19.2.7 AFSR0_EL3, Auxiliary Fault Status Register 0 (EL3)
1168 pub const afsr0_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0101, .CRm = 0b0001, .op2 = 0b000 };
1169 /// D19.2.8 AFSR1_EL1, Auxiliary Fault Status Register 1 (EL1)
1170 pub const afsr1_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0101, .CRm = 0b0001, .op2 = 0b001 };
1171 /// D19.2.8 AFSR1_EL12, Auxiliary Fault Status Register 1 (EL12)
1172 pub const afsr1_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0101, .CRm = 0b0001, .op2 = 0b001 };
1173 /// D19.2.9 AFSR1_EL2, Auxiliary Fault Status Register 1 (EL2)
1174 pub const afsr1_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0101, .CRm = 0b0001, .op2 = 0b001 };
1175 /// D19.2.10 AFSR1_EL3, Auxiliary Fault Status Register 1 (EL3)
1176 pub const afsr1_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0101, .CRm = 0b0001, .op2 = 0b001 };
1177 /// D19.2.11 AIDR_EL1, Auxiliary ID Register
1178 pub const aidr_el1: System = .{ .op0 = 0b11, .op1 = 0b001, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b111 };
1179 /// D19.2.12 AMAIR_EL1, Auxiliary Memory Attribute Indirection Register (EL1)
1180 pub const amair_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1010, .CRm = 0b0011, .op2 = 0b000 };
1181 /// D19.2.12 AMAIR_EL12, Auxiliary Memory Attribute Indirection Register (EL12)
1182 pub const amair_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b1010, .CRm = 0b0011, .op2 = 0b000 };
1183 /// D19.2.13 AMAIR_EL2, Auxiliary Memory Attribute Indirection Register (EL2)
1184 pub const amair_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b1010, .CRm = 0b0011, .op2 = 0b000 };
1185 /// D19.2.14 AMAIR_EL3, Auxiliary Memory Attribute Indirection Register (EL3)
1186 pub const amair_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b1010, .CRm = 0b0011, .op2 = 0b000 };
1187 /// D19.2.15 APDAKeyHi_EL1, Pointer Authentication Key A for Data (bits[127:64])
1188 pub const apdakeyhi_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0010, .op2 = 0b001 };
1189 /// D19.2.16 APDAKeyLo_EL1, Pointer Authentication Key A for Data (bits[63:0])
1190 pub const apdakeylo_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0010, .op2 = 0b000 };
1191 /// D19.2.17 APDBKeyHi_EL1, Pointer Authentication Key B for Data (bits[127:64])
1192 pub const apdbkeyhi_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0010, .op2 = 0b011 };
1193 /// D19.2.18 APDAKeyHi_EL1, Pointer Authentication Key B for Data (bits[63:0])
1194 pub const apdbkeylo_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0010, .op2 = 0b010 };
1195 /// D19.2.19 APGAKeyHi_EL1, Pointer Authentication Key A for Code (bits[127:64])
1196 pub const apgakeyhi_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0011, .op2 = 0b001 };
1197 /// D19.2.20 APGAKeyLo_EL1, Pointer Authentication Key A for Code (bits[63:0])
1198 pub const apgakeylo_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0011, .op2 = 0b000 };
1199 /// D19.2.21 APIAKeyHi_EL1, Pointer Authentication Key A for Instruction (bits[127:64])
1200 pub const apiakeyhi_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0001, .op2 = 0b001 };
1201 /// D19.2.22 APIAKeyLo_EL1, Pointer Authentication Key A for Instruction (bits[63:0])
1202 pub const apiakeylo_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0001, .op2 = 0b000 };
1203 /// D19.2.23 APIBKeyHi_EL1, Pointer Authentication Key B for Instruction (bits[127:64])
1204 pub const apibkeyhi_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0001, .op2 = 0b011 };
1205 /// D19.2.24 APIBKeyLo_EL1, Pointer Authentication Key B for Instruction (bits[63:0])
1206 pub const apibkeylo_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0001, .op2 = 0b010 };
1207 /// D19.2.25 CCSIDR2_EL1, Current Cache Size ID Register 2
1208 pub const ccsidr2_el1: System = .{ .op0 = 0b11, .op1 = 0b001, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b010 };
1209 /// D19.2.26 CCSIDR_EL1, Current Cache Size ID Register
1210 pub const ccsidr_el1: System = .{ .op0 = 0b11, .op1 = 0b001, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b000 };
1211 /// D19.2.27 CLIDR_EL1, Cache Level ID Register
1212 pub const clidr_el1: System = .{ .op0 = 0b11, .op1 = 0b001, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b001 };
1213 /// D19.2.28 CONTEXTIDR_EL1, Context ID Register (EL1)
1214 pub const contextidr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b001 };
1215 /// D19.2.28 CONTEXTIDR_EL12, Context ID Register (EL12)
1216 pub const contextidr_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b001 };
1217 /// D19.2.29 CONTEXTIDR_EL2, Context ID Register (EL2)
1218 pub const contextidr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b001 };
1219 /// D19.2.30 CPACR_EL1, Architectural Feature Access Control Register
1220 pub const cpacr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b010 };
1221 /// D19.2.30 CPACR_EL12, Architectural Feature Access Control Register
1222 pub const cpacr_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b010 };
1223 /// D19.2.31 CPACR_EL2, Architectural Feature Trap Register (EL2)
1224 pub const cptr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0001, .op2 = 0b010 };
1225 /// D19.2.32 CPACR_EL3, Architectural Feature Trap Register (EL3)
1226 pub const cptr_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0001, .CRm = 0b0001, .op2 = 0b010 };
1227 /// D19.2.33 CSSELR_EL1, Cache Size Selection Register
1228 pub const csselr_el1: System = .{ .op0 = 0b11, .op1 = 0b010, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b000 };
1229 /// D19.2.34 CTR_EL0, Cache Type Register
1230 pub const ctr_el0: System = .{ .op0 = 0b11, .op1 = 0b011, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b001 };
1231 /// D19.2.35 DACR32_EL2, Domain Access Control Register
1232 pub const dacr32_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0011, .CRm = 0b0000, .op2 = 0b000 };
1233 /// D19.2.36 DCZID_EL0, Data Cache Zero ID Register
1234 pub const dczid_el0: System = .{ .op0 = 0b11, .op1 = 0b011, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b111 };
1235 /// D19.2.37 ESR_EL1, Exception Syndrome Register (EL1)
1236 pub const esr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0101, .CRm = 0b0010, .op2 = 0b000 };
1237 /// D19.2.37 ESR_EL12, Exception Syndrome Register (EL12)
1238 pub const esr_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0101, .CRm = 0b0010, .op2 = 0b000 };
1239 /// D19.2.38 ESR_EL2, Exception Syndrome Register (EL2)
1240 pub const esr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0101, .CRm = 0b0010, .op2 = 0b000 };
1241 /// D19.2.39 ESR_EL3, Exception Syndrome Register (EL3)
1242 pub const esr_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0101, .CRm = 0b0010, .op2 = 0b000 };
1243 /// D19.2.40 FAR_EL1, Fault Address Register (EL1)
1244 pub const far_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0110, .CRm = 0b0000, .op2 = 0b000 };
1245 /// D19.2.40 FAR_EL12, Fault Address Register (EL12)
1246 pub const far_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0110, .CRm = 0b0000, .op2 = 0b000 };
1247 /// D19.2.41 FAR_EL2, Fault Address Register (EL2)
1248 pub const far_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0110, .CRm = 0b0000, .op2 = 0b000 };
1249 /// D19.2.42 FAR_EL3, Fault Address Register (EL3)
1250 pub const far_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0110, .CRm = 0b0000, .op2 = 0b000 };
1251 /// D19.2.43 FPEXC32_EL2, Floating-Point Exception Control Register
1252 pub const fpexc32_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0101, .CRm = 0b0011, .op2 = 0b000 };
1253 /// D19.2.44 GCR_EL1, Tag Control Register
1254 pub const gcr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b110 };
1255 /// D19.2.45 GMID_EL1, Tag Control Register
1256 pub const gmid_el1: System = .{ .op0 = 0b11, .op1 = 0b001, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b100 };
1257 /// D19.2.46 HACR_EL2, Hypervisor Auxiliary Control Register
1258 pub const hacr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0001, .op2 = 0b111 };
1259 /// D19.2.47 HAFGRTR_EL2, Hypervisor Activity Monitors Fine-Grained Read Trap Register
1260 pub const hafgrtr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0011, .CRm = 0b0001, .op2 = 0b110 };
1261 /// D19.2.48 HCR_EL2, Hypervisor Configuration Register
1262 pub const hcr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0001, .op2 = 0b000 };
1263 /// D19.2.49 HCRX_EL2, Extended Hypervisor Configuration Register
1264 pub const hcrx_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0010, .op2 = 0b010 };
1265 /// D19.2.50 HDFGRTR_EL2, Hypervisor Debug Fine-Grained Read Trap Register
1266 pub const hdfgrtr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0011, .CRm = 0b0001, .op2 = 0b100 };
1267 /// D19.2.51 HDFGWTR_EL2, Hypervisor Debug Fine-Grained Write Trap Register
1268 pub const hdfgwtr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0011, .CRm = 0b0001, .op2 = 0b101 };
1269 /// D19.2.52 HFGITR_EL2, Hypervisor Fine-Grained Instruction Trap Register
1270 pub const hfgitr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0001, .op2 = 0b110 };
1271 /// D19.2.53 HFGRTR_EL2, Hypervisor Fine-Grained Read Trap Register
1272 pub const hfgrtr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0001, .op2 = 0b100 };
1273 /// D19.2.54 HFGWTR_EL2, Hypervisor Fine-Grained Write Trap Register
1274 pub const hfgwtr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0001, .op2 = 0b101 };
1275 /// D19.2.55 HPFAR_EL2, Hypervisor IPA Fault Address Register
1276 pub const hpfar_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0110, .CRm = 0b0000, .op2 = 0b100 };
1277 /// D19.2.56 HSTR_EL2, Hypervisor System Trap Register
1278 pub const hstr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0001, .op2 = 0b011 };
1279 /// D19.2.57 ID_AA64AFR0_EL1, AArch64 Auxiliary Feature Register 0
1280 pub const id_aa64afr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0101, .op2 = 0b100 };
1281 /// D19.2.58 ID_AA64AFR1_EL1, AArch64 Auxiliary Feature Register 1
1282 pub const id_aa64afr1_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0101, .op2 = 0b101 };
1283 /// D19.2.59 ID_AA64DFR0_EL1, AArch64 Debug Feature Register 0
1284 pub const id_aa64dfr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0101, .op2 = 0b000 };
1285 /// D19.2.60 ID_AA64DFR1_EL1, AArch64 Debug Feature Register 1
1286 pub const id_aa64dfr1_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0101, .op2 = 0b001 };
1287 /// D19.2.61 ID_AA64ISAR0_EL1, AArch64 Instruction Set Attribute Register 0
1288 pub const id_aa64isar0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0110, .op2 = 0b000 };
1289 /// D19.2.62 ID_AA64ISAR1_EL1, AArch64 Instruction Set Attribute Register 1
1290 pub const id_aa64isar1_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0110, .op2 = 0b001 };
1291 /// D19.2.63 ID_AA64ISAR2_EL1, AArch64 Instruction Set Attribute Register 2
1292 pub const id_aa64isar2_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0110, .op2 = 0b010 };
1293 /// D19.2.64 ID_AA64MMFR0_EL1, AArch64 Memory Model Feature Register 0
1294 pub const id_aa64mmfr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0111, .op2 = 0b000 };
1295 /// D19.2.65 ID_AA64MMFR1_EL1, AArch64 Memory Model Feature Register 1
1296 pub const id_aa64mmfr1_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0111, .op2 = 0b001 };
1297 /// D19.2.66 ID_AA64MMFR2_EL1, AArch64 Memory Model Feature Register 2
1298 pub const id_aa64mmfr2_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0111, .op2 = 0b010 };
1299 /// D19.2.67 ID_AA64MMFR3_EL1, AArch64 Memory Model Feature Register 3
1300 pub const id_aa64mmfr3_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0111, .op2 = 0b011 };
1301 /// D19.2.68 ID_AA64MMFR4_EL1, AArch64 Memory Model Feature Register 4
1302 pub const id_aa64mmfr4_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0111, .op2 = 0b100 };
1303 /// D19.2.69 ID_AA64PFR0_EL1, AArch64 Processor Feature Register 0
1304 pub const id_aa64pfr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0100, .op2 = 0b000 };
1305 /// D19.2.70 ID_AA64PFR1_EL1, AArch64 Processor Feature Register 1
1306 pub const id_aa64pfr1_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0100, .op2 = 0b001 };
1307 /// D19.2.71 ID_AA64PFR2_EL1, AArch64 Processor Feature Register 2
1308 pub const id_aa64pfr2_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0100, .op2 = 0b010 };
1309 /// D19.2.72 ID_AA64SMFR0_EL1, SME Feature ID Register 0
1310 pub const id_aa64smfr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0100, .op2 = 0b101 };
1311 /// D19.2.73 ID_AA64ZFR0_EL1, SVE Feature ID Register 0
1312 pub const id_aa64zfr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0100, .op2 = 0b100 };
1313 /// D19.2.74 ID_AFR0_EL1, AArch32 Auxiliary Feature Register 0
1314 pub const id_afr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0001, .op2 = 0b011 };
1315 /// D19.2.75 ID_DFR0_EL1, AArch32 Debug Feature Register 0
1316 pub const id_dfr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0001, .op2 = 0b010 };
1317 /// D19.2.76 ID_DFR1_EL1, AArch32 Debug Feature Register 1
1318 pub const id_dfr1_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0011, .op2 = 0b101 };
1319 /// D19.2.77 ID_ISAR0_EL1, AArch32 Instruction Set Attribute Register 0
1320 pub const id_isar0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0010, .op2 = 0b000 };
1321 /// D19.2.78 ID_ISAR1_EL1, AArch32 Instruction Set Attribute Register 1
1322 pub const id_isar1_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0010, .op2 = 0b001 };
1323 /// D19.2.79 ID_ISAR2_EL1, AArch32 Instruction Set Attribute Register 2
1324 pub const id_isar2_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0010, .op2 = 0b010 };
1325 /// D19.2.80 ID_ISAR3_EL1, AArch32 Instruction Set Attribute Register 3
1326 pub const id_isar3_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0010, .op2 = 0b011 };
1327 /// D19.2.81 ID_ISAR4_EL1, AArch32 Instruction Set Attribute Register 4
1328 pub const id_isar4_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0010, .op2 = 0b100 };
1329 /// D19.2.82 ID_ISAR5_EL1, AArch32 Instruction Set Attribute Register 5
1330 pub const id_isar5_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0010, .op2 = 0b101 };
1331 /// D19.2.83 ID_ISAR6_EL1, AArch32 Instruction Set Attribute Register 6
1332 pub const id_isar6_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0010, .op2 = 0b111 };
1333 /// D19.2.84 ID_MMFR0_EL1, AArch32 Memory Model Feature Register 0
1334 pub const id_mmfr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0001, .op2 = 0b100 };
1335 /// D19.2.85 ID_MMFR1_EL1, AArch32 Memory Model Feature Register 1
1336 pub const id_mmfr1_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0001, .op2 = 0b101 };
1337 /// D19.2.86 ID_MMFR2_EL1, AArch32 Memory Model Feature Register 2
1338 pub const id_mmfr2_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0001, .op2 = 0b110 };
1339 /// D19.2.87 ID_MMFR3_EL1, AArch32 Memory Model Feature Register 3
1340 pub const id_mmfr3_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0001, .op2 = 0b111 };
1341 /// D19.2.88 ID_MMFR4_EL1, AArch32 Memory Model Feature Register 4
1342 pub const id_mmfr4_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0010, .op2 = 0b110 };
1343 /// D19.2.89 ID_MMFR5_EL1, AArch32 Memory Model Feature Register 5
1344 pub const id_mmfr5_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0011, .op2 = 0b110 };
1345 /// D19.2.90 ID_PFR0_EL1, AArch32 Processor Feature Register 0
1346 pub const id_pfr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0001, .op2 = 0b000 };
1347 /// D19.2.91 ID_PFR1_EL1, AArch32 Processor Feature Register 1
1348 pub const id_pfr1_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0001, .op2 = 0b001 };
1349 /// D19.2.92 ID_PFR2_EL1, AArch32 Processor Feature Register 2
1350 pub const id_pfr2_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0011, .op2 = 0b100 };
1351 /// D19.2.93 IFSR32_EL2, Instruction Fault Status Register (EL2)
1352 pub const ifsr32_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0101, .CRm = 0b0000, .op2 = 0b001 };
1353 /// D19.2.94 ISR_EL1, Interrupt Status Register
1354 pub const isr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1100, .CRm = 0b0001, .op2 = 0b000 };
1355 /// D19.2.95 LORC_EL1, LORegion Control (EL1)
1356 pub const lorc_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1010, .CRm = 0b0100, .op2 = 0b011 };
1357 /// D19.2.96 LOREA_EL1, LORegion End Address (EL1)
1358 pub const lorea_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1010, .CRm = 0b0100, .op2 = 0b001 };
1359 /// D19.2.97 SORID_EL1, LORegionID (EL1)
1360 pub const lorid_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1010, .CRm = 0b0100, .op2 = 0b111 };
1361 /// D19.2.98 LORN_EL1, LORegion Number (EL1)
1362 pub const lorn_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1010, .CRm = 0b0100, .op2 = 0b010 };
1363 /// D19.2.99 LORSA_EL1, LORegion Start Address (EL1)
1364 pub const lorsa_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1010, .CRm = 0b0100, .op2 = 0b000 };
1365 /// D19.2.100 MAIR_EL1, Memory Attribute Indirection Register (EL1)
1366 pub const mair_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1010, .CRm = 0b0010, .op2 = 0b000 };
1367 /// D19.2.100 MAIR_EL12, Memory Attribute Indirection Register (EL12)
1368 pub const mair_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b1010, .CRm = 0b0010, .op2 = 0b000 };
1369 /// D19.2.101 MAIR_EL2, Memory Attribute Indirection Register (EL2)
1370 pub const mair_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b1010, .CRm = 0b0010, .op2 = 0b000 };
1371 /// D19.2.102 MAIR_EL3, Memory Attribute Indirection Register (EL3)
1372 pub const mair_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b1010, .CRm = 0b0010, .op2 = 0b000 };
1373 /// D19.2.103 MIDR_EL1, Main ID Register
1374 pub const midr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b000 };
1375 /// D19.2.104 MPIDR_EL1, Multiprocessor Affinity Register
1376 pub const mpidr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b101 };
1377 /// D19.2.105 MVFR0_EL1, AArch32 Media and VFP Feature Register 0
1378 pub const mvfr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0011, .op2 = 0b000 };
1379 /// D19.2.106 MVFR1_EL1, AArch32 Media and VFP Feature Register 1
1380 pub const mvfr1_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0011, .op2 = 0b001 };
1381 /// D19.2.107 MVFR2_EL1, AArch32 Media and VFP Feature Register 2
1382 pub const mvfr2_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0011, .op2 = 0b010 };
1383 /// D19.2.108 PAR_EL1, Physical Address Register
1384 pub const par_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0111, .CRm = 0b0100, .op2 = 0b000 };
1385 /// D19.2.109 REVIDR_EL1, Revision ID Register
1386 pub const revidr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b110 };
1387 /// D19.2.110 RGSR_EL1, Random Allocation Tag Seed Register
1388 pub const rgsr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b101 };
1389 /// D19.2.111 RMR_EL1, Reset Management Register (EL1)
1390 pub const rmr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1100, .CRm = 0b0000, .op2 = 0b010 };
1391 /// D19.2.112 RMR_EL2, Reset Management Register (EL2)
1392 pub const rmr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b1100, .CRm = 0b0000, .op2 = 0b010 };
1393 /// D19.2.113 RMR_EL3, Reset Management Register (EL3)
1394 pub const rmr_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b1100, .CRm = 0b0000, .op2 = 0b010 };
1395 /// D19.2.114 RNDR, Random Number
1396 pub const rndr: System = .{ .op0 = 0b11, .op1 = 0b011, .CRn = 0b0010, .CRm = 0b0100, .op2 = 0b000 };
1397 /// D19.2.115 RNDRRS, Reseeded Random Number
1398 pub const rndrrs: System = .{ .op0 = 0b11, .op1 = 0b011, .CRn = 0b0010, .CRm = 0b0100, .op2 = 0b001 };
1399 /// D19.2.116 RVBAR_EL1, Reset Vector Base Address Register (if EL2 and EL3 not implemented)
1400 pub const rvbar_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1100, .CRm = 0b0000, .op2 = 0b001 };
1401 /// D19.2.117 RVBAR_EL2, Reset Vector Base Address Register (if EL3 not implemented)
1402 pub const rvbar_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b1100, .CRm = 0b0000, .op2 = 0b001 };
1403 /// D19.2.118 RVBAR_EL3, Reset Vector Base Address Register (if EL3 implemented)
1404 pub const rvbar_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b1100, .CRm = 0b0000, .op2 = 0b001 };
1405 /// D19.2.120 SCR_EL3, Secure Configuration Register
1406 pub const scr_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0001, .CRm = 0b0001, .op2 = 0b000 };
1407 /// D19.2.121 SCTLR2_EL1, System Control Register (EL1)
1408 pub const sctlr2_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b011 };
1409 /// D19.2.121 SCTLR2_EL12, System Control Register (EL12)
1410 pub const sctlr2_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b011 };
1411 /// D19.2.122 SCTLR2_EL2, System Control Register (EL2)
1412 pub const sctlr2_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b011 };
1413 /// D19.2.123 SCTLR2_EL3, System Control Register (EL3)
1414 pub const sctlr2_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b011 };
1415 /// D19.2.124 SCTLR_EL1, System Control Register (EL1)
1416 pub const sctlr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b000 };
1417 /// D19.2.124 SCTLR_EL12, System Control Register (EL12)
1418 pub const sctlr_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b000 };
1419 /// D19.2.125 SCTLR_EL2, System Control Register (EL2)
1420 pub const sctlr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b000 };
1421 /// D19.2.126 SCTLR_EL3, System Control Register (EL3)
1422 pub const sctlr_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b000 };
1423 /// D19.2.127 SCXTNUM_EL0, EL0 Read/Write Software Context Number
1424 pub const scxtnum_el0: System = .{ .op0 = 0b11, .op1 = 0b011, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b111 };
1425 /// D19.2.128 SCXTNUM_EL1, EL1 Read/Write Software Context Number
1426 pub const scxtnum_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b111 };
1427 /// D19.2.128 SCXTNUM_EL12, EL12 Read/Write Software Context Number
1428 pub const scxtnum_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b111 };
1429 /// D19.2.129 SCXTNUM_EL2, EL2 Read/Write Software Context Number
1430 pub const scxtnum_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b111 };
1431 /// D19.2.130 SCXTNUM_EL3, EL3 Read/Write Software Context Number
1432 pub const scxtnum_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b111 };
1433 /// D19.2.131 SMCR_EL1, SME Control Register (EL1)
1434 pub const smcr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0001, .CRm = 0b0010, .op2 = 0b110 };
1435 /// D19.2.131 SMCR_EL12, SME Control Register (EL12)
1436 pub const smcr_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0001, .CRm = 0b0010, .op2 = 0b110 };
1437 /// D19.2.132 SMCR_EL2, SME Control Register (EL2)
1438 pub const smcr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0010, .op2 = 0b110 };
1439 /// D19.2.133 SMCR_EL3, SME Control Register (EL3)
1440 pub const smcr_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0001, .CRm = 0b0010, .op2 = 0b110 };
1441 /// D19.2.134 SMIDR_EL1, Streaming Mode Identification Register
1442 pub const smidr_el1: System = .{ .op0 = 0b11, .op1 = 0b001, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b110 };
1443 /// D19.2.135 SMPRIMAP_EL2, Streaming Mode Priority Mapping Register
1444 pub const smprimap_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0010, .op2 = 0b101 };
1445 /// D19.2.136 SMPRI_EL1, Streaming Mode Priority Register
1446 pub const smpri_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0001, .CRm = 0b0010, .op2 = 0b100 };
1447 /// D19.2.137 TCR2_EL1, Extended Translation Control Register (EL1)
1448 pub const tcr2_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b011 };
1449 /// D19.2.137 TCR2_EL12, Extended Translation Control Register (EL12)
1450 pub const tcr2_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b011 };
1451 /// D19.2.138 TCR2_EL2, Extended Translation Control Register (EL2)
1452 pub const tcr2_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b011 };
1453 /// D19.2.139 TCR_EL1, Translation Control Register (EL1)
1454 pub const tcr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b010 };
1455 /// D19.2.139 TCR_EL12, Translation Control Register (EL12)
1456 pub const tcr_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b010 };
1457 /// D19.2.140 TCR_EL2, Translation Control Register (EL2)
1458 pub const tcr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b010 };
1459 /// D19.2.141 TCR_EL3, Translation Control Register (EL3)
1460 pub const tcr_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b010 };
1461 /// D19.2.142 TFSRE0_EL1, Tag Fault Status Register (EL0)
1462 pub const tfsre0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0101, .CRm = 0b0110, .op2 = 0b001 };
1463 /// D19.2.143 TFSR_EL1, Tag Fault Status Register (EL1)
1464 pub const tfsr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0101, .CRm = 0b0110, .op2 = 0b000 };
1465 /// D19.2.143 TFSR_EL12, Tag Fault Status Register (EL12)
1466 pub const tfsr_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0101, .CRm = 0b0110, .op2 = 0b000 };
1467 /// D19.2.144 TFSR_EL2, Tag Fault Status Register (EL2)
1468 pub const tfsr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0101, .CRm = 0b0110, .op2 = 0b000 };
1469 /// D19.2.145 TFSR_EL3, Tag Fault Status Register (EL3)
1470 pub const tfsr_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0101, .CRm = 0b0110, .op2 = 0b000 };
1471 /// D19.2.146 TPIDR2_EL0, EL0 Read/Write Software Thread ID Register 2
1472 pub const tpidr2_el0: System = .{ .op0 = 0b11, .op1 = 0b011, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b101 };
1473 /// D19.2.147 TPIDR_EL0, EL0 Read/Write Software Thread ID Register
1474 pub const tpidr_el0: System = .{ .op0 = 0b11, .op1 = 0b011, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b010 };
1475 /// D19.2.148 TPIDR_EL1, EL1 Read/Write Software Thread ID Register
1476 pub const tpidr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b100 };
1477 /// D19.2.149 TPIDR_EL2, EL2 Read/Write Software Thread ID Register
1478 pub const tpidr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b010 };
1479 /// D19.2.150 TPIDR_EL3, EL3 Read/Write Software Thread ID Register
1480 pub const tpidr_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b010 };
1481 /// D19.2.151 TPIDRRO_EL0, EL0 Read-Only Software Thread ID Register
1482 pub const tpidrro_el3: System = .{ .op0 = 0b11, .op1 = 0b011, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b011 };
1483 /// D19.2.152 TTBR0_EL1, Translation Table Base Register 0 (EL1)
1484 pub const ttbr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b000 };
1485 /// D19.2.152 TTBR0_EL12, Translation Table Base Register 0 (EL12)
1486 pub const ttbr0_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b000 };
1487 /// D19.2.153 TTBR0_EL2, Translation Table Base Register 0 (EL2)
1488 pub const ttbr0_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b000 };
1489 /// D19.2.154 TTBR0_EL3, Translation Table Base Register 0 (EL3)
1490 pub const ttbr0_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b000 };
1491 /// D19.2.155 TTBR1_EL1, Translation Table Base Register 1 (EL1)
1492 pub const ttbr1_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b001 };
1493 /// D19.2.155 TTBR1_EL12, Translation Table Base Register 1 (EL12)
1494 pub const ttbr1_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b001 };
1495 /// D19.2.156 TTBR1_EL2, Translation Table Base Register 1 (EL2)
1496 pub const ttbr1_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b001 };
1497 /// D19.2.157 VBAR_EL1, Vector Base Address Register (EL1)
1498 pub const vbar_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1100, .CRm = 0b0000, .op2 = 0b000 };
1499 /// D19.2.157 VBAR_EL12, Vector Base Address Register (EL12)
1500 pub const vbar_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b1100, .CRm = 0b0000, .op2 = 0b000 };
1501 /// D19.2.158 VBAR_EL2, Vector Base Address Register (EL2)
1502 pub const vbar_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b1100, .CRm = 0b0000, .op2 = 0b000 };
1503 /// D19.2.159 VBAR_EL3, Vector Base Address Register (EL3)
1504 pub const vbar_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b1100, .CRm = 0b0000, .op2 = 0b000 };
1505 /// D19.2.160 VMPIDR_EL2, Virtualization Multiprocessor ID Register
1506 pub const vmpidr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b101 };
1507 /// D19.2.161 VNCR_EL2, Virtual Nested Control Register
1508 pub const nvcr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0010, .CRm = 0b0010, .op2 = 0b000 };
1509 /// D19.2.162 VPIDR_EL2, Virtualization Processor ID Register
1510 pub const vpidr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b000 };
1511 /// D19.2.163 VSTCR_EL2, Virtualization Secure Translation Control Register
1512 pub const vstcr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0010, .CRm = 0b0110, .op2 = 0b010 };
1513 /// D19.2.164 VSTTBR_EL2, Virtualization Secure Translation Table Base Register
1514 pub const vsttbr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0010, .CRm = 0b0110, .op2 = 0b000 };
1515 /// D19.2.165 VTCR_EL2, Virtualization Translation Control Register
1516 pub const vtcr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0010, .CRm = 0b0001, .op2 = 0b010 };
1517 /// D19.2.166 VTTBR_EL2, Virtualization Translation Table Base Register
1518 pub const vttbr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0010, .CRm = 0b0001, .op2 = 0b000 };
1519 /// D19.2.167 ZCR_EL1, SVE Control Register (EL1)
1520 pub const zcr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0001, .CRm = 0b0010, .op2 = 0b000 };
1521 /// D19.2.167 ZCR_EL12, SVE Control Register (EL12)
1522 pub const zcr_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0001, .CRm = 0b0010, .op2 = 0b000 };
1523 /// D19.2.168 ZCR_EL2, SVE Control Register (EL2)
1524 pub const zcr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0010, .op2 = 0b000 };
1525 /// D19.2.169 ZCR_EL3, SVE Control Register (EL3)
1526 pub const zcr_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0001, .CRm = 0b0010, .op2 = 0b000 };
1527
1528 pub fn parse(reg: []const u8) ?System {
1529 if (reg.len >= 10 and std.ascii.toLower(reg[0]) == 's') encoded: {
1530 var symbol_it = std.mem.splitScalar(u8, reg[1..], '_');
1531 const op0 = std.fmt.parseInt(u2, symbol_it.next() orelse break :encoded, 10) catch break :encoded;
1532 if (op0 < 0b10) break :encoded;
1533 const op1 = std.fmt.parseInt(u3, symbol_it.next() orelse break :encoded, 10) catch break :encoded;
1534 const n = symbol_it.next() orelse break :encoded;
1535 if (n.len == 0 or std.ascii.toLower(n[0]) != 'c') break :encoded;
1536 const CRn = std.fmt.parseInt(u4, n[1..], 10) catch break :encoded;
1537 const m = symbol_it.next() orelse break :encoded;
1538 if (m.len == 0 or std.ascii.toLower(m[0]) != 'c') break :encoded;
1539 const CRm = std.fmt.parseInt(u4, m[1..], 10) catch break :encoded;
1540 const op2 = std.fmt.parseInt(u3, symbol_it.next() orelse break :encoded, 10) catch break :encoded;
1541 if (symbol_it.next() != null) break :encoded;
1542 return .{ .op0 = op0, .op1 = op1, .CRn = CRn, .CRm = CRm, .op2 = op2 };
1543 }
1544 inline for (@typeInfo(System).@"struct".decls) |decl| {
1545 if (@TypeOf(@field(System, decl.name)) != System) continue;
1546 if (toLowerEqlAssertLower(reg, decl.name)) return @field(System, decl.name);
1547 }
1548 return null;
1549 }
1550 };
1551
1552 fn toLowerEqlAssertLower(lhs: []const u8, rhs: []const u8) bool {
1553 if (lhs.len != rhs.len) return false;
1554 for (lhs, rhs) |l, r| {
1555 assert(!std.ascii.isUpper(r));
1556 if (std.ascii.toLower(l) != r) return false;
1557 }
1558 return true;
1559 }
1144};1560};
11451561
1146/// C1.2.4 Condition code1562/// C1.2.4 Condition code
...@@ -2385,12 +2801,7 @@ pub const Instruction = packed union {...@@ -2385,12 +2801,7 @@ pub const Instruction = packed union {
23852801
2386 pub const Group = packed struct {2802 pub const Group = packed struct {
2387 Rt: Register.Encoded,2803 Rt: Register.Encoded,
2388 op2: u3,2804 systemreg: Register.System,
2389 CRm: u4,
2390 CRn: u4,
2391 op1: u3,
2392 o0: u1,
2393 decoded20: u1 = 0b1,
2394 L: L,2805 L: L,
2395 decoded22: u10 = 0b1101010100,2806 decoded22: u10 = 0b1101010100,
2396 };2807 };
...@@ -2398,12 +2809,7 @@ pub const Instruction = packed union {...@@ -2398,12 +2809,7 @@ pub const Instruction = packed union {
2398 /// C6.2.230 MSR (register)2809 /// C6.2.230 MSR (register)
2399 pub const Msr = packed struct {2810 pub const Msr = packed struct {
2400 Rt: Register.Encoded,2811 Rt: Register.Encoded,
2401 op2: u3,2812 systemreg: Register.System,
2402 CRm: u4,
2403 CRn: u4,
2404 op1: u3,
2405 o0: u1,
2406 decoded20: u1 = 0b1,
2407 L: L = .msr,2813 L: L = .msr,
2408 decoded22: u10 = 0b1101010100,2814 decoded22: u10 = 0b1101010100,
2409 };2815 };
...@@ -2411,12 +2817,7 @@ pub const Instruction = packed union {...@@ -2411,12 +2817,7 @@ pub const Instruction = packed union {
2411 /// C6.2.228 MRS2817 /// C6.2.228 MRS
2412 pub const Mrs = packed struct {2818 pub const Mrs = packed struct {
2413 Rt: Register.Encoded,2819 Rt: Register.Encoded,
2414 op2: u3,2820 systemreg: Register.System,
2415 CRm: u4,
2416 CRn: u4,
2417 op1: u3,
2418 o0: u1,
2419 decoded20: u1 = 0b1,
2420 L: L = .mrs,2821 L: L = .mrs,
2421 decoded22: u10 = 0b1101010100,2822 decoded22: u10 = 0b1101010100,
2422 };2823 };
...@@ -10585,30 +10986,22 @@ pub const Instruction = packed union {...@@ -10585,30 +10986,22 @@ pub const Instruction = packed union {
10585 } } };10986 } } };
10586 }10987 }
10587 /// C6.2.228 MRS10988 /// C6.2.228 MRS
10588 pub fn mrs(t: Register, op0: u2, op1: u3, n: u4, m: u4, op2: u3) Instruction {10989 pub fn mrs(t: Register, systemreg: Register.System) Instruction {
10589 assert(t.format.integer == .doubleword);10990 assert(t.format.integer == .doubleword and systemreg.op0 >= 0b10);
10590 return .{ .branch_exception_generating_system = .{ .system_register_move = .{10991 return .{ .branch_exception_generating_system = .{ .system_register_move = .{
10591 .mrs = .{10992 .mrs = .{
10592 .Rt = t.alias.encode(.{}),10993 .Rt = t.alias.encode(.{}),
10593 .op2 = op2,10994 .systemreg = systemreg,
10594 .CRm = m,
10595 .CRn = n,
10596 .op1 = op1,
10597 .o0 = @intCast(op0 - 0b10),
10598 },10995 },
10599 } } };10996 } } };
10600 }10997 }
10601 /// C6.2.230 MSR (register)10998 /// C6.2.230 MSR (register)
10602 pub fn msr(op0: u2, op1: u3, n: u4, m: u4, op2: u3, t: Register) Instruction {10999 pub fn msr(systemreg: Register.System, t: Register) Instruction {
10603 assert(t.format.integer == .doubleword);11000 assert(systemreg.op0 >= 0b10 and t.format.integer == .doubleword);
10604 return .{ .branch_exception_generating_system = .{ .system_register_move = .{11001 return .{ .branch_exception_generating_system = .{ .system_register_move = .{
10605 .msr = .{11002 .msr = .{
10606 .Rt = t.alias.encode(.{}),11003 .Rt = t.alias.encode(.{}),
10607 .op2 = op2,11004 .systemreg = systemreg,
10608 .CRm = m,
10609 .CRn = n,
10610 .op1 = op1,
10611 .o0 = @intCast(op0 - 0b10),
10612 },11005 },
10613 } } };11006 } } };
10614 }11007 }
src/codegen/aarch64/instructions.zon+12-2
...@@ -851,11 +851,21 @@...@@ -851,11 +851,21 @@
851 },851 },
852 // C6.2.228 MRS852 // C6.2.228 MRS
853 .{853 .{
854 .pattern = "MRS <Xt>, CTR_EL0",854 .pattern = "MRS <Xt>, <systemreg>",
855 .symbols = .{855 .symbols = .{
856 .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } },856 .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
857 .systemreg = .systemreg,
857 },858 },
858 .encode = .{ .mrs, .Xt, 0b11, 0b011, 0b0000, 0b0000, 0b001 },859 .encode = .{ .mrs, .Xt, .systemreg },
860 },
861 // C6.2.230 MSR (register)
862 .{
863 .pattern = "MSR <systemreg>, <Xt>",
864 .symbols = .{
865 .systemreg = .systemreg,
866 .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
867 },
868 .encode = .{ .msr, .systemreg, .Xt },
859 },869 },
860 // C6.2.234 NEG870 // C6.2.234 NEG
861 .{871 .{
src/main.zig+92-54
...@@ -4648,14 +4648,14 @@ const usage_init =...@@ -4648,14 +4648,14 @@ const usage_init =
4648fn cmdInit(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {4648fn cmdInit(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
4649 dev.check(.init_command);4649 dev.check(.init_command);
46504650
4651 var strip = false;4651 var template: enum { example, minimal } = .example;
4652 {4652 {
4653 var i: usize = 0;4653 var i: usize = 0;
4654 while (i < args.len) : (i += 1) {4654 while (i < args.len) : (i += 1) {
4655 const arg = args[i];4655 const arg = args[i];
4656 if (mem.startsWith(u8, arg, "-")) {4656 if (mem.startsWith(u8, arg, "-")) {
4657 if (mem.eql(u8, arg, "-s") or mem.eql(u8, arg, "--strip")) {4657 if (mem.eql(u8, arg, "-m") or mem.eql(u8, arg, "--minimal")) {
4658 strip = true;4658 template = .minimal;
4659 } else if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) {4659 } else if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) {
4660 try fs.File.stdout().writeAll(usage_init);4660 try fs.File.stdout().writeAll(usage_init);
4661 return cleanExit();4661 return cleanExit();
...@@ -4668,40 +4668,79 @@ fn cmdInit(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {...@@ -4668,40 +4668,79 @@ fn cmdInit(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
4668 }4668 }
4669 }4669 }
46704670
4671 var templates = findTemplates(gpa, arena, strip);
4672 defer templates.deinit();
4673
4674 const cwd_path = try introspect.getResolvedCwd(arena);4671 const cwd_path = try introspect.getResolvedCwd(arena);
4675 const cwd_basename = fs.path.basename(cwd_path);4672 const cwd_basename = fs.path.basename(cwd_path);
4676 const sanitized_root_name = try sanitizeExampleName(arena, cwd_basename);4673 const sanitized_root_name = try sanitizeExampleName(arena, cwd_basename);
46774674
4678 const s = fs.path.sep_str;
4679 const template_paths = [_][]const u8{
4680 Package.build_zig_basename,
4681 Package.Manifest.basename,
4682 "src" ++ s ++ "main.zig",
4683 "src" ++ s ++ "root.zig",
4684 };
4685 var ok_count: usize = 0;
4686
4687 const fingerprint: Package.Fingerprint = .generate(sanitized_root_name);4675 const fingerprint: Package.Fingerprint = .generate(sanitized_root_name);
46884676
4689 for (template_paths) |template_path| {4677 switch (template) {
4690 if (templates.write(arena, fs.cwd(), sanitized_root_name, template_path, fingerprint)) |_| {4678 .example => {
4691 std.log.info("created {s}", .{template_path});4679 var templates = findTemplates(gpa, arena);
4692 ok_count += 1;4680 defer templates.deinit();
4693 } else |err| switch (err) {4681
4694 error.PathAlreadyExists => std.log.info("preserving already existing file: {s}", .{4682 const s = fs.path.sep_str;
4695 template_path,4683 const template_paths = [_][]const u8{
4696 }),4684 Package.build_zig_basename,
4697 else => std.log.err("unable to write {s}: {s}\n", .{ template_path, @errorName(err) }),4685 Package.Manifest.basename,
4698 }4686 "src" ++ s ++ "main.zig",
4699 }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 }
47004702
4701 if (ok_count == template_paths.len) {4703 if (ok_count == template_paths.len) {
4702 std.log.info("see `zig build --help` for a menu of options", .{});4704 std.log.info("see `zig build --help` for a menu of options", .{});
4705 }
4706 return cleanExit();
4707 },
4708 .minimal => {
4709 writeSimpleTemplateFile(Package.Manifest.basename,
4710 \\.{{
4711 \\ .name = .{s},
4712 \\ .version = "{s}",
4713 \\ .paths = .{{""}},
4714 \\ .fingerprint = 0x{x},
4715 \\}}
4716 \\
4717 , .{
4718 sanitized_root_name,
4719 build_options.version,
4720 fingerprint.int(),
4721 }) catch |err| switch (err) {
4722 else => fatal("failed to create '{s}': {s}", .{ Package.Manifest.basename, @errorName(err) }),
4723 error.PathAlreadyExists => fatal("refusing to overwrite '{s}'", .{Package.Manifest.basename}),
4724 };
4725 writeSimpleTemplateFile(Package.build_zig_basename,
4726 \\const std = @import("std");
4727 \\pub fn build(b: *std.Build) void {{
4728 \\ _ = b; // stub
4729 \\}}
4730 \\
4731 , .{}) catch |err| switch (err) {
4732 else => fatal("failed to create '{s}': {s}", .{ Package.build_zig_basename, @errorName(err) }),
4733 // `build.zig` already existing is okay: the user has just used `zig init` to set up
4734 // their `build.zig.zon` *after* writing their `build.zig`. So this one isn't fatal.
4735 error.PathAlreadyExists => {
4736 std.log.info("successfully populated '{s}', preserving existing '{s}'", .{ Package.Manifest.basename, Package.build_zig_basename });
4737 return cleanExit();
4738 },
4739 };
4740 std.log.info("successfully populated '{s}' and '{s}'", .{ Package.Manifest.basename, Package.build_zig_basename });
4741 return cleanExit();
4742 },
4703 }4743 }
4704 return cleanExit();
4705}4744}
47064745
4707fn sanitizeExampleName(arena: Allocator, bytes: []const u8) error{OutOfMemory}![]const u8 {4746fn sanitizeExampleName(arena: Allocator, bytes: []const u8) error{OutOfMemory}![]const u8 {
...@@ -7229,13 +7268,20 @@ fn loadManifest(...@@ -7229,13 +7268,20 @@ fn loadManifest(
7229 0,7268 0,
7230 ) catch |err| switch (err) {7269 ) catch |err| switch (err) {
7231 error.FileNotFound => {7270 error.FileNotFound => {
7232 const fingerprint: Package.Fingerprint = .generate(options.root_name);7271 writeSimpleTemplateFile(Package.Manifest.basename,
7233 var templates = findTemplates(gpa, arena, true);7272 \\.{{
7234 defer templates.deinit();7273 \\ .name = .{s},
7235 templates.write(arena, options.dir, options.root_name, Package.Manifest.basename, fingerprint) catch |e| {7274 \\ .version = "{s}",
7236 fatal("unable to write {s}: {s}", .{7275 \\ .paths = .{{""}},
7237 Package.Manifest.basename, @errorName(e),7276 \\ .fingerprint = 0x{x},
7238 });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) });
7239 };7285 };
7240 continue;7286 continue;
7241 },7287 },
...@@ -7276,7 +7322,6 @@ const Templates = struct {...@@ -7276,7 +7322,6 @@ const Templates = struct {
7276 zig_lib_directory: Cache.Directory,7322 zig_lib_directory: Cache.Directory,
7277 dir: fs.Dir,7323 dir: fs.Dir,
7278 buffer: std.ArrayList(u8),7324 buffer: std.ArrayList(u8),
7279 strip: bool,
72807325
7281 fn deinit(templates: *Templates) void {7326 fn deinit(templates: *Templates) void {
7282 templates.zig_lib_directory.handle.close();7327 templates.zig_lib_directory.handle.close();
...@@ -7305,23 +7350,9 @@ const Templates = struct {...@@ -7305,23 +7350,9 @@ const Templates = struct {
7305 };7350 };
7306 templates.buffer.clearRetainingCapacity();7351 templates.buffer.clearRetainingCapacity();
7307 try templates.buffer.ensureUnusedCapacity(contents.len);7352 try templates.buffer.ensureUnusedCapacity(contents.len);
7308 var new_line = templates.strip;
7309 var i: usize = 0;7353 var i: usize = 0;
7310 while (i < contents.len) {7354 while (i < contents.len) {
7311 if (new_line) {7355 if (contents[i] == '_' or contents[i] == '.') {
7312 const trimmed = std.mem.trimLeft(u8, contents[i..], " ");
7313 if (std.mem.startsWith(u8, trimmed, "//")) {
7314 i += std.mem.indexOfScalar(u8, contents[i..], '\n') orelse break;
7315 i += 1;
7316 continue;
7317 } else {
7318 new_line = false;
7319 }
7320 }
7321
7322 if (templates.strip and contents[i] == '\n') {
7323 new_line = true;
7324 } else if (contents[i] == '_' or contents[i] == '.') {
7325 // Both '_' and '.' are allowed because depending on the context7356 // Both '_' and '.' are allowed because depending on the context
7326 // one prefix will be valid, while the other might not.7357 // one prefix will be valid, while the other might not.
7327 if (std.mem.startsWith(u8, contents[i + 1 ..], "NAME")) {7358 if (std.mem.startsWith(u8, contents[i + 1 ..], "NAME")) {
...@@ -7350,8 +7381,16 @@ const Templates = struct {...@@ -7350,8 +7381,16 @@ const Templates = struct {
7350 });7381 });
7351 }7382 }
7352};7383};
7384fn writeSimpleTemplateFile(file_name: []const u8, comptime fmt: []const u8, args: anytype) !void {
7385 const f = try fs.cwd().createFile(file_name, .{ .exclusive = true });
7386 defer f.close();
7387 var buf: [4096]u8 = undefined;
7388 var fw = f.writer(&buf);
7389 try fw.interface.print(fmt, args);
7390 try fw.interface.flush();
7391}
73537392
7354fn findTemplates(gpa: Allocator, arena: Allocator, strip: bool) Templates {7393fn findTemplates(gpa: Allocator, arena: Allocator) Templates {
7355 const cwd_path = introspect.getResolvedCwd(arena) catch |err| {7394 const cwd_path = introspect.getResolvedCwd(arena) catch |err| {
7356 fatal("unable to get cwd: {s}", .{@errorName(err)});7395 fatal("unable to get cwd: {s}", .{@errorName(err)});
7357 };7396 };
...@@ -7375,7 +7414,6 @@ fn findTemplates(gpa: Allocator, arena: Allocator, strip: bool) Templates {...@@ -7375,7 +7414,6 @@ fn findTemplates(gpa: Allocator, arena: Allocator, strip: bool) Templates {
7375 .zig_lib_directory = zig_lib_directory,7414 .zig_lib_directory = zig_lib_directory,
7376 .dir = template_dir,7415 .dir = template_dir,
7377 .buffer = std.ArrayList(u8).init(gpa),7416 .buffer = std.ArrayList(u8).init(gpa),
7378 .strip = strip,
7379 };7417 };
7380}7418}
73817419
stage1/wasm2c.c+1-1
...@@ -316,10 +316,10 @@ int main(int argc, char **argv) {...@@ -316,10 +316,10 @@ int main(int argc, char **argv) {
316 "}\n"316 "}\n"
317 "\n"317 "\n"
318 "static uint32_t memory_grow(uint8_t **m, uint32_t *p, uint32_t *c, uint32_t n) {\n"318 "static uint32_t memory_grow(uint8_t **m, uint32_t *p, uint32_t *c, uint32_t n) {\n"
319 " uint8_t *new_m = *m;\n"
320 " uint32_t r = *p;\n"319 " uint32_t r = *p;\n"
321 " uint32_t new_p = r + n;\n"320 " uint32_t new_p = r + n;\n"
322 " if (new_p > UINT32_C(0xFFFF)) return UINT32_C(0xFFFFFFFF);\n"321 " if (new_p > UINT32_C(0xFFFF)) return UINT32_C(0xFFFFFFFF);\n"
322 " uint8_t *new_m = *m;\n"
323 " uint32_t new_c = *c;\n"323 " uint32_t new_c = *c;\n"
324 " if (new_c < new_p) {\n"324 " if (new_c < new_p) {\n"
325 " do new_c += new_c / 2 + 8; while (new_c < new_p);\n"325 " do new_c += new_c / 2 + 8; while (new_c < new_p);\n"
test/behavior/basic.zig-3
...@@ -471,7 +471,6 @@ fn testPointerToVoidReturnType2() *const void {...@@ -471,7 +471,6 @@ fn testPointerToVoidReturnType2() *const void {
471}471}
472472
473test "array 2D const double ptr" {473test "array 2D const double ptr" {
474 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
475 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO474 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
476 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;475 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
477 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;476 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -484,7 +483,6 @@ test "array 2D const double ptr" {...@@ -484,7 +483,6 @@ test "array 2D const double ptr" {
484}483}
485484
486test "array 2D const double ptr with offset" {485test "array 2D const double ptr with offset" {
487 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
488 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO486 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
489 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;487 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
490 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;488 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -497,7 +495,6 @@ test "array 2D const double ptr with offset" {...@@ -497,7 +495,6 @@ test "array 2D const double ptr with offset" {
497}495}
498496
499test "array 3D const double ptr with offset" {497test "array 3D const double ptr with offset" {
500 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
501 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO498 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
502 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;499 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
503 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;500 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
test/behavior/cast.zig-1
...@@ -1816,7 +1816,6 @@ test "peer type resolution: C pointer and @TypeOf(null)" {...@@ -1816,7 +1816,6 @@ test "peer type resolution: C pointer and @TypeOf(null)" {
1816}1816}
18171817
1818test "peer type resolution: three-way resolution combines error set and optional" {1818test "peer type resolution: three-way resolution combines error set and optional" {
1819 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1820 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1819 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1821 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1820 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1822 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1821 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
test/behavior/pointers.zig-1
...@@ -436,7 +436,6 @@ test "pointer sentinel with optional element" {...@@ -436,7 +436,6 @@ test "pointer sentinel with optional element" {
436}436}
437437
438test "pointer sentinel with +inf" {438test "pointer sentinel with +inf" {
439 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
440 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO439 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
441 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO440 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
442 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;441 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
test/tests.zig+10
...@@ -2016,6 +2016,16 @@ pub fn addCliTests(b: *std.Build) *Step {...@@ -2016,6 +2016,16 @@ pub fn addCliTests(b: *std.Build) *Step {
2016 step.dependOn(&cleanup.step);2016 step.dependOn(&cleanup.step);
2017 }2017 }
20182018
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
2019 // Test Godbolt API2029 // Test Godbolt API
2020 if (builtin.os.tag == .linux and builtin.cpu.arch == .x86_64) {2030 if (builtin.os.tag == .linux and builtin.cpu.arch == .x86_64) {
2021 const tmp_path = b.makeTempPath();2031 const tmp_path = b.makeTempPath();