authorgravatar for git@l4.pmluna <git@l4.pm> 2020-07-02 00:49:56-03:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2020-07-02 00:49:56-03:00
loge2cfc65909d49d1102fa440759f5475ced0c0c15
tree64eb34f48fb4066df4e54306f3115a9d341d3fd4
parent3f5b2d6c51b983ae66ad20124924378c2291cd67
parent6f98ef09e31768e3356598ef30e60fe028a0e70c
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge branch 'master' into ebadf-error


13 files changed, 474 insertions(+), 183 deletions(-)

build.zig+28-25
...@@ -49,11 +49,6 @@ pub fn build(b: *Builder) !void {...@@ -49,11 +49,6 @@ pub fn build(b: *Builder) !void {
4949
50 const fmt_build_zig = b.addFmt(&[_][]const u8{"build.zig"});50 const fmt_build_zig = b.addFmt(&[_][]const u8{"build.zig"});
5151
52 var exe = b.addExecutable("zig", "src-self-hosted/main.zig");
53 exe.setBuildMode(mode);
54 test_step.dependOn(&exe.step);
55 b.default_step.dependOn(&exe.step);
56
57 const skip_release = b.option(bool, "skip-release", "Main test suite skips release builds") orelse false;52 const skip_release = b.option(bool, "skip-release", "Main test suite skips release builds") orelse false;
58 const skip_release_small = b.option(bool, "skip-release-small", "Main test suite skips release-small builds") orelse skip_release;53 const skip_release_small = b.option(bool, "skip-release-small", "Main test suite skips release-small builds") orelse skip_release;
59 const skip_release_fast = b.option(bool, "skip-release-fast", "Main test suite skips release-fast builds") orelse skip_release;54 const skip_release_fast = b.option(bool, "skip-release-fast", "Main test suite skips release-fast builds") orelse skip_release;
...@@ -63,29 +58,37 @@ pub fn build(b: *Builder) !void {...@@ -63,29 +58,37 @@ pub fn build(b: *Builder) !void {
6358
64 const only_install_lib_files = b.option(bool, "lib-files-only", "Only install library files") orelse false;59 const only_install_lib_files = b.option(bool, "lib-files-only", "Only install library files") orelse false;
65 const enable_llvm = b.option(bool, "enable-llvm", "Build self-hosted compiler with LLVM backend enabled") orelse false;60 const enable_llvm = b.option(bool, "enable-llvm", "Build self-hosted compiler with LLVM backend enabled") orelse false;
66 if (enable_llvm) {
67 var ctx = parseConfigH(b, config_h_text);
68 ctx.llvm = try findLLVM(b, ctx.llvm_config_exe);
6961
70 try configureStage2(b, exe, ctx);
71 }
72 if (!only_install_lib_files) {62 if (!only_install_lib_files) {
73 exe.install();63 var exe = b.addExecutable("zig", "src-self-hosted/main.zig");
74 }64 exe.setBuildMode(mode);
75 const tracy = b.option([]const u8, "tracy", "Enable Tracy integration. Supply path to Tracy source");65 test_step.dependOn(&exe.step);
76 const link_libc = b.option(bool, "force-link-libc", "Force self-hosted compiler to link libc") orelse false;66 b.default_step.dependOn(&exe.step);
77 if (link_libc) exe.linkLibC();
7867
79 exe.addBuildOption(bool, "enable_tracy", tracy != null);68 if (enable_llvm) {
80 if (tracy) |tracy_path| {69 var ctx = parseConfigH(b, config_h_text);
81 const client_cpp = fs.path.join(70 ctx.llvm = try findLLVM(b, ctx.llvm_config_exe);
82 b.allocator,71
83 &[_][]const u8{ tracy_path, "TracyClient.cpp" },72 try configureStage2(b, exe, ctx);
84 ) catch unreachable;73 }
85 exe.addIncludeDir(tracy_path);74 if (!only_install_lib_files) {
86 exe.addCSourceFile(client_cpp, &[_][]const u8{ "-DTRACY_ENABLE=1", "-fno-sanitize=undefined" });75 exe.install();
87 exe.linkSystemLibraryName("c++");76 }
88 exe.linkLibC();77 const tracy = b.option([]const u8, "tracy", "Enable Tracy integration. Supply path to Tracy source");
78 const link_libc = b.option(bool, "force-link-libc", "Force self-hosted compiler to link libc") orelse false;
79 if (link_libc) exe.linkLibC();
80
81 exe.addBuildOption(bool, "enable_tracy", tracy != null);
82 if (tracy) |tracy_path| {
83 const client_cpp = fs.path.join(
84 b.allocator,
85 &[_][]const u8{ tracy_path, "TracyClient.cpp" },
86 ) catch unreachable;
87 exe.addIncludeDir(tracy_path);
88 exe.addCSourceFile(client_cpp, &[_][]const u8{ "-DTRACY_ENABLE=1", "-fno-sanitize=undefined" });
89 exe.linkSystemLibraryName("c++");
90 exe.linkLibC();
91 }
89 }92 }
9093
91 b.installDirectory(InstallDirectoryOptions{94 b.installDirectory(InstallDirectoryOptions{
doc/langref.html.in+23-1
...@@ -7530,7 +7530,7 @@ test "@hasDecl" {...@@ -7530,7 +7530,7 @@ test "@hasDecl" {
7530 source file than the one they are declared in.7530 source file than the one they are declared in.
7531 </p>7531 </p>
7532 <p>7532 <p>
7533 {#syntax#}path{#endsyntax#} can be a relative or absolute path, or it can be the name of a package.7533 {#syntax#}path{#endsyntax#} can be a relative path or it can be the name of a package.
7534 If it is a relative path, it is relative to the file that contains the {#syntax#}@import{#endsyntax#}7534 If it is a relative path, it is relative to the file that contains the {#syntax#}@import{#endsyntax#}
7535 function call.7535 function call.
7536 </p>7536 </p>
...@@ -8030,7 +8030,29 @@ test "vector @splat" {...@@ -8030,7 +8030,29 @@ test "vector @splat" {
8030 </p>8030 </p>
8031 {#see_also|Vectors|@shuffle#}8031 {#see_also|Vectors|@shuffle#}
8032 {#header_close#}8032 {#header_close#}
8033 {#header_open|@src#}
8034 <pre>{#syntax#}@src() std.builtin.SourceLocation{#endsyntax#}</pre>
8035 <p>
8036 Returns a {#syntax#}SourceLocation{#endsyntax#} struct representing the function's name and location in the source code. This must be called in a function.
8037 </p>
8038 {#code_begin|test#}
8039const std = @import("std");
8040const expect = std.testing.expect;
8041
8042test "@src" {
8043 doTheTest();
8044}
8045
8046fn doTheTest() void {
8047 const src = @src();
80338048
8049 expect(src.line == 9);
8050 expect(src.column == 17);
8051 expect(std.mem.endsWith(u8, src.fn_name, "doTheTest"));
8052 expect(std.mem.endsWith(u8, src.file, "test.zig"));
8053}
8054 {#code_end#}
8055 {#header_close#}
8034 {#header_open|@sqrt#}8056 {#header_open|@sqrt#}
8035 <pre>{#syntax#}@sqrt(value: var) @TypeOf(value){#endsyntax#}</pre>8057 <pre>{#syntax#}@sqrt(value: var) @TypeOf(value){#endsyntax#}</pre>
8036 <p>8058 <p>
lib/std/elf.zig+1
...@@ -552,6 +552,7 @@ fn preadNoEof(file: std.fs.File, buf: []u8, offset: u64) !void {...@@ -552,6 +552,7 @@ fn preadNoEof(file: std.fs.File, buf: []u8, offset: u64) !void {
552 error.Unexpected => return error.Unexpected,552 error.Unexpected => return error.Unexpected,
553 error.WouldBlock => return error.Unexpected,553 error.WouldBlock => return error.Unexpected,
554 error.NotOpenForReading => return error.Unexpected,554 error.NotOpenForReading => return error.Unexpected,
555 error.AccessDenied => return error.Unexpected,
555 };556 };
556 if (len == 0) return error.UnexpectedEndOfFile;557 if (len == 0) return error.UnexpectedEndOfFile;
557 i += len;558 i += len;
lib/std/fs.zig+32-12
...@@ -535,14 +535,15 @@ pub const Dir = struct {...@@ -535,14 +535,15 @@ pub const Dir = struct {
535 w.EFAULT => unreachable,535 w.EFAULT => unreachable,
536 w.ENOTDIR => unreachable,536 w.ENOTDIR => unreachable,
537 w.EINVAL => unreachable,537 w.EINVAL => unreachable,
538 w.ENOTCAPABLE => return error.AccessDenied,
538 else => |err| return os.unexpectedErrno(err),539 else => |err| return os.unexpectedErrno(err),
539 }540 }
540 if (bufused == 0) return null;541 if (bufused == 0) return null;
541 self.index = 0;542 self.index = 0;
542 self.end_index = bufused;543 self.end_index = bufused;
543 }544 }
544 const entry = @ptrCast(*align(1) os.wasi.dirent_t, &self.buf[self.index]);545 const entry = @ptrCast(*align(1) w.dirent_t, &self.buf[self.index]);
545 const entry_size = @sizeOf(os.wasi.dirent_t);546 const entry_size = @sizeOf(w.dirent_t);
546 const name_index = self.index + entry_size;547 const name_index = self.index + entry_size;
547 const name = mem.span(self.buf[name_index .. name_index + entry.d_namlen]);548 const name = mem.span(self.buf[name_index .. name_index + entry.d_namlen]);
548549
...@@ -556,12 +557,12 @@ pub const Dir = struct {...@@ -556,12 +557,12 @@ pub const Dir = struct {
556 }557 }
557558
558 const entry_kind = switch (entry.d_type) {559 const entry_kind = switch (entry.d_type) {
559 wasi.FILETYPE_BLOCK_DEVICE => Entry.Kind.BlockDevice,560 w.FILETYPE_BLOCK_DEVICE => Entry.Kind.BlockDevice,
560 wasi.FILETYPE_CHARACTER_DEVICE => Entry.Kind.CharacterDevice,561 w.FILETYPE_CHARACTER_DEVICE => Entry.Kind.CharacterDevice,
561 wasi.FILETYPE_DIRECTORY => Entry.Kind.Directory,562 w.FILETYPE_DIRECTORY => Entry.Kind.Directory,
562 wasi.FILETYPE_SYMBOLIC_LINK => Entry.Kind.SymLink,563 w.FILETYPE_SYMBOLIC_LINK => Entry.Kind.SymLink,
563 wasi.FILETYPE_REGULAR_FILE => Entry.Kind.File,564 w.FILETYPE_REGULAR_FILE => Entry.Kind.File,
564 wasi.FILETYPE_SOCKET_STREAM, wasi.FILETYPE_SOCKET_DGRAM => Entry.Kind.UnixDomainSocket,565 w.FILETYPE_SOCKET_STREAM, wasi.FILETYPE_SOCKET_DGRAM => Entry.Kind.UnixDomainSocket,
565 else => Entry.Kind.Unknown,566 else => Entry.Kind.Unknown,
566 };567 };
567 return Entry{568 return Entry{
...@@ -1110,10 +1111,18 @@ pub const Dir = struct {...@@ -1110,10 +1111,18 @@ pub const Dir = struct {
1110 /// Delete a file name and possibly the file it refers to, based on an open directory handle.1111 /// Delete a file name and possibly the file it refers to, based on an open directory handle.
1111 /// Asserts that the path parameter has no null bytes.1112 /// Asserts that the path parameter has no null bytes.
1112 pub fn deleteFile(self: Dir, sub_path: []const u8) DeleteFileError!void {1113 pub fn deleteFile(self: Dir, sub_path: []const u8) DeleteFileError!void {
1113 os.unlinkat(self.fd, sub_path, 0) catch |err| switch (err) {1114 if (builtin.os.tag == .windows) {
1114 error.DirNotEmpty => unreachable, // not passing AT_REMOVEDIR1115 const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path);
1115 else => |e| return e,1116 return self.deleteFileW(sub_path_w.span().ptr);
1116 };1117 } else if (builtin.os.tag == .wasi) {
1118 os.unlinkatWasi(self.fd, sub_path, 0) catch |err| switch (err) {
1119 error.DirNotEmpty => unreachable, // not passing AT_REMOVEDIR
1120 else => |e| return e,
1121 };
1122 } else {
1123 const sub_path_c = try os.toPosixPath(sub_path);
1124 return self.deleteFileZ(&sub_path_c);
1125 }
1117 }1126 }
11181127
1119 pub const deleteFileC = @compileError("deprecated: renamed to deleteFileZ");1128 pub const deleteFileC = @compileError("deprecated: renamed to deleteFileZ");
...@@ -1122,6 +1131,17 @@ pub const Dir = struct {...@@ -1122,6 +1131,17 @@ pub const Dir = struct {
1122 pub fn deleteFileZ(self: Dir, sub_path_c: [*:0]const u8) DeleteFileError!void {1131 pub fn deleteFileZ(self: Dir, sub_path_c: [*:0]const u8) DeleteFileError!void {
1123 os.unlinkatZ(self.fd, sub_path_c, 0) catch |err| switch (err) {1132 os.unlinkatZ(self.fd, sub_path_c, 0) catch |err| switch (err) {
1124 error.DirNotEmpty => unreachable, // not passing AT_REMOVEDIR1133 error.DirNotEmpty => unreachable, // not passing AT_REMOVEDIR
1134 error.AccessDenied => |e| switch (builtin.os.tag) {
1135 // non-Linux POSIX systems return EPERM when trying to delete a directory, so
1136 // we need to handle that case specifically and translate the error
1137 .macosx, .ios, .freebsd, .netbsd, .dragonfly => {
1138 // Don't follow symlinks to match unlinkat (which acts on symlinks rather than follows them)
1139 const fstat = os.fstatatZ(self.fd, sub_path_c, os.AT_SYMLINK_NOFOLLOW) catch return e;
1140 const is_dir = fstat.mode & os.S_IFMT == os.S_IFDIR;
1141 return if (is_dir) error.IsDir else e;
1142 },
1143 else => return e,
1144 },
1125 else => |e| return e,1145 else => |e| return e,
1126 };1146 };
1127 }1147 }
lib/std/fs/test.zig+37
...@@ -73,6 +73,43 @@ test "directory operations on files" {...@@ -73,6 +73,43 @@ test "directory operations on files" {
73 file.close();73 file.close();
74}74}
7575
76test "file operations on directories" {
77 var tmp_dir = tmpDir(.{});
78 defer tmp_dir.cleanup();
79
80 const test_dir_name = "test_dir";
81
82 try tmp_dir.dir.makeDir(test_dir_name);
83
84 testing.expectError(error.IsDir, tmp_dir.dir.createFile(test_dir_name, .{}));
85 testing.expectError(error.IsDir, tmp_dir.dir.deleteFile(test_dir_name));
86 // Currently, WASI will return error.Unexpected (via ENOTCAPABLE) when attempting fd_read on a directory handle.
87 // TODO: Re-enable on WASI once https://github.com/bytecodealliance/wasmtime/issues/1935 is resolved.
88 if (builtin.os.tag != .wasi) {
89 testing.expectError(error.IsDir, tmp_dir.dir.readFileAlloc(testing.allocator, test_dir_name, std.math.maxInt(usize)));
90 }
91 // Note: The `.write = true` is necessary to ensure the error occurs on all platforms.
92 // TODO: Add a read-only test as well, see https://github.com/ziglang/zig/issues/5732
93 testing.expectError(error.IsDir, tmp_dir.dir.openFile(test_dir_name, .{ .write = true }));
94
95 if (builtin.os.tag != .wasi) {
96 // TODO: use Dir's realpath function once that exists
97 const absolute_path = blk: {
98 const relative_path = try fs.path.join(testing.allocator, &[_][]const u8{ "zig-cache", "tmp", tmp_dir.sub_path[0..], test_dir_name });
99 defer testing.allocator.free(relative_path);
100 break :blk try fs.realpathAlloc(testing.allocator, relative_path);
101 };
102 defer testing.allocator.free(absolute_path);
103
104 testing.expectError(error.IsDir, fs.createFileAbsolute(absolute_path, .{}));
105 testing.expectError(error.IsDir, fs.deleteFileAbsolute(absolute_path));
106 }
107
108 // ensure the directory still exists as a sanity check
109 var dir = try tmp_dir.dir.openDir(test_dir_name, .{});
110 dir.close();
111}
112
76test "openSelfExe" {113test "openSelfExe" {
77 if (builtin.os.tag == .wasi) return error.SkipZigTest;114 if (builtin.os.tag == .wasi) return error.SkipZigTest;
78115
lib/std/heap.zig+5
...@@ -714,6 +714,11 @@ test "PageAllocator" {...@@ -714,6 +714,11 @@ test "PageAllocator" {
714 slice[127] = 0x34;714 slice[127] = 0x34;
715 allocator.free(slice);715 allocator.free(slice);
716 }716 }
717 {
718 var buf = try allocator.alloc(u8, mem.page_size + 1);
719 defer allocator.free(buf);
720 buf = try allocator.realloc(buf, 1); // shrink past the page boundary
721 }
717}722}
718723
719test "HeapAllocator" {724test "HeapAllocator" {
lib/std/heap/arena_allocator.zig+2-3
...@@ -49,9 +49,8 @@ pub const ArenaAllocator = struct {...@@ -49,9 +49,8 @@ pub const ArenaAllocator = struct {
49 const actual_min_size = minimum_size + (@sizeOf(BufNode) + 16);49 const actual_min_size = minimum_size + (@sizeOf(BufNode) + 16);
50 const big_enough_len = prev_len + actual_min_size;50 const big_enough_len = prev_len + actual_min_size;
51 const len = big_enough_len + big_enough_len / 2;51 const len = big_enough_len + big_enough_len / 2;
52 const buf = try self.child_allocator.alignedAlloc(u8, @alignOf(BufNode), len);52 const buf = try self.child_allocator.callAllocFn(len, @alignOf(BufNode), 1);
53 const buf_node_slice = mem.bytesAsSlice(BufNode, buf[0..@sizeOf(BufNode)]);53 const buf_node = @ptrCast(*BufNode, @alignCast(@alignOf(BufNode), buf.ptr));
54 const buf_node = &buf_node_slice[0];
55 buf_node.* = BufNode{54 buf_node.* = BufNode{
56 .data = buf,55 .data = buf,
57 .next = null,56 .next = null,
lib/std/mem.zig+4-7
...@@ -116,9 +116,6 @@ pub const Allocator = struct {...@@ -116,9 +116,6 @@ pub const Allocator = struct {
116 if (isAligned(@ptrToInt(old_mem.ptr), new_alignment)) {116 if (isAligned(@ptrToInt(old_mem.ptr), new_alignment)) {
117 if (new_byte_count <= old_mem.len) {117 if (new_byte_count <= old_mem.len) {
118 const shrunk_len = self.shrinkBytes(old_mem, new_byte_count, len_align);118 const shrunk_len = self.shrinkBytes(old_mem, new_byte_count, len_align);
119 if (shrunk_len < old_mem.len) {
120 @memset(old_mem.ptr + shrunk_len, undefined, old_mem.len - shrunk_len);
121 }
122 return old_mem.ptr[0..shrunk_len];119 return old_mem.ptr[0..shrunk_len];
123 }120 }
124 if (self.callResizeFn(old_mem, new_byte_count, len_align)) |resized_len| {121 if (self.callResizeFn(old_mem, new_byte_count, len_align)) |resized_len| {
...@@ -723,8 +720,8 @@ pub fn zeroInit(comptime T: type, init: var) T {...@@ -723,8 +720,8 @@ pub fn zeroInit(comptime T: type, init: var) T {
723 @field(value, field.name) = @field(init, field.name);720 @field(value, field.name) = @field(init, field.name);
724 },721 },
725 }722 }
726 } else if (field.default_value != null) {723 } else if (field.default_value) |default_value| {
727 @field(value, field.name) = field.default_value;724 @field(value, field.name) = default_value;
728 }725 }
729 }726 }
730727
...@@ -751,7 +748,7 @@ test "zeroInit" {...@@ -751,7 +748,7 @@ test "zeroInit" {
751 b: ?bool,748 b: ?bool,
752 c: I,749 c: I,
753 e: [3]u8,750 e: [3]u8,
754 f: i64,751 f: i64 = -1,
755 };752 };
756753
757 const s = zeroInit(S, .{754 const s = zeroInit(S, .{
...@@ -765,7 +762,7 @@ test "zeroInit" {...@@ -765,7 +762,7 @@ test "zeroInit" {
765 .d = 0,762 .d = 0,
766 },763 },
767 .e = [3]u8{ 0, 0, 0 },764 .e = [3]u8{ 0, 0, 0 },
768 .f = 0,765 .f = -1,
769 });766 });
770}767}
771768
lib/std/os.zig+76-23
...@@ -301,6 +301,10 @@ pub const ReadError = error{...@@ -301,6 +301,10 @@ pub const ReadError = error{
301 /// This error occurs when no global event loop is configured,301 /// This error occurs when no global event loop is configured,
302 /// and reading from the file descriptor would block.302 /// and reading from the file descriptor would block.
303 WouldBlock,303 WouldBlock,
304
305 /// In WASI, this error occurs when the file descriptor does
306 /// not hold the required rights to read from it.
307 AccessDenied,
304} || UnexpectedError;308} || UnexpectedError;
305309
306/// Returns the number of bytes that were read, which can be less than310/// Returns the number of bytes that were read, which can be less than
...@@ -336,6 +340,7 @@ pub fn read(fd: fd_t, buf: []u8) ReadError!usize {...@@ -336,6 +340,7 @@ pub fn read(fd: fd_t, buf: []u8) ReadError!usize {
336 wasi.ENOMEM => return error.SystemResources,340 wasi.ENOMEM => return error.SystemResources,
337 wasi.ECONNRESET => return error.ConnectionResetByPeer,341 wasi.ECONNRESET => return error.ConnectionResetByPeer,
338 wasi.ETIMEDOUT => return error.ConnectionTimedOut,342 wasi.ETIMEDOUT => return error.ConnectionTimedOut,
343 wasi.ENOTCAPABLE => return error.AccessDenied,
339 else => |err| return unexpectedErrno(err),344 else => |err| return unexpectedErrno(err),
340 }345 }
341 }346 }
...@@ -403,6 +408,7 @@ pub fn readv(fd: fd_t, iov: []const iovec) ReadError!usize {...@@ -403,6 +408,7 @@ pub fn readv(fd: fd_t, iov: []const iovec) ReadError!usize {
403 wasi.EISDIR => return error.IsDir,408 wasi.EISDIR => return error.IsDir,
404 wasi.ENOBUFS => return error.SystemResources,409 wasi.ENOBUFS => return error.SystemResources,
405 wasi.ENOMEM => return error.SystemResources,410 wasi.ENOMEM => return error.SystemResources,
411 wasi.ENOTCAPABLE => return error.AccessDenied,
406 else => |err| return unexpectedErrno(err),412 else => |err| return unexpectedErrno(err),
407 }413 }
408 }414 }
...@@ -467,6 +473,7 @@ pub fn pread(fd: fd_t, buf: []u8, offset: u64) PReadError!usize {...@@ -467,6 +473,7 @@ pub fn pread(fd: fd_t, buf: []u8, offset: u64) PReadError!usize {
467 wasi.ENXIO => return error.Unseekable,473 wasi.ENXIO => return error.Unseekable,
468 wasi.ESPIPE => return error.Unseekable,474 wasi.ESPIPE => return error.Unseekable,
469 wasi.EOVERFLOW => return error.Unseekable,475 wasi.EOVERFLOW => return error.Unseekable,
476 wasi.ENOTCAPABLE => return error.AccessDenied,
470 else => |err| return unexpectedErrno(err),477 else => |err| return unexpectedErrno(err),
471 }478 }
472 }479 }
...@@ -501,8 +508,11 @@ pub fn pread(fd: fd_t, buf: []u8, offset: u64) PReadError!usize {...@@ -501,8 +508,11 @@ pub fn pread(fd: fd_t, buf: []u8, offset: u64) PReadError!usize {
501pub const TruncateError = error{508pub const TruncateError = error{
502 FileTooBig,509 FileTooBig,
503 InputOutput,510 InputOutput,
504 CannotTruncate,
505 FileBusy,511 FileBusy,
512
513 /// In WASI, this error occurs when the file descriptor does
514 /// not hold the required rights to call `ftruncate` on it.
515 AccessDenied,
506} || UnexpectedError;516} || UnexpectedError;
507517
508pub fn ftruncate(fd: fd_t, length: u64) TruncateError!void {518pub fn ftruncate(fd: fd_t, length: u64) TruncateError!void {
...@@ -523,7 +533,7 @@ pub fn ftruncate(fd: fd_t, length: u64) TruncateError!void {...@@ -523,7 +533,7 @@ pub fn ftruncate(fd: fd_t, length: u64) TruncateError!void {
523 switch (rc) {533 switch (rc) {
524 .SUCCESS => return,534 .SUCCESS => return,
525 .INVALID_HANDLE => unreachable, // Handle not open for writing535 .INVALID_HANDLE => unreachable, // Handle not open for writing
526 .ACCESS_DENIED => return error.CannotTruncate,536 .ACCESS_DENIED => return error.AccessDenied,
527 else => return windows.unexpectedStatus(rc),537 else => return windows.unexpectedStatus(rc),
528 }538 }
529 }539 }
...@@ -533,10 +543,11 @@ pub fn ftruncate(fd: fd_t, length: u64) TruncateError!void {...@@ -533,10 +543,11 @@ pub fn ftruncate(fd: fd_t, length: u64) TruncateError!void {
533 wasi.EINTR => unreachable,543 wasi.EINTR => unreachable,
534 wasi.EFBIG => return error.FileTooBig,544 wasi.EFBIG => return error.FileTooBig,
535 wasi.EIO => return error.InputOutput,545 wasi.EIO => return error.InputOutput,
536 wasi.EPERM => return error.CannotTruncate,546 wasi.EPERM => return error.AccessDenied,
537 wasi.ETXTBSY => return error.FileBusy,547 wasi.ETXTBSY => return error.FileBusy,
538 wasi.EBADF => unreachable, // Handle not open for writing548 wasi.EBADF => unreachable, // Handle not open for writing
539 wasi.EINVAL => unreachable, // Handle not open for writing549 wasi.EINVAL => unreachable, // Handle not open for writing
550 wasi.ENOTCAPABLE => return error.AccessDenied,
540 else => |err| return unexpectedErrno(err),551 else => |err| return unexpectedErrno(err),
541 }552 }
542 }553 }
...@@ -555,7 +566,7 @@ pub fn ftruncate(fd: fd_t, length: u64) TruncateError!void {...@@ -555,7 +566,7 @@ pub fn ftruncate(fd: fd_t, length: u64) TruncateError!void {
555 EINTR => continue,566 EINTR => continue,
556 EFBIG => return error.FileTooBig,567 EFBIG => return error.FileTooBig,
557 EIO => return error.InputOutput,568 EIO => return error.InputOutput,
558 EPERM => return error.CannotTruncate,569 EPERM => return error.AccessDenied,
559 ETXTBSY => return error.FileBusy,570 ETXTBSY => return error.FileBusy,
560 EBADF => unreachable, // Handle not open for writing571 EBADF => unreachable, // Handle not open for writing
561 EINVAL => unreachable, // Handle not open for writing572 EINVAL => unreachable, // Handle not open for writing
...@@ -605,6 +616,7 @@ pub fn preadv(fd: fd_t, iov: []const iovec, offset: u64) PReadError!usize {...@@ -605,6 +616,7 @@ pub fn preadv(fd: fd_t, iov: []const iovec, offset: u64) PReadError!usize {
605 wasi.ENXIO => return error.Unseekable,616 wasi.ENXIO => return error.Unseekable,
606 wasi.ESPIPE => return error.Unseekable,617 wasi.ESPIPE => return error.Unseekable,
607 wasi.EOVERFLOW => return error.Unseekable,618 wasi.EOVERFLOW => return error.Unseekable,
619 wasi.ENOTCAPABLE => return error.AccessDenied,
608 else => |err| return unexpectedErrno(err),620 else => |err| return unexpectedErrno(err),
609 }621 }
610 }622 }
...@@ -642,6 +654,9 @@ pub const WriteError = error{...@@ -642,6 +654,9 @@ pub const WriteError = error{
642 FileTooBig,654 FileTooBig,
643 InputOutput,655 InputOutput,
644 NoSpaceLeft,656 NoSpaceLeft,
657
658 /// In WASI, this error may occur when the file descriptor does
659 /// not hold the required rights to write to it.
645 AccessDenied,660 AccessDenied,
646 BrokenPipe,661 BrokenPipe,
647 SystemResources,662 SystemResources,
...@@ -699,6 +714,7 @@ pub fn write(fd: fd_t, bytes: []const u8) WriteError!usize {...@@ -699,6 +714,7 @@ pub fn write(fd: fd_t, bytes: []const u8) WriteError!usize {
699 wasi.ENOSPC => return error.NoSpaceLeft,714 wasi.ENOSPC => return error.NoSpaceLeft,
700 wasi.EPERM => return error.AccessDenied,715 wasi.EPERM => return error.AccessDenied,
701 wasi.EPIPE => return error.BrokenPipe,716 wasi.EPIPE => return error.BrokenPipe,
717 wasi.ENOTCAPABLE => return error.AccessDenied,
702 else => |err| return unexpectedErrno(err),718 else => |err| return unexpectedErrno(err),
703 }719 }
704 }720 }
...@@ -776,6 +792,7 @@ pub fn writev(fd: fd_t, iov: []const iovec_const) WriteError!usize {...@@ -776,6 +792,7 @@ pub fn writev(fd: fd_t, iov: []const iovec_const) WriteError!usize {
776 wasi.ENOSPC => return error.NoSpaceLeft,792 wasi.ENOSPC => return error.NoSpaceLeft,
777 wasi.EPERM => return error.AccessDenied,793 wasi.EPERM => return error.AccessDenied,
778 wasi.EPIPE => return error.BrokenPipe,794 wasi.EPIPE => return error.BrokenPipe,
795 wasi.ENOTCAPABLE => return error.AccessDenied,
779 else => |err| return unexpectedErrno(err),796 else => |err| return unexpectedErrno(err),
780 }797 }
781 }798 }
...@@ -858,6 +875,7 @@ pub fn pwrite(fd: fd_t, bytes: []const u8, offset: u64) PWriteError!usize {...@@ -858,6 +875,7 @@ pub fn pwrite(fd: fd_t, bytes: []const u8, offset: u64) PWriteError!usize {
858 wasi.ENXIO => return error.Unseekable,875 wasi.ENXIO => return error.Unseekable,
859 wasi.ESPIPE => return error.Unseekable,876 wasi.ESPIPE => return error.Unseekable,
860 wasi.EOVERFLOW => return error.Unseekable,877 wasi.EOVERFLOW => return error.Unseekable,
878 wasi.ENOTCAPABLE => return error.AccessDenied,
861 else => |err| return unexpectedErrno(err),879 else => |err| return unexpectedErrno(err),
862 }880 }
863 }881 }
...@@ -951,6 +969,7 @@ pub fn pwritev(fd: fd_t, iov: []const iovec_const, offset: u64) PWriteError!usiz...@@ -951,6 +969,7 @@ pub fn pwritev(fd: fd_t, iov: []const iovec_const, offset: u64) PWriteError!usiz
951 wasi.ENXIO => return error.Unseekable,969 wasi.ENXIO => return error.Unseekable,
952 wasi.ESPIPE => return error.Unseekable,970 wasi.ESPIPE => return error.Unseekable,
953 wasi.EOVERFLOW => return error.Unseekable,971 wasi.EOVERFLOW => return error.Unseekable,
972 wasi.ENOTCAPABLE => return error.AccessDenied,
954 else => |err| return unexpectedErrno(err),973 else => |err| return unexpectedErrno(err),
955 }974 }
956 }975 }
...@@ -986,6 +1005,8 @@ pub fn pwritev(fd: fd_t, iov: []const iovec_const, offset: u64) PWriteError!usiz...@@ -986,6 +1005,8 @@ pub fn pwritev(fd: fd_t, iov: []const iovec_const, offset: u64) PWriteError!usiz
986}1005}
9871006
988pub const OpenError = error{1007pub const OpenError = error{
1008 /// In WASI, this error may occur when the file descriptor does
1009 /// not hold the required rights to open a new resource relative to it.
989 AccessDenied,1010 AccessDenied,
990 SymLinkLoop,1011 SymLinkLoop,
991 ProcessFdQuotaExceeded,1012 ProcessFdQuotaExceeded,
...@@ -1115,6 +1136,7 @@ pub fn openatWasi(dir_fd: fd_t, file_path: []const u8, oflags: oflags_t, fdflags...@@ -1115,6 +1136,7 @@ pub fn openatWasi(dir_fd: fd_t, file_path: []const u8, oflags: oflags_t, fdflags
1115 wasi.EPERM => return error.AccessDenied,1136 wasi.EPERM => return error.AccessDenied,
1116 wasi.EEXIST => return error.PathAlreadyExists,1137 wasi.EEXIST => return error.PathAlreadyExists,
1117 wasi.EBUSY => return error.DeviceBusy,1138 wasi.EBUSY => return error.DeviceBusy,
1139 wasi.ENOTCAPABLE => return error.AccessDenied,
1118 else => |err| return unexpectedErrno(err),1140 else => |err| return unexpectedErrno(err),
1119 }1141 }
1120 }1142 }
...@@ -1501,6 +1523,8 @@ pub fn getcwd(out_buffer: []u8) GetCwdError![]u8 {...@@ -1501,6 +1523,8 @@ pub fn getcwd(out_buffer: []u8) GetCwdError![]u8 {
1501}1523}
15021524
1503pub const SymLinkError = error{1525pub const SymLinkError = error{
1526 /// In WASI, this error may occur when the file descriptor does
1527 /// not hold the required rights to create a new symbolic link relative to it.
1504 AccessDenied,1528 AccessDenied,
1505 DiskQuota,1529 DiskQuota,
1506 PathAlreadyExists,1530 PathAlreadyExists,
...@@ -1606,13 +1630,14 @@ pub fn symlinkatWasi(target_path: []const u8, newdirfd: fd_t, sym_link_path: []c...@@ -1606,13 +1630,14 @@ pub fn symlinkatWasi(target_path: []const u8, newdirfd: fd_t, sym_link_path: []c
1606 wasi.ENOMEM => return error.SystemResources,1630 wasi.ENOMEM => return error.SystemResources,
1607 wasi.ENOSPC => return error.NoSpaceLeft,1631 wasi.ENOSPC => return error.NoSpaceLeft,
1608 wasi.EROFS => return error.ReadOnlyFileSystem,1632 wasi.EROFS => return error.ReadOnlyFileSystem,
1633 wasi.ENOTCAPABLE => return error.AccessDenied,
1609 else => |err| return unexpectedErrno(err),1634 else => |err| return unexpectedErrno(err),
1610 }1635 }
1611}1636}
16121637
1613/// Windows-only. The same as `symlinkat` except the paths are null-terminated, WTF-16 encoded.1638/// Windows-only. The same as `symlinkat` except the paths are null-terminated, WTF-16 encoded.
1614/// See also `symlinkat`.1639/// See also `symlinkat`.
1615pub fn symlinkatW(target_path: [*:0]const u16, newdirfd: fd_t, sym_link_path: [*:0]const u16) SymlinkError!void {1640pub fn symlinkatW(target_path: [*:0]const u16, newdirfd: fd_t, sym_link_path: [*:0]const u16) SymLinkError!void {
1616 @compileError("TODO implement on Windows");1641 @compileError("TODO implement on Windows");
1617}1642}
16181643
...@@ -1646,6 +1671,9 @@ pub fn symlinkatZ(target_path: [*:0]const u8, newdirfd: fd_t, sym_link_path: [*:...@@ -1646,6 +1671,9 @@ pub fn symlinkatZ(target_path: [*:0]const u8, newdirfd: fd_t, sym_link_path: [*:
16461671
1647pub const UnlinkError = error{1672pub const UnlinkError = error{
1648 FileNotFound,1673 FileNotFound,
1674
1675 /// In WASI, this error may occur when the file descriptor does
1676 /// not hold the required rights to unlink a resource by path relative to it.
1649 AccessDenied,1677 AccessDenied,
1650 FileBusy,1678 FileBusy,
1651 FileSystem,1679 FileSystem,
...@@ -1749,6 +1777,7 @@ pub fn unlinkatWasi(dirfd: fd_t, file_path: []const u8, flags: u32) UnlinkatErro...@@ -1749,6 +1777,7 @@ pub fn unlinkatWasi(dirfd: fd_t, file_path: []const u8, flags: u32) UnlinkatErro
1749 wasi.ENOMEM => return error.SystemResources,1777 wasi.ENOMEM => return error.SystemResources,
1750 wasi.EROFS => return error.ReadOnlyFileSystem,1778 wasi.EROFS => return error.ReadOnlyFileSystem,
1751 wasi.ENOTEMPTY => return error.DirNotEmpty,1779 wasi.ENOTEMPTY => return error.DirNotEmpty,
1780 wasi.ENOTCAPABLE => return error.AccessDenied,
17521781
1753 wasi.EINVAL => unreachable, // invalid flags, or pathname has . as last component1782 wasi.EINVAL => unreachable, // invalid flags, or pathname has . as last component
1754 wasi.EBADF => unreachable, // always a race condition1783 wasi.EBADF => unreachable, // always a race condition
...@@ -1851,6 +1880,8 @@ pub fn unlinkatW(dirfd: fd_t, sub_path_w: [*:0]const u16, flags: u32) UnlinkatEr...@@ -1851,6 +1880,8 @@ pub fn unlinkatW(dirfd: fd_t, sub_path_w: [*:0]const u16, flags: u32) UnlinkatEr
1851}1880}
18521881
1853const RenameError = error{1882const RenameError = error{
1883 /// In WASI, this error may occur when the file descriptor does
1884 /// not hold the required rights to rename a resource by path relative to it.
1854 AccessDenied,1885 AccessDenied,
1855 FileBusy,1886 FileBusy,
1856 DiskQuota,1887 DiskQuota,
...@@ -1970,6 +2001,7 @@ pub fn renameatWasi(old_dir_fd: fd_t, old_path: []const u8, new_dir_fd: fd_t, ne...@@ -1970,6 +2001,7 @@ pub fn renameatWasi(old_dir_fd: fd_t, old_path: []const u8, new_dir_fd: fd_t, ne
1970 wasi.ENOTEMPTY => return error.PathAlreadyExists,2001 wasi.ENOTEMPTY => return error.PathAlreadyExists,
1971 wasi.EROFS => return error.ReadOnlyFileSystem,2002 wasi.EROFS => return error.ReadOnlyFileSystem,
1972 wasi.EXDEV => return error.RenameAcrossMountPoints,2003 wasi.EXDEV => return error.RenameAcrossMountPoints,
2004 wasi.ENOTCAPABLE => return error.AccessDenied,
1973 else => |err| return unexpectedErrno(err),2005 else => |err| return unexpectedErrno(err),
1974 }2006 }
1975}2007}
...@@ -2068,23 +2100,6 @@ pub fn renameatW(...@@ -2068,23 +2100,6 @@ pub fn renameatW(
2068 }2100 }
2069}2101}
20702102
2071pub const MakeDirError = error{
2072 AccessDenied,
2073 DiskQuota,
2074 PathAlreadyExists,
2075 SymLinkLoop,
2076 LinkQuotaExceeded,
2077 NameTooLong,
2078 FileNotFound,
2079 SystemResources,
2080 NoSpaceLeft,
2081 NotDir,
2082 ReadOnlyFileSystem,
2083 InvalidUtf8,
2084 BadPathName,
2085 NoDevice,
2086} || UnexpectedError;
2087
2088pub fn mkdirat(dir_fd: fd_t, sub_dir_path: []const u8, mode: u32) MakeDirError!void {2103pub fn mkdirat(dir_fd: fd_t, sub_dir_path: []const u8, mode: u32) MakeDirError!void {
2089 if (builtin.os.tag == .windows) {2104 if (builtin.os.tag == .windows) {
2090 const sub_dir_path_w = try windows.sliceToPrefixedFileW(sub_dir_path);2105 const sub_dir_path_w = try windows.sliceToPrefixedFileW(sub_dir_path);
...@@ -2116,6 +2131,7 @@ pub fn mkdiratWasi(dir_fd: fd_t, sub_dir_path: []const u8, mode: u32) MakeDirErr...@@ -2116,6 +2131,7 @@ pub fn mkdiratWasi(dir_fd: fd_t, sub_dir_path: []const u8, mode: u32) MakeDirErr
2116 wasi.ENOSPC => return error.NoSpaceLeft,2131 wasi.ENOSPC => return error.NoSpaceLeft,
2117 wasi.ENOTDIR => return error.NotDir,2132 wasi.ENOTDIR => return error.NotDir,
2118 wasi.EROFS => return error.ReadOnlyFileSystem,2133 wasi.EROFS => return error.ReadOnlyFileSystem,
2134 wasi.ENOTCAPABLE => return error.AccessDenied,
2119 else => |err| return unexpectedErrno(err),2135 else => |err| return unexpectedErrno(err),
2120 }2136 }
2121}2137}
...@@ -2150,6 +2166,25 @@ pub fn mkdiratW(dir_fd: fd_t, sub_path_w: [*:0]const u16, mode: u32) MakeDirErro...@@ -2150,6 +2166,25 @@ pub fn mkdiratW(dir_fd: fd_t, sub_path_w: [*:0]const u16, mode: u32) MakeDirErro
2150 windows.CloseHandle(sub_dir_handle);2166 windows.CloseHandle(sub_dir_handle);
2151}2167}
21522168
2169pub const MakeDirError = error{
2170 /// In WASI, this error may occur when the file descriptor does
2171 /// not hold the required rights to create a new directory relative to it.
2172 AccessDenied,
2173 DiskQuota,
2174 PathAlreadyExists,
2175 SymLinkLoop,
2176 LinkQuotaExceeded,
2177 NameTooLong,
2178 FileNotFound,
2179 SystemResources,
2180 NoSpaceLeft,
2181 NotDir,
2182 ReadOnlyFileSystem,
2183 InvalidUtf8,
2184 BadPathName,
2185 NoDevice,
2186} || UnexpectedError;
2187
2153/// Create a directory.2188/// Create a directory.
2154/// `mode` is ignored on Windows.2189/// `mode` is ignored on Windows.
2155pub fn mkdir(dir_path: []const u8, mode: u32) MakeDirError!void {2190pub fn mkdir(dir_path: []const u8, mode: u32) MakeDirError!void {
...@@ -2313,6 +2348,8 @@ pub fn fchdir(dirfd: fd_t) FchdirError!void {...@@ -2313,6 +2348,8 @@ pub fn fchdir(dirfd: fd_t) FchdirError!void {
2313}2348}
23142349
2315pub const ReadLinkError = error{2350pub const ReadLinkError = error{
2351 /// In WASI, this error may occur when the file descriptor does
2352 /// not hold the required rights to read value of a symbolic link relative to it.
2316 AccessDenied,2353 AccessDenied,
2317 FileSystem,2354 FileSystem,
2318 SymLinkLoop,2355 SymLinkLoop,
...@@ -2398,6 +2435,7 @@ pub fn readlinkatWasi(dirfd: fd_t, file_path: []const u8, out_buffer: []u8) Read...@@ -2398,6 +2435,7 @@ pub fn readlinkatWasi(dirfd: fd_t, file_path: []const u8, out_buffer: []u8) Read
2398 wasi.ENOENT => return error.FileNotFound,2435 wasi.ENOENT => return error.FileNotFound,
2399 wasi.ENOMEM => return error.SystemResources,2436 wasi.ENOMEM => return error.SystemResources,
2400 wasi.ENOTDIR => return error.NotDir,2437 wasi.ENOTDIR => return error.NotDir,
2438 wasi.ENOTCAPABLE => return error.AccessDenied,
2401 else => |err| return unexpectedErrno(err),2439 else => |err| return unexpectedErrno(err),
2402 }2440 }
2403}2441}
...@@ -3075,6 +3113,9 @@ pub fn waitpid(pid: i32, flags: u32) u32 {...@@ -3075,6 +3113,9 @@ pub fn waitpid(pid: i32, flags: u32) u32 {
30753113
3076pub const FStatError = error{3114pub const FStatError = error{
3077 SystemResources,3115 SystemResources,
3116
3117 /// In WASI, this error may occur when the file descriptor does
3118 /// not hold the required rights to get its filestat information.
3078 AccessDenied,3119 AccessDenied,
3079} || UnexpectedError;3120} || UnexpectedError;
30803121
...@@ -3088,6 +3129,7 @@ pub fn fstat(fd: fd_t) FStatError!Stat {...@@ -3088,6 +3129,7 @@ pub fn fstat(fd: fd_t) FStatError!Stat {
3088 wasi.EBADF => unreachable, // Always a race condition.3129 wasi.EBADF => unreachable, // Always a race condition.
3089 wasi.ENOMEM => return error.SystemResources,3130 wasi.ENOMEM => return error.SystemResources,
3090 wasi.EACCES => return error.AccessDenied,3131 wasi.EACCES => return error.AccessDenied,
3132 wasi.ENOTCAPABLE => return error.AccessDenied,
3091 else => |err| return unexpectedErrno(err),3133 else => |err| return unexpectedErrno(err),
3092 }3134 }
3093 }3135 }
...@@ -3138,6 +3180,7 @@ pub fn fstatatWasi(dirfd: fd_t, pathname: []const u8, flags: u32) FStatAtError!S...@@ -3138,6 +3180,7 @@ pub fn fstatatWasi(dirfd: fd_t, pathname: []const u8, flags: u32) FStatAtError!S
3138 wasi.ENAMETOOLONG => return error.NameTooLong,3180 wasi.ENAMETOOLONG => return error.NameTooLong,
3139 wasi.ENOENT => return error.FileNotFound,3181 wasi.ENOENT => return error.FileNotFound,
3140 wasi.ENOTDIR => return error.FileNotFound,3182 wasi.ENOTDIR => return error.FileNotFound,
3183 wasi.ENOTCAPABLE => return error.AccessDenied,
3141 else => |err| return unexpectedErrno(err),3184 else => |err| return unexpectedErrno(err),
3142 }3185 }
3143}3186}
...@@ -3643,7 +3686,13 @@ pub fn gettimeofday(tv: ?*timeval, tz: ?*timezone) void {...@@ -3643,7 +3686,13 @@ pub fn gettimeofday(tv: ?*timeval, tz: ?*timezone) void {
3643 }3686 }
3644}3687}
36453688
3646pub const SeekError = error{Unseekable} || UnexpectedError;3689pub const SeekError = error{
3690 Unseekable,
3691
3692 /// In WASI, this error may occur when the file descriptor does
3693 /// not hold the required rights to seek on it.
3694 AccessDenied,
3695} || UnexpectedError;
36473696
3648/// Repositions read/write file offset relative to the beginning.3697/// Repositions read/write file offset relative to the beginning.
3649pub fn lseek_SET(fd: fd_t, offset: u64) SeekError!void {3698pub fn lseek_SET(fd: fd_t, offset: u64) SeekError!void {
...@@ -3671,6 +3720,7 @@ pub fn lseek_SET(fd: fd_t, offset: u64) SeekError!void {...@@ -3671,6 +3720,7 @@ pub fn lseek_SET(fd: fd_t, offset: u64) SeekError!void {
3671 wasi.EOVERFLOW => return error.Unseekable,3720 wasi.EOVERFLOW => return error.Unseekable,
3672 wasi.ESPIPE => return error.Unseekable,3721 wasi.ESPIPE => return error.Unseekable,
3673 wasi.ENXIO => return error.Unseekable,3722 wasi.ENXIO => return error.Unseekable,
3723 wasi.ENOTCAPABLE => return error.AccessDenied,
3674 else => |err| return unexpectedErrno(err),3724 else => |err| return unexpectedErrno(err),
3675 }3725 }
3676 }3726 }
...@@ -3712,6 +3762,7 @@ pub fn lseek_CUR(fd: fd_t, offset: i64) SeekError!void {...@@ -3712,6 +3762,7 @@ pub fn lseek_CUR(fd: fd_t, offset: i64) SeekError!void {
3712 wasi.EOVERFLOW => return error.Unseekable,3762 wasi.EOVERFLOW => return error.Unseekable,
3713 wasi.ESPIPE => return error.Unseekable,3763 wasi.ESPIPE => return error.Unseekable,
3714 wasi.ENXIO => return error.Unseekable,3764 wasi.ENXIO => return error.Unseekable,
3765 wasi.ENOTCAPABLE => return error.AccessDenied,
3715 else => |err| return unexpectedErrno(err),3766 else => |err| return unexpectedErrno(err),
3716 }3767 }
3717 }3768 }
...@@ -3752,6 +3803,7 @@ pub fn lseek_END(fd: fd_t, offset: i64) SeekError!void {...@@ -3752,6 +3803,7 @@ pub fn lseek_END(fd: fd_t, offset: i64) SeekError!void {
3752 wasi.EOVERFLOW => return error.Unseekable,3803 wasi.EOVERFLOW => return error.Unseekable,
3753 wasi.ESPIPE => return error.Unseekable,3804 wasi.ESPIPE => return error.Unseekable,
3754 wasi.ENXIO => return error.Unseekable,3805 wasi.ENXIO => return error.Unseekable,
3806 wasi.ENOTCAPABLE => return error.AccessDenied,
3755 else => |err| return unexpectedErrno(err),3807 else => |err| return unexpectedErrno(err),
3756 }3808 }
3757 }3809 }
...@@ -3792,6 +3844,7 @@ pub fn lseek_CUR_get(fd: fd_t) SeekError!u64 {...@@ -3792,6 +3844,7 @@ pub fn lseek_CUR_get(fd: fd_t) SeekError!u64 {
3792 wasi.EOVERFLOW => return error.Unseekable,3844 wasi.EOVERFLOW => return error.Unseekable,
3793 wasi.ESPIPE => return error.Unseekable,3845 wasi.ESPIPE => return error.Unseekable,
3794 wasi.ENXIO => return error.Unseekable,3846 wasi.ENXIO => return error.Unseekable,
3847 wasi.ENOTCAPABLE => return error.AccessDenied,
3795 else => |err| return unexpectedErrno(err),3848 else => |err| return unexpectedErrno(err),
3796 }3849 }
3797 }3850 }
lib/std/zig/system.zig+1
...@@ -860,6 +860,7 @@ pub const NativeTargetInfo = struct {...@@ -860,6 +860,7 @@ pub const NativeTargetInfo = struct {
860 error.ConnectionTimedOut => return error.UnableToReadElfFile,860 error.ConnectionTimedOut => return error.UnableToReadElfFile,
861 error.Unexpected => return error.Unexpected,861 error.Unexpected => return error.Unexpected,
862 error.InputOutput => return error.FileSystem,862 error.InputOutput => return error.FileSystem,
863 error.AccessDenied => return error.Unexpected,
863 };864 };
864 if (len == 0) return error.UnexpectedEndOfFile;865 if (len == 0) return error.UnexpectedEndOfFile;
865 i += len;866 i += len;
src-self-hosted/codegen.zig+189-107
...@@ -37,6 +37,68 @@ pub fn generateSymbol(...@@ -37,6 +37,68 @@ pub fn generateSymbol(
37 .Fn => {37 .Fn => {
38 const module_fn = typed_value.val.cast(Value.Payload.Function).?.func;38 const module_fn = typed_value.val.cast(Value.Payload.Function).?.func;
3939
40 const fn_type = module_fn.owner_decl.typed_value.most_recent.typed_value.ty;
41 const param_types = try bin_file.allocator.alloc(Type, fn_type.fnParamLen());
42 defer bin_file.allocator.free(param_types);
43 fn_type.fnParamTypes(param_types);
44 // A parameter may be broken into multiple machine code parameters, so we don't
45 // know the size up front.
46 var mc_args = try std.ArrayList(Function.MCValue).initCapacity(bin_file.allocator, param_types.len);
47 defer mc_args.deinit();
48
49 var next_stack_offset: u64 = 0;
50
51 switch (fn_type.fnCallingConvention()) {
52 .Naked => assert(mc_args.items.len == 0),
53 .Unspecified, .C => {
54 // Prepare the function parameters
55 switch (bin_file.options.target.cpu.arch) {
56 .x86_64 => {
57 const integer_registers = [_]Reg(.x86_64){ .rdi, .rsi, .rdx, .rcx, .r8, .r9 };
58 var next_int_reg: usize = 0;
59
60 for (param_types) |param_type, src_i| {
61 switch (param_type.zigTypeTag()) {
62 .Bool, .Int => {
63 if (next_int_reg >= integer_registers.len) {
64 try mc_args.append(.{ .stack_offset = next_stack_offset });
65 next_stack_offset += param_type.abiSize(bin_file.options.target);
66 } else {
67 try mc_args.append(.{ .register = @enumToInt(integer_registers[next_int_reg]) });
68 next_int_reg += 1;
69 }
70 },
71 else => return Result{
72 .fail = try ErrorMsg.create(
73 bin_file.allocator,
74 src,
75 "TODO implement function parameters of type {}",
76 .{@tagName(param_type.zigTypeTag())},
77 ),
78 },
79 }
80 }
81 },
82 else => return Result{
83 .fail = try ErrorMsg.create(
84 bin_file.allocator,
85 src,
86 "TODO implement function parameters for {}",
87 .{bin_file.options.target.cpu.arch},
88 ),
89 },
90 }
91 },
92 else => return Result{
93 .fail = try ErrorMsg.create(
94 bin_file.allocator,
95 src,
96 "TODO implement {} calling convention",
97 .{fn_type.fnCallingConvention()},
98 ),
99 },
100 }
101
40 var function = Function{102 var function = Function{
41 .target = &bin_file.options.target,103 .target = &bin_file.options.target,
42 .bin_file = bin_file,104 .bin_file = bin_file,
...@@ -44,16 +106,14 @@ pub fn generateSymbol(...@@ -44,16 +106,14 @@ pub fn generateSymbol(
44 .code = code,106 .code = code,
45 .inst_table = std.AutoHashMap(*ir.Inst, Function.MCValue).init(bin_file.allocator),107 .inst_table = std.AutoHashMap(*ir.Inst, Function.MCValue).init(bin_file.allocator),
46 .err_msg = null,108 .err_msg = null,
109 .args = mc_args.items,
47 };110 };
48 defer function.inst_table.deinit();111 defer function.inst_table.deinit();
49112
50 for (module_fn.analysis.success.instructions) |inst| {113 function.gen() catch |err| switch (err) {
51 const new_inst = function.genFuncInst(inst) catch |err| switch (err) {114 error.CodegenFail => return Result{ .fail = function.err_msg.? },
52 error.CodegenFail => return Result{ .fail = function.err_msg.? },115 else => |e| return e,
53 else => |e| return e,116 };
54 };
55 try function.inst_table.putNoClobber(inst, new_inst);
56 }
57117
58 if (function.err_msg) |em| {118 if (function.err_msg) |em| {
59 return Result{ .fail = em };119 return Result{ .fail = em };
...@@ -157,6 +217,7 @@ const Function = struct {...@@ -157,6 +217,7 @@ const Function = struct {
157 code: *std.ArrayList(u8),217 code: *std.ArrayList(u8),
158 inst_table: std.AutoHashMap(*ir.Inst, MCValue),218 inst_table: std.AutoHashMap(*ir.Inst, MCValue),
159 err_msg: ?*ErrorMsg,219 err_msg: ?*ErrorMsg,
220 args: []MCValue,
160221
161 const MCValue = union(enum) {222 const MCValue = union(enum) {
162 none,223 none,
...@@ -170,44 +231,119 @@ const Function = struct {...@@ -170,44 +231,119 @@ const Function = struct {
170 register: usize,231 register: usize,
171 /// The value is in memory at a hard-coded address.232 /// The value is in memory at a hard-coded address.
172 memory: u64,233 memory: u64,
234 /// The value is one of the stack variables.
235 stack_offset: u64,
173 };236 };
174237
175 fn genFuncInst(self: *Function, inst: *ir.Inst) !MCValue {238 fn gen(self: *Function) !void {
239 switch (self.target.cpu.arch) {
240 .arm => return self.genArch(.arm),
241 .armeb => return self.genArch(.armeb),
242 .aarch64 => return self.genArch(.aarch64),
243 .aarch64_be => return self.genArch(.aarch64_be),
244 .aarch64_32 => return self.genArch(.aarch64_32),
245 .arc => return self.genArch(.arc),
246 .avr => return self.genArch(.avr),
247 .bpfel => return self.genArch(.bpfel),
248 .bpfeb => return self.genArch(.bpfeb),
249 .hexagon => return self.genArch(.hexagon),
250 .mips => return self.genArch(.mips),
251 .mipsel => return self.genArch(.mipsel),
252 .mips64 => return self.genArch(.mips64),
253 .mips64el => return self.genArch(.mips64el),
254 .msp430 => return self.genArch(.msp430),
255 .powerpc => return self.genArch(.powerpc),
256 .powerpc64 => return self.genArch(.powerpc64),
257 .powerpc64le => return self.genArch(.powerpc64le),
258 .r600 => return self.genArch(.r600),
259 .amdgcn => return self.genArch(.amdgcn),
260 .riscv32 => return self.genArch(.riscv32),
261 .riscv64 => return self.genArch(.riscv64),
262 .sparc => return self.genArch(.sparc),
263 .sparcv9 => return self.genArch(.sparcv9),
264 .sparcel => return self.genArch(.sparcel),
265 .s390x => return self.genArch(.s390x),
266 .tce => return self.genArch(.tce),
267 .tcele => return self.genArch(.tcele),
268 .thumb => return self.genArch(.thumb),
269 .thumbeb => return self.genArch(.thumbeb),
270 .i386 => return self.genArch(.i386),
271 .x86_64 => return self.genArch(.x86_64),
272 .xcore => return self.genArch(.xcore),
273 .nvptx => return self.genArch(.nvptx),
274 .nvptx64 => return self.genArch(.nvptx64),
275 .le32 => return self.genArch(.le32),
276 .le64 => return self.genArch(.le64),
277 .amdil => return self.genArch(.amdil),
278 .amdil64 => return self.genArch(.amdil64),
279 .hsail => return self.genArch(.hsail),
280 .hsail64 => return self.genArch(.hsail64),
281 .spir => return self.genArch(.spir),
282 .spir64 => return self.genArch(.spir64),
283 .kalimba => return self.genArch(.kalimba),
284 .shave => return self.genArch(.shave),
285 .lanai => return self.genArch(.lanai),
286 .wasm32 => return self.genArch(.wasm32),
287 .wasm64 => return self.genArch(.wasm64),
288 .renderscript32 => return self.genArch(.renderscript32),
289 .renderscript64 => return self.genArch(.renderscript64),
290 .ve => return self.genArch(.ve),
291 }
292 }
293
294 fn genArch(self: *Function, comptime arch: std.Target.Cpu.Arch) !void {
295 for (self.mod_fn.analysis.success.instructions) |inst| {
296 const new_inst = try self.genFuncInst(inst, arch);
297 try self.inst_table.putNoClobber(inst, new_inst);
298 }
299 }
300
301 fn genFuncInst(self: *Function, inst: *ir.Inst, comptime arch: std.Target.Cpu.Arch) !MCValue {
176 switch (inst.tag) {302 switch (inst.tag) {
177 .add => return self.genAdd(inst.cast(ir.Inst.Add).?),303 .add => return self.genAdd(inst.cast(ir.Inst.Add).?, arch),
178 .arg => return self.genArg(inst.src),304 .arg => return self.genArg(inst.cast(ir.Inst.Arg).?),
179 .block => return self.genBlock(inst.cast(ir.Inst.Block).?),305 .block => return self.genBlock(inst.cast(ir.Inst.Block).?, arch),
180 .breakpoint => return self.genBreakpoint(inst.src),306 .breakpoint => return self.genBreakpoint(inst.src, arch),
181 .call => return self.genCall(inst.cast(ir.Inst.Call).?),307 .call => return self.genCall(inst.cast(ir.Inst.Call).?, arch),
182 .unreach => return MCValue{ .unreach = {} },308 .unreach => return MCValue{ .unreach = {} },
183 .constant => unreachable, // excluded from function bodies309 .constant => unreachable, // excluded from function bodies
184 .assembly => return self.genAsm(inst.cast(ir.Inst.Assembly).?),310 .assembly => return self.genAsm(inst.cast(ir.Inst.Assembly).?, arch),
185 .ptrtoint => return self.genPtrToInt(inst.cast(ir.Inst.PtrToInt).?),311 .ptrtoint => return self.genPtrToInt(inst.cast(ir.Inst.PtrToInt).?),
186 .bitcast => return self.genBitCast(inst.cast(ir.Inst.BitCast).?),312 .bitcast => return self.genBitCast(inst.cast(ir.Inst.BitCast).?),
187 .ret => return self.genRet(inst.cast(ir.Inst.Ret).?),313 .ret => return self.genRet(inst.cast(ir.Inst.Ret).?, arch),
188 .retvoid => return self.genRetVoid(inst.cast(ir.Inst.RetVoid).?),314 .retvoid => return self.genRetVoid(inst.cast(ir.Inst.RetVoid).?, arch),
189 .cmp => return self.genCmp(inst.cast(ir.Inst.Cmp).?),315 .cmp => return self.genCmp(inst.cast(ir.Inst.Cmp).?, arch),
190 .condbr => return self.genCondBr(inst.cast(ir.Inst.CondBr).?),316 .condbr => return self.genCondBr(inst.cast(ir.Inst.CondBr).?, arch),
191 .isnull => return self.genIsNull(inst.cast(ir.Inst.IsNull).?),317 .isnull => return self.genIsNull(inst.cast(ir.Inst.IsNull).?, arch),
192 .isnonnull => return self.genIsNonNull(inst.cast(ir.Inst.IsNonNull).?),318 .isnonnull => return self.genIsNonNull(inst.cast(ir.Inst.IsNonNull).?, arch),
193 }319 }
194 }320 }
195321
196 fn genAdd(self: *Function, inst: *ir.Inst.Add) !MCValue {322 fn genAdd(self: *Function, inst: *ir.Inst.Add, comptime arch: std.Target.Cpu.Arch) !MCValue {
197 switch (self.target.cpu.arch) {323 const lhs = try self.resolveInst(inst.args.lhs);
324 const rhs = try self.resolveInst(inst.args.rhs);
325 switch (arch) {
326 .i386, .x86_64 => {
327 // const lhs_reg = try self.instAsReg(lhs);
328 // const rhs_reg = try self.instAsReg(rhs);
329 // const result = try self.allocateReg();
330
331 // try self.code.append(??);
332
333 // lhs_reg.release();
334 // rhs_reg.release();
335 return self.fail(inst.base.src, "TODO implement register allocation", .{});
336 },
198 else => return self.fail(inst.base.src, "TODO implement add for {}", .{self.target.cpu.arch}),337 else => return self.fail(inst.base.src, "TODO implement add for {}", .{self.target.cpu.arch}),
199 }338 }
200 }339 }
201340
202 fn genArg(self: *Function, src: usize) !MCValue {341 fn genArg(self: *Function, inst: *ir.Inst.Arg) !MCValue {
203 switch (self.target.cpu.arch) {342 return self.args[inst.args.index];
204 else => return self.fail(src, "TODO implement function parameters for {}", .{self.target.cpu.arch}),
205 }
206 return .none;
207 }343 }
208344
209 fn genBreakpoint(self: *Function, src: usize) !MCValue {345 fn genBreakpoint(self: *Function, src: usize, comptime arch: std.Target.Cpu.Arch) !MCValue {
210 switch (self.target.cpu.arch) {346 switch (arch) {
211 .i386, .x86_64 => {347 .i386, .x86_64 => {
212 try self.code.append(0xcc); // int3348 try self.code.append(0xcc); // int3
213 },349 },
...@@ -216,8 +352,8 @@ const Function = struct {...@@ -216,8 +352,8 @@ const Function = struct {
216 return .none;352 return .none;
217 }353 }
218354
219 fn genCall(self: *Function, inst: *ir.Inst.Call) !MCValue {355 fn genCall(self: *Function, inst: *ir.Inst.Call, comptime arch: std.Target.Cpu.Arch) !MCValue {
220 switch (self.target.cpu.arch) {356 switch (arch) {
221 .x86_64, .i386 => {357 .x86_64, .i386 => {
222 if (inst.args.func.cast(ir.Inst.Constant)) |func_inst| {358 if (inst.args.func.cast(ir.Inst.Constant)) |func_inst| {
223 if (inst.args.args.len != 0) {359 if (inst.args.args.len != 0) {
...@@ -251,11 +387,11 @@ const Function = struct {...@@ -251,11 +387,11 @@ const Function = struct {
251 }387 }
252 }388 }
253389
254 fn ret(self: *Function, src: usize, mcv: MCValue) !MCValue {390 fn ret(self: *Function, src: usize, comptime arch: std.Target.Cpu.Arch, mcv: MCValue) !MCValue {
255 if (mcv != .none) {391 if (mcv != .none) {
256 return self.fail(src, "TODO implement return with non-void operand", .{});392 return self.fail(src, "TODO implement return with non-void operand", .{});
257 }393 }
258 switch (self.target.cpu.arch) {394 switch (arch) {
259 .i386, .x86_64 => {395 .i386, .x86_64 => {
260 try self.code.append(0xc3); // ret396 try self.code.append(0xc3); // ret
261 },397 },
...@@ -264,43 +400,43 @@ const Function = struct {...@@ -264,43 +400,43 @@ const Function = struct {
264 return .unreach;400 return .unreach;
265 }401 }
266402
267 fn genRet(self: *Function, inst: *ir.Inst.Ret) !MCValue {403 fn genRet(self: *Function, inst: *ir.Inst.Ret, comptime arch: std.Target.Cpu.Arch) !MCValue {
268 const operand = try self.resolveInst(inst.args.operand);404 const operand = try self.resolveInst(inst.args.operand);
269 return self.ret(inst.base.src, operand);405 return self.ret(inst.base.src, arch, operand);
270 }406 }
271407
272 fn genRetVoid(self: *Function, inst: *ir.Inst.RetVoid) !MCValue {408 fn genRetVoid(self: *Function, inst: *ir.Inst.RetVoid, comptime arch: std.Target.Cpu.Arch) !MCValue {
273 return self.ret(inst.base.src, .none);409 return self.ret(inst.base.src, arch, .none);
274 }410 }
275411
276 fn genCmp(self: *Function, inst: *ir.Inst.Cmp) !MCValue {412 fn genCmp(self: *Function, inst: *ir.Inst.Cmp, comptime arch: std.Target.Cpu.Arch) !MCValue {
277 switch (self.target.cpu.arch) {413 switch (arch) {
278 else => return self.fail(inst.base.src, "TODO implement cmp for {}", .{self.target.cpu.arch}),414 else => return self.fail(inst.base.src, "TODO implement cmp for {}", .{self.target.cpu.arch}),
279 }415 }
280 }416 }
281417
282 fn genCondBr(self: *Function, inst: *ir.Inst.CondBr) !MCValue {418 fn genCondBr(self: *Function, inst: *ir.Inst.CondBr, comptime arch: std.Target.Cpu.Arch) !MCValue {
283 switch (self.target.cpu.arch) {419 switch (arch) {
284 else => return self.fail(inst.base.src, "TODO implement condbr for {}", .{self.target.cpu.arch}),420 else => return self.fail(inst.base.src, "TODO implement condbr for {}", .{self.target.cpu.arch}),
285 }421 }
286 }422 }
287423
288 fn genIsNull(self: *Function, inst: *ir.Inst.IsNull) !MCValue {424 fn genIsNull(self: *Function, inst: *ir.Inst.IsNull, comptime arch: std.Target.Cpu.Arch) !MCValue {
289 switch (self.target.cpu.arch) {425 switch (arch) {
290 else => return self.fail(inst.base.src, "TODO implement isnull for {}", .{self.target.cpu.arch}),426 else => return self.fail(inst.base.src, "TODO implement isnull for {}", .{self.target.cpu.arch}),
291 }427 }
292 }428 }
293429
294 fn genIsNonNull(self: *Function, inst: *ir.Inst.IsNonNull) !MCValue {430 fn genIsNonNull(self: *Function, inst: *ir.Inst.IsNonNull, comptime arch: std.Target.Cpu.Arch) !MCValue {
295 // Here you can specialize this instruction if it makes sense to, otherwise the default431 // Here you can specialize this instruction if it makes sense to, otherwise the default
296 // will call genIsNull and invert the result.432 // will call genIsNull and invert the result.
297 switch (self.target.cpu.arch) {433 switch (arch) {
298 else => return self.fail(inst.base.src, "TODO call genIsNull and invert the result ", .{}),434 else => return self.fail(inst.base.src, "TODO call genIsNull and invert the result ", .{}),
299 }435 }
300 }436 }
301437
302 fn genRelativeFwdJump(self: *Function, src: usize, amount: u32) !void {438 fn genRelativeFwdJump(self: *Function, src: usize, comptime arch: std.Target.Cpu.Arch, amount: u32) !void {
303 switch (self.target.cpu.arch) {439 switch (arch) {
304 .i386, .x86_64 => {440 .i386, .x86_64 => {
305 // TODO x86 treats the operands as signed441 // TODO x86 treats the operands as signed
306 if (amount <= std.math.maxInt(u8)) {442 if (amount <= std.math.maxInt(u8)) {
...@@ -318,70 +454,13 @@ const Function = struct {...@@ -318,70 +454,13 @@ const Function = struct {
318 }454 }
319 }455 }
320456
321 fn genBlock(self: *Function, inst: *ir.Inst.Block) !MCValue {457 fn genBlock(self: *Function, inst: *ir.Inst.Block, comptime arch: std.Target.Cpu.Arch) !MCValue {
322 switch (self.target.cpu.arch) {458 switch (arch) {
323 else => return self.fail(inst.base.src, "TODO implement codegen Block for {}", .{self.target.cpu.arch}),459 else => return self.fail(inst.base.src, "TODO implement codegen Block for {}", .{self.target.cpu.arch}),
324 }460 }
325 }461 }
326462
327 fn genAsm(self: *Function, inst: *ir.Inst.Assembly) !MCValue {463 fn genAsm(self: *Function, inst: *ir.Inst.Assembly, comptime arch: Target.Cpu.Arch) !MCValue {
328 // TODO convert to inline function
329 switch (self.target.cpu.arch) {
330 .arm => return self.genAsmArch(.arm, inst),
331 .armeb => return self.genAsmArch(.armeb, inst),
332 .aarch64 => return self.genAsmArch(.aarch64, inst),
333 .aarch64_be => return self.genAsmArch(.aarch64_be, inst),
334 .aarch64_32 => return self.genAsmArch(.aarch64_32, inst),
335 .arc => return self.genAsmArch(.arc, inst),
336 .avr => return self.genAsmArch(.avr, inst),
337 .bpfel => return self.genAsmArch(.bpfel, inst),
338 .bpfeb => return self.genAsmArch(.bpfeb, inst),
339 .hexagon => return self.genAsmArch(.hexagon, inst),
340 .mips => return self.genAsmArch(.mips, inst),
341 .mipsel => return self.genAsmArch(.mipsel, inst),
342 .mips64 => return self.genAsmArch(.mips64, inst),
343 .mips64el => return self.genAsmArch(.mips64el, inst),
344 .msp430 => return self.genAsmArch(.msp430, inst),
345 .powerpc => return self.genAsmArch(.powerpc, inst),
346 .powerpc64 => return self.genAsmArch(.powerpc64, inst),
347 .powerpc64le => return self.genAsmArch(.powerpc64le, inst),
348 .r600 => return self.genAsmArch(.r600, inst),
349 .amdgcn => return self.genAsmArch(.amdgcn, inst),
350 .riscv32 => return self.genAsmArch(.riscv32, inst),
351 .riscv64 => return self.genAsmArch(.riscv64, inst),
352 .sparc => return self.genAsmArch(.sparc, inst),
353 .sparcv9 => return self.genAsmArch(.sparcv9, inst),
354 .sparcel => return self.genAsmArch(.sparcel, inst),
355 .s390x => return self.genAsmArch(.s390x, inst),
356 .tce => return self.genAsmArch(.tce, inst),
357 .tcele => return self.genAsmArch(.tcele, inst),
358 .thumb => return self.genAsmArch(.thumb, inst),
359 .thumbeb => return self.genAsmArch(.thumbeb, inst),
360 .i386 => return self.genAsmArch(.i386, inst),
361 .x86_64 => return self.genAsmArch(.x86_64, inst),
362 .xcore => return self.genAsmArch(.xcore, inst),
363 .nvptx => return self.genAsmArch(.nvptx, inst),
364 .nvptx64 => return self.genAsmArch(.nvptx64, inst),
365 .le32 => return self.genAsmArch(.le32, inst),
366 .le64 => return self.genAsmArch(.le64, inst),
367 .amdil => return self.genAsmArch(.amdil, inst),
368 .amdil64 => return self.genAsmArch(.amdil64, inst),
369 .hsail => return self.genAsmArch(.hsail, inst),
370 .hsail64 => return self.genAsmArch(.hsail64, inst),
371 .spir => return self.genAsmArch(.spir, inst),
372 .spir64 => return self.genAsmArch(.spir64, inst),
373 .kalimba => return self.genAsmArch(.kalimba, inst),
374 .shave => return self.genAsmArch(.shave, inst),
375 .lanai => return self.genAsmArch(.lanai, inst),
376 .wasm32 => return self.genAsmArch(.wasm32, inst),
377 .wasm64 => return self.genAsmArch(.wasm64, inst),
378 .renderscript32 => return self.genAsmArch(.renderscript32, inst),
379 .renderscript64 => return self.genAsmArch(.renderscript64, inst),
380 .ve => return self.genAsmArch(.ve, inst),
381 }
382 }
383
384 fn genAsmArch(self: *Function, comptime arch: Target.Cpu.Arch, inst: *ir.Inst.Assembly) !MCValue {
385 if (arch != .x86_64 and arch != .i386) {464 if (arch != .x86_64 and arch != .i386) {
386 return self.fail(inst.base.src, "TODO implement inline asm support for more architectures", .{});465 return self.fail(inst.base.src, "TODO implement inline asm support for more architectures", .{});
387 }466 }
...@@ -607,6 +686,9 @@ const Function = struct {...@@ -607,6 +686,9 @@ const Function = struct {
607 }686 }
608 }687 }
609 },688 },
689 .stack_offset => |off| {
690 return self.fail(src, "TODO implement genSetReg for stack variables", .{});
691 },
610 },692 },
611 else => return self.fail(src, "TODO implement genSetReg for more architectures", .{}),693 else => return self.fail(src, "TODO implement genSetReg for more architectures", .{}),
612 }694 }
src-self-hosted/codegen/x86_64.zig+6-5
...@@ -1,20 +1,21 @@...@@ -1,20 +1,21 @@
1const Type = @import("../Type.zig");
2
1// zig fmt: off3// zig fmt: off
24
3/// Definitions of all of the x64 registers. The order is very, very important.5/// Definitions of all of the x64 registers. The order is semantically meaningful.
4/// The registers are defined such that IDs go in descending order of 64-bit,6/// The registers are defined such that IDs go in descending order of 64-bit,
5/// 32-bit, 16-bit, and then 8-bit, and each set contains exactly sixteen7/// 32-bit, 16-bit, and then 8-bit, and each set contains exactly sixteen
6/// registers. This results in some very, very useful properties:8/// registers. This results in some useful properties:
7///9///
8/// Any 64-bit register can be turned into its 32-bit form by adding 16, and10/// Any 64-bit register can be turned into its 32-bit form by adding 16, and
9/// vice versa. This also works between 32-bit and 16-bit forms. With 8-bit, it11/// vice versa. This also works between 32-bit and 16-bit forms. With 8-bit, it
10/// works for all except for sp, bp, si, and di, which don't *have* an 8-bit12/// works for all except for sp, bp, si, and di, which do *not* have an 8-bit
11/// form.13/// form.
12///14///
13/// If (register & 8) is set, the register is extended.15/// If (register & 8) is set, the register is extended.
14///16///
15/// The ID can be easily determined by figuring out what range the register is17/// The ID can be easily determined by figuring out what range the register is
16/// in, and then subtracting the base.18/// in, and then subtracting the base.
17///
18pub const Register = enum(u8) {19pub const Register = enum(u8) {
19 // 0 through 15, 64-bit registers. 8-15 are extended.20 // 0 through 15, 64-bit registers. 8-15 are extended.
20 // id is just the int value.21 // id is just the int value.
...@@ -66,4 +67,4 @@ pub const Register = enum(u8) {...@@ -66,4 +67,4 @@ pub const Register = enum(u8) {
66 }67 }
67};68};
6869
69// zig fmt: on70// zig fmt: on
\ No newline at end of file
src-self-hosted/type.zig+70
...@@ -535,6 +535,76 @@ pub const Type = extern union {...@@ -535,6 +535,76 @@ pub const Type = extern union {
535 };535 };
536 }536 }
537537
538 /// Asserts the type has the ABI size already resolved.
539 pub fn abiSize(self: Type, target: Target) u64 {
540 return switch (self.tag()) {
541 .fn_noreturn_no_args => unreachable, // represents machine code; not a pointer
542 .fn_void_no_args => unreachable, // represents machine code; not a pointer
543 .fn_naked_noreturn_no_args => unreachable, // represents machine code; not a pointer
544 .fn_ccc_void_no_args => unreachable, // represents machine code; not a pointer
545 .function => unreachable, // represents machine code; not a pointer
546 .c_void => unreachable,
547 .void => unreachable,
548 .type => unreachable,
549 .comptime_int => unreachable,
550 .comptime_float => unreachable,
551 .noreturn => unreachable,
552 .@"null" => unreachable,
553 .@"undefined" => unreachable,
554
555 .u8,
556 .i8,
557 .bool,
558 => return 1,
559
560 .array_u8_sentinel_0 => @fieldParentPtr(Payload.Array_u8_Sentinel0, "base", self.ptr_otherwise).len,
561 .array => {
562 const payload = @fieldParentPtr(Payload.Array, "base", self.ptr_otherwise);
563 const elem_size = std.math.max(payload.elem_type.abiAlignment(target), payload.elem_type.abiSize(target));
564 return payload.len * elem_size;
565 },
566 .i16, .u16 => return 2,
567 .i32, .u32 => return 4,
568 .i64, .u64 => return 8,
569
570 .isize,
571 .usize,
572 .single_const_pointer_to_comptime_int,
573 .const_slice_u8,
574 .single_const_pointer,
575 => return @divExact(target.cpu.arch.ptrBitWidth(), 8),
576
577 .c_short => return @divExact(CType.short.sizeInBits(target), 8),
578 .c_ushort => return @divExact(CType.ushort.sizeInBits(target), 8),
579 .c_int => return @divExact(CType.int.sizeInBits(target), 8),
580 .c_uint => return @divExact(CType.uint.sizeInBits(target), 8),
581 .c_long => return @divExact(CType.long.sizeInBits(target), 8),
582 .c_ulong => return @divExact(CType.ulong.sizeInBits(target), 8),
583 .c_longlong => return @divExact(CType.longlong.sizeInBits(target), 8),
584 .c_ulonglong => return @divExact(CType.ulonglong.sizeInBits(target), 8),
585
586 .f16 => return 2,
587 .f32 => return 4,
588 .f64 => return 8,
589 .f128 => return 16,
590 .c_longdouble => return 16,
591
592 .anyerror => return 2, // TODO revisit this when we have the concept of the error tag type
593
594
595 .int_signed, .int_unsigned => {
596 const bits: u16 = if (self.cast(Payload.IntSigned)) |pl|
597 pl.bits
598 else if (self.cast(Payload.IntUnsigned)) |pl|
599 pl.bits
600 else
601 unreachable;
602
603 return std.math.ceilPowerOfTwoPromote(u16, (bits + 7) / 8);
604 },
605 };
606 }
607
538 pub fn isSinglePointer(self: Type) bool {608 pub fn isSinglePointer(self: Type) bool {
539 return switch (self.tag()) {609 return switch (self.tag()) {
540 .u8,610 .u8,