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 {
4949
5050 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
5752 const skip_release = b.option(bool, "skip-release", "Main test suite skips release builds") orelse false;
5853 const skip_release_small = b.option(bool, "skip-release-small", "Main test suite skips release-small builds") orelse skip_release;
5954 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 {
6358
6459 const only_install_lib_files = b.option(bool, "lib-files-only", "Only install library files") orelse false;
6560 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 }
7262 if (!only_install_lib_files) {
73 exe.install();
74 }
75 const tracy = b.option([]const u8, "tracy", "Enable Tracy integration. Supply path to Tracy source");
76 const link_libc = b.option(bool, "force-link-libc", "Force self-hosted compiler to link libc") orelse false;
77 if (link_libc) exe.linkLibC();
63 var exe = b.addExecutable("zig", "src-self-hosted/main.zig");
64 exe.setBuildMode(mode);
65 test_step.dependOn(&exe.step);
66 b.default_step.dependOn(&exe.step);
7867
79 exe.addBuildOption(bool, "enable_tracy", tracy != null);
80 if (tracy) |tracy_path| {
81 const client_cpp = fs.path.join(
82 b.allocator,
83 &[_][]const u8{ tracy_path, "TracyClient.cpp" },
84 ) catch unreachable;
85 exe.addIncludeDir(tracy_path);
86 exe.addCSourceFile(client_cpp, &[_][]const u8{ "-DTRACY_ENABLE=1", "-fno-sanitize=undefined" });
87 exe.linkSystemLibraryName("c++");
88 exe.linkLibC();
68 if (enable_llvm) {
69 var ctx = parseConfigH(b, config_h_text);
70 ctx.llvm = try findLLVM(b, ctx.llvm_config_exe);
71
72 try configureStage2(b, exe, ctx);
73 }
74 if (!only_install_lib_files) {
75 exe.install();
76 }
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 }
8992 }
9093
9194 b.installDirectory(InstallDirectoryOptions{
doc/langref.html.in+23-1
......@@ -7530,7 +7530,7 @@ test "@hasDecl" {
75307530 source file than the one they are declared in.
75317531 </p>
75327532 <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.
75347534 If it is a relative path, it is relative to the file that contains the {#syntax#}@import{#endsyntax#}
75357535 function call.
75367536 </p>
......@@ -8030,7 +8030,29 @@ test "vector @splat" {
80308030 </p>
80318031 {#see_also|Vectors|@shuffle#}
80328032 {#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#}
80348056 {#header_open|@sqrt#}
80358057 <pre>{#syntax#}@sqrt(value: var) @TypeOf(value){#endsyntax#}</pre>
80368058 <p>
lib/std/elf.zig+1
......@@ -552,6 +552,7 @@ fn preadNoEof(file: std.fs.File, buf: []u8, offset: u64) !void {
552552 error.Unexpected => return error.Unexpected,
553553 error.WouldBlock => return error.Unexpected,
554554 error.NotOpenForReading => return error.Unexpected,
555 error.AccessDenied => return error.Unexpected,
555556 };
556557 if (len == 0) return error.UnexpectedEndOfFile;
557558 i += len;
lib/std/fs.zig+32-12
......@@ -535,14 +535,15 @@ pub const Dir = struct {
535535 w.EFAULT => unreachable,
536536 w.ENOTDIR => unreachable,
537537 w.EINVAL => unreachable,
538 w.ENOTCAPABLE => return error.AccessDenied,
538539 else => |err| return os.unexpectedErrno(err),
539540 }
540541 if (bufused == 0) return null;
541542 self.index = 0;
542543 self.end_index = bufused;
543544 }
544 const entry = @ptrCast(*align(1) os.wasi.dirent_t, &self.buf[self.index]);
545 const entry_size = @sizeOf(os.wasi.dirent_t);
545 const entry = @ptrCast(*align(1) w.dirent_t, &self.buf[self.index]);
546 const entry_size = @sizeOf(w.dirent_t);
546547 const name_index = self.index + entry_size;
547548 const name = mem.span(self.buf[name_index .. name_index + entry.d_namlen]);
548549
......@@ -556,12 +557,12 @@ pub const Dir = struct {
556557 }
557558
558559 const entry_kind = switch (entry.d_type) {
559 wasi.FILETYPE_BLOCK_DEVICE => Entry.Kind.BlockDevice,
560 wasi.FILETYPE_CHARACTER_DEVICE => Entry.Kind.CharacterDevice,
561 wasi.FILETYPE_DIRECTORY => Entry.Kind.Directory,
562 wasi.FILETYPE_SYMBOLIC_LINK => Entry.Kind.SymLink,
563 wasi.FILETYPE_REGULAR_FILE => Entry.Kind.File,
564 wasi.FILETYPE_SOCKET_STREAM, wasi.FILETYPE_SOCKET_DGRAM => Entry.Kind.UnixDomainSocket,
560 w.FILETYPE_BLOCK_DEVICE => Entry.Kind.BlockDevice,
561 w.FILETYPE_CHARACTER_DEVICE => Entry.Kind.CharacterDevice,
562 w.FILETYPE_DIRECTORY => Entry.Kind.Directory,
563 w.FILETYPE_SYMBOLIC_LINK => Entry.Kind.SymLink,
564 w.FILETYPE_REGULAR_FILE => Entry.Kind.File,
565 w.FILETYPE_SOCKET_STREAM, wasi.FILETYPE_SOCKET_DGRAM => Entry.Kind.UnixDomainSocket,
565566 else => Entry.Kind.Unknown,
566567 };
567568 return Entry{
......@@ -1110,10 +1111,18 @@ pub const Dir = struct {
11101111 /// Delete a file name and possibly the file it refers to, based on an open directory handle.
11111112 /// Asserts that the path parameter has no null bytes.
11121113 pub fn deleteFile(self: Dir, sub_path: []const u8) DeleteFileError!void {
1113 os.unlinkat(self.fd, sub_path, 0) catch |err| switch (err) {
1114 error.DirNotEmpty => unreachable, // not passing AT_REMOVEDIR
1115 else => |e| return e,
1116 };
1114 if (builtin.os.tag == .windows) {
1115 const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path);
1116 return self.deleteFileW(sub_path_w.span().ptr);
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 }
11171126 }
11181127
11191128 pub const deleteFileC = @compileError("deprecated: renamed to deleteFileZ");
......@@ -1122,6 +1131,17 @@ pub const Dir = struct {
11221131 pub fn deleteFileZ(self: Dir, sub_path_c: [*:0]const u8) DeleteFileError!void {
11231132 os.unlinkatZ(self.fd, sub_path_c, 0) catch |err| switch (err) {
11241133 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 },
11251145 else => |e| return e,
11261146 };
11271147 }
lib/std/fs/test.zig+37
......@@ -73,6 +73,43 @@ test "directory operations on files" {
7373 file.close();
7474}
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
76113test "openSelfExe" {
77114 if (builtin.os.tag == .wasi) return error.SkipZigTest;
78115
lib/std/heap.zig+5
......@@ -714,6 +714,11 @@ test "PageAllocator" {
714714 slice[127] = 0x34;
715715 allocator.free(slice);
716716 }
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 }
717722}
718723
719724test "HeapAllocator" {
lib/std/heap/arena_allocator.zig+2-3
......@@ -49,9 +49,8 @@ pub const ArenaAllocator = struct {
4949 const actual_min_size = minimum_size + (@sizeOf(BufNode) + 16);
5050 const big_enough_len = prev_len + actual_min_size;
5151 const len = big_enough_len + big_enough_len / 2;
52 const buf = try self.child_allocator.alignedAlloc(u8, @alignOf(BufNode), len);
53 const buf_node_slice = mem.bytesAsSlice(BufNode, buf[0..@sizeOf(BufNode)]);
54 const buf_node = &buf_node_slice[0];
52 const buf = try self.child_allocator.callAllocFn(len, @alignOf(BufNode), 1);
53 const buf_node = @ptrCast(*BufNode, @alignCast(@alignOf(BufNode), buf.ptr));
5554 buf_node.* = BufNode{
5655 .data = buf,
5756 .next = null,
lib/std/mem.zig+4-7
......@@ -116,9 +116,6 @@ pub const Allocator = struct {
116116 if (isAligned(@ptrToInt(old_mem.ptr), new_alignment)) {
117117 if (new_byte_count <= old_mem.len) {
118118 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 }
122119 return old_mem.ptr[0..shrunk_len];
123120 }
124121 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 {
723720 @field(value, field.name) = @field(init, field.name);
724721 },
725722 }
726 } else if (field.default_value != null) {
727 @field(value, field.name) = field.default_value;
723 } else if (field.default_value) |default_value| {
724 @field(value, field.name) = default_value;
728725 }
729726 }
730727
......@@ -751,7 +748,7 @@ test "zeroInit" {
751748 b: ?bool,
752749 c: I,
753750 e: [3]u8,
754 f: i64,
751 f: i64 = -1,
755752 };
756753
757754 const s = zeroInit(S, .{
......@@ -765,7 +762,7 @@ test "zeroInit" {
765762 .d = 0,
766763 },
767764 .e = [3]u8{ 0, 0, 0 },
768 .f = 0,
765 .f = -1,
769766 });
770767}
771768
lib/std/os.zig+76-23
......@@ -301,6 +301,10 @@ pub const ReadError = error{
301301 /// This error occurs when no global event loop is configured,
302302 /// and reading from the file descriptor would block.
303303 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,
304308} || UnexpectedError;
305309
306310/// 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 {
336340 wasi.ENOMEM => return error.SystemResources,
337341 wasi.ECONNRESET => return error.ConnectionResetByPeer,
338342 wasi.ETIMEDOUT => return error.ConnectionTimedOut,
343 wasi.ENOTCAPABLE => return error.AccessDenied,
339344 else => |err| return unexpectedErrno(err),
340345 }
341346 }
......@@ -403,6 +408,7 @@ pub fn readv(fd: fd_t, iov: []const iovec) ReadError!usize {
403408 wasi.EISDIR => return error.IsDir,
404409 wasi.ENOBUFS => return error.SystemResources,
405410 wasi.ENOMEM => return error.SystemResources,
411 wasi.ENOTCAPABLE => return error.AccessDenied,
406412 else => |err| return unexpectedErrno(err),
407413 }
408414 }
......@@ -467,6 +473,7 @@ pub fn pread(fd: fd_t, buf: []u8, offset: u64) PReadError!usize {
467473 wasi.ENXIO => return error.Unseekable,
468474 wasi.ESPIPE => return error.Unseekable,
469475 wasi.EOVERFLOW => return error.Unseekable,
476 wasi.ENOTCAPABLE => return error.AccessDenied,
470477 else => |err| return unexpectedErrno(err),
471478 }
472479 }
......@@ -501,8 +508,11 @@ pub fn pread(fd: fd_t, buf: []u8, offset: u64) PReadError!usize {
501508pub const TruncateError = error{
502509 FileTooBig,
503510 InputOutput,
504 CannotTruncate,
505511 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,
506516} || UnexpectedError;
507517
508518pub fn ftruncate(fd: fd_t, length: u64) TruncateError!void {
......@@ -523,7 +533,7 @@ pub fn ftruncate(fd: fd_t, length: u64) TruncateError!void {
523533 switch (rc) {
524534 .SUCCESS => return,
525535 .INVALID_HANDLE => unreachable, // Handle not open for writing
526 .ACCESS_DENIED => return error.CannotTruncate,
536 .ACCESS_DENIED => return error.AccessDenied,
527537 else => return windows.unexpectedStatus(rc),
528538 }
529539 }
......@@ -533,10 +543,11 @@ pub fn ftruncate(fd: fd_t, length: u64) TruncateError!void {
533543 wasi.EINTR => unreachable,
534544 wasi.EFBIG => return error.FileTooBig,
535545 wasi.EIO => return error.InputOutput,
536 wasi.EPERM => return error.CannotTruncate,
546 wasi.EPERM => return error.AccessDenied,
537547 wasi.ETXTBSY => return error.FileBusy,
538548 wasi.EBADF => unreachable, // Handle not open for writing
539549 wasi.EINVAL => unreachable, // Handle not open for writing
550 wasi.ENOTCAPABLE => return error.AccessDenied,
540551 else => |err| return unexpectedErrno(err),
541552 }
542553 }
......@@ -555,7 +566,7 @@ pub fn ftruncate(fd: fd_t, length: u64) TruncateError!void {
555566 EINTR => continue,
556567 EFBIG => return error.FileTooBig,
557568 EIO => return error.InputOutput,
558 EPERM => return error.CannotTruncate,
569 EPERM => return error.AccessDenied,
559570 ETXTBSY => return error.FileBusy,
560571 EBADF => unreachable, // Handle not open for writing
561572 EINVAL => unreachable, // Handle not open for writing
......@@ -605,6 +616,7 @@ pub fn preadv(fd: fd_t, iov: []const iovec, offset: u64) PReadError!usize {
605616 wasi.ENXIO => return error.Unseekable,
606617 wasi.ESPIPE => return error.Unseekable,
607618 wasi.EOVERFLOW => return error.Unseekable,
619 wasi.ENOTCAPABLE => return error.AccessDenied,
608620 else => |err| return unexpectedErrno(err),
609621 }
610622 }
......@@ -642,6 +654,9 @@ pub const WriteError = error{
642654 FileTooBig,
643655 InputOutput,
644656 NoSpaceLeft,
657
658 /// In WASI, this error may occur when the file descriptor does
659 /// not hold the required rights to write to it.
645660 AccessDenied,
646661 BrokenPipe,
647662 SystemResources,
......@@ -699,6 +714,7 @@ pub fn write(fd: fd_t, bytes: []const u8) WriteError!usize {
699714 wasi.ENOSPC => return error.NoSpaceLeft,
700715 wasi.EPERM => return error.AccessDenied,
701716 wasi.EPIPE => return error.BrokenPipe,
717 wasi.ENOTCAPABLE => return error.AccessDenied,
702718 else => |err| return unexpectedErrno(err),
703719 }
704720 }
......@@ -776,6 +792,7 @@ pub fn writev(fd: fd_t, iov: []const iovec_const) WriteError!usize {
776792 wasi.ENOSPC => return error.NoSpaceLeft,
777793 wasi.EPERM => return error.AccessDenied,
778794 wasi.EPIPE => return error.BrokenPipe,
795 wasi.ENOTCAPABLE => return error.AccessDenied,
779796 else => |err| return unexpectedErrno(err),
780797 }
781798 }
......@@ -858,6 +875,7 @@ pub fn pwrite(fd: fd_t, bytes: []const u8, offset: u64) PWriteError!usize {
858875 wasi.ENXIO => return error.Unseekable,
859876 wasi.ESPIPE => return error.Unseekable,
860877 wasi.EOVERFLOW => return error.Unseekable,
878 wasi.ENOTCAPABLE => return error.AccessDenied,
861879 else => |err| return unexpectedErrno(err),
862880 }
863881 }
......@@ -951,6 +969,7 @@ pub fn pwritev(fd: fd_t, iov: []const iovec_const, offset: u64) PWriteError!usiz
951969 wasi.ENXIO => return error.Unseekable,
952970 wasi.ESPIPE => return error.Unseekable,
953971 wasi.EOVERFLOW => return error.Unseekable,
972 wasi.ENOTCAPABLE => return error.AccessDenied,
954973 else => |err| return unexpectedErrno(err),
955974 }
956975 }
......@@ -986,6 +1005,8 @@ pub fn pwritev(fd: fd_t, iov: []const iovec_const, offset: u64) PWriteError!usiz
9861005}
9871006
9881007pub 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.
9891010 AccessDenied,
9901011 SymLinkLoop,
9911012 ProcessFdQuotaExceeded,
......@@ -1115,6 +1136,7 @@ pub fn openatWasi(dir_fd: fd_t, file_path: []const u8, oflags: oflags_t, fdflags
11151136 wasi.EPERM => return error.AccessDenied,
11161137 wasi.EEXIST => return error.PathAlreadyExists,
11171138 wasi.EBUSY => return error.DeviceBusy,
1139 wasi.ENOTCAPABLE => return error.AccessDenied,
11181140 else => |err| return unexpectedErrno(err),
11191141 }
11201142 }
......@@ -1501,6 +1523,8 @@ pub fn getcwd(out_buffer: []u8) GetCwdError![]u8 {
15011523}
15021524
15031525pub 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.
15041528 AccessDenied,
15051529 DiskQuota,
15061530 PathAlreadyExists,
......@@ -1606,13 +1630,14 @@ pub fn symlinkatWasi(target_path: []const u8, newdirfd: fd_t, sym_link_path: []c
16061630 wasi.ENOMEM => return error.SystemResources,
16071631 wasi.ENOSPC => return error.NoSpaceLeft,
16081632 wasi.EROFS => return error.ReadOnlyFileSystem,
1633 wasi.ENOTCAPABLE => return error.AccessDenied,
16091634 else => |err| return unexpectedErrno(err),
16101635 }
16111636}
16121637
16131638/// Windows-only. The same as `symlinkat` except the paths are null-terminated, WTF-16 encoded.
16141639/// 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 {
16161641 @compileError("TODO implement on Windows");
16171642}
16181643
......@@ -1646,6 +1671,9 @@ pub fn symlinkatZ(target_path: [*:0]const u8, newdirfd: fd_t, sym_link_path: [*:
16461671
16471672pub const UnlinkError = error{
16481673 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.
16491677 AccessDenied,
16501678 FileBusy,
16511679 FileSystem,
......@@ -1749,6 +1777,7 @@ pub fn unlinkatWasi(dirfd: fd_t, file_path: []const u8, flags: u32) UnlinkatErro
17491777 wasi.ENOMEM => return error.SystemResources,
17501778 wasi.EROFS => return error.ReadOnlyFileSystem,
17511779 wasi.ENOTEMPTY => return error.DirNotEmpty,
1780 wasi.ENOTCAPABLE => return error.AccessDenied,
17521781
17531782 wasi.EINVAL => unreachable, // invalid flags, or pathname has . as last component
17541783 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
18511880}
18521881
18531882const 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.
18541885 AccessDenied,
18551886 FileBusy,
18561887 DiskQuota,
......@@ -1970,6 +2001,7 @@ pub fn renameatWasi(old_dir_fd: fd_t, old_path: []const u8, new_dir_fd: fd_t, ne
19702001 wasi.ENOTEMPTY => return error.PathAlreadyExists,
19712002 wasi.EROFS => return error.ReadOnlyFileSystem,
19722003 wasi.EXDEV => return error.RenameAcrossMountPoints,
2004 wasi.ENOTCAPABLE => return error.AccessDenied,
19732005 else => |err| return unexpectedErrno(err),
19742006 }
19752007}
......@@ -2068,23 +2100,6 @@ pub fn renameatW(
20682100 }
20692101}
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
20882103pub fn mkdirat(dir_fd: fd_t, sub_dir_path: []const u8, mode: u32) MakeDirError!void {
20892104 if (builtin.os.tag == .windows) {
20902105 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
21162131 wasi.ENOSPC => return error.NoSpaceLeft,
21172132 wasi.ENOTDIR => return error.NotDir,
21182133 wasi.EROFS => return error.ReadOnlyFileSystem,
2134 wasi.ENOTCAPABLE => return error.AccessDenied,
21192135 else => |err| return unexpectedErrno(err),
21202136 }
21212137}
......@@ -2150,6 +2166,25 @@ pub fn mkdiratW(dir_fd: fd_t, sub_path_w: [*:0]const u16, mode: u32) MakeDirErro
21502166 windows.CloseHandle(sub_dir_handle);
21512167}
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
21532188/// Create a directory.
21542189/// `mode` is ignored on Windows.
21552190pub fn mkdir(dir_path: []const u8, mode: u32) MakeDirError!void {
......@@ -2313,6 +2348,8 @@ pub fn fchdir(dirfd: fd_t) FchdirError!void {
23132348}
23142349
23152350pub 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.
23162353 AccessDenied,
23172354 FileSystem,
23182355 SymLinkLoop,
......@@ -2398,6 +2435,7 @@ pub fn readlinkatWasi(dirfd: fd_t, file_path: []const u8, out_buffer: []u8) Read
23982435 wasi.ENOENT => return error.FileNotFound,
23992436 wasi.ENOMEM => return error.SystemResources,
24002437 wasi.ENOTDIR => return error.NotDir,
2438 wasi.ENOTCAPABLE => return error.AccessDenied,
24012439 else => |err| return unexpectedErrno(err),
24022440 }
24032441}
......@@ -3075,6 +3113,9 @@ pub fn waitpid(pid: i32, flags: u32) u32 {
30753113
30763114pub const FStatError = error{
30773115 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.
30783119 AccessDenied,
30793120} || UnexpectedError;
30803121
......@@ -3088,6 +3129,7 @@ pub fn fstat(fd: fd_t) FStatError!Stat {
30883129 wasi.EBADF => unreachable, // Always a race condition.
30893130 wasi.ENOMEM => return error.SystemResources,
30903131 wasi.EACCES => return error.AccessDenied,
3132 wasi.ENOTCAPABLE => return error.AccessDenied,
30913133 else => |err| return unexpectedErrno(err),
30923134 }
30933135 }
......@@ -3138,6 +3180,7 @@ pub fn fstatatWasi(dirfd: fd_t, pathname: []const u8, flags: u32) FStatAtError!S
31383180 wasi.ENAMETOOLONG => return error.NameTooLong,
31393181 wasi.ENOENT => return error.FileNotFound,
31403182 wasi.ENOTDIR => return error.FileNotFound,
3183 wasi.ENOTCAPABLE => return error.AccessDenied,
31413184 else => |err| return unexpectedErrno(err),
31423185 }
31433186}
......@@ -3643,7 +3686,13 @@ pub fn gettimeofday(tv: ?*timeval, tz: ?*timezone) void {
36433686 }
36443687}
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
36483697/// Repositions read/write file offset relative to the beginning.
36493698pub 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 {
36713720 wasi.EOVERFLOW => return error.Unseekable,
36723721 wasi.ESPIPE => return error.Unseekable,
36733722 wasi.ENXIO => return error.Unseekable,
3723 wasi.ENOTCAPABLE => return error.AccessDenied,
36743724 else => |err| return unexpectedErrno(err),
36753725 }
36763726 }
......@@ -3712,6 +3762,7 @@ pub fn lseek_CUR(fd: fd_t, offset: i64) SeekError!void {
37123762 wasi.EOVERFLOW => return error.Unseekable,
37133763 wasi.ESPIPE => return error.Unseekable,
37143764 wasi.ENXIO => return error.Unseekable,
3765 wasi.ENOTCAPABLE => return error.AccessDenied,
37153766 else => |err| return unexpectedErrno(err),
37163767 }
37173768 }
......@@ -3752,6 +3803,7 @@ pub fn lseek_END(fd: fd_t, offset: i64) SeekError!void {
37523803 wasi.EOVERFLOW => return error.Unseekable,
37533804 wasi.ESPIPE => return error.Unseekable,
37543805 wasi.ENXIO => return error.Unseekable,
3806 wasi.ENOTCAPABLE => return error.AccessDenied,
37553807 else => |err| return unexpectedErrno(err),
37563808 }
37573809 }
......@@ -3792,6 +3844,7 @@ pub fn lseek_CUR_get(fd: fd_t) SeekError!u64 {
37923844 wasi.EOVERFLOW => return error.Unseekable,
37933845 wasi.ESPIPE => return error.Unseekable,
37943846 wasi.ENXIO => return error.Unseekable,
3847 wasi.ENOTCAPABLE => return error.AccessDenied,
37953848 else => |err| return unexpectedErrno(err),
37963849 }
37973850 }
lib/std/zig/system.zig+1
......@@ -860,6 +860,7 @@ pub const NativeTargetInfo = struct {
860860 error.ConnectionTimedOut => return error.UnableToReadElfFile,
861861 error.Unexpected => return error.Unexpected,
862862 error.InputOutput => return error.FileSystem,
863 error.AccessDenied => return error.Unexpected,
863864 };
864865 if (len == 0) return error.UnexpectedEndOfFile;
865866 i += len;
src-self-hosted/codegen.zig+189-107
......@@ -37,6 +37,68 @@ pub fn generateSymbol(
3737 .Fn => {
3838 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
40102 var function = Function{
41103 .target = &bin_file.options.target,
42104 .bin_file = bin_file,
......@@ -44,16 +106,14 @@ pub fn generateSymbol(
44106 .code = code,
45107 .inst_table = std.AutoHashMap(*ir.Inst, Function.MCValue).init(bin_file.allocator),
46108 .err_msg = null,
109 .args = mc_args.items,
47110 };
48111 defer function.inst_table.deinit();
49112
50 for (module_fn.analysis.success.instructions) |inst| {
51 const new_inst = function.genFuncInst(inst) catch |err| switch (err) {
52 error.CodegenFail => return Result{ .fail = function.err_msg.? },
53 else => |e| return e,
54 };
55 try function.inst_table.putNoClobber(inst, new_inst);
56 }
113 function.gen() catch |err| switch (err) {
114 error.CodegenFail => return Result{ .fail = function.err_msg.? },
115 else => |e| return e,
116 };
57117
58118 if (function.err_msg) |em| {
59119 return Result{ .fail = em };
......@@ -157,6 +217,7 @@ const Function = struct {
157217 code: *std.ArrayList(u8),
158218 inst_table: std.AutoHashMap(*ir.Inst, MCValue),
159219 err_msg: ?*ErrorMsg,
220 args: []MCValue,
160221
161222 const MCValue = union(enum) {
162223 none,
......@@ -170,44 +231,119 @@ const Function = struct {
170231 register: usize,
171232 /// The value is in memory at a hard-coded address.
172233 memory: u64,
234 /// The value is one of the stack variables.
235 stack_offset: u64,
173236 };
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 {
176302 switch (inst.tag) {
177 .add => return self.genAdd(inst.cast(ir.Inst.Add).?),
178 .arg => return self.genArg(inst.src),
179 .block => return self.genBlock(inst.cast(ir.Inst.Block).?),
180 .breakpoint => return self.genBreakpoint(inst.src),
181 .call => return self.genCall(inst.cast(ir.Inst.Call).?),
303 .add => return self.genAdd(inst.cast(ir.Inst.Add).?, arch),
304 .arg => return self.genArg(inst.cast(ir.Inst.Arg).?),
305 .block => return self.genBlock(inst.cast(ir.Inst.Block).?, arch),
306 .breakpoint => return self.genBreakpoint(inst.src, arch),
307 .call => return self.genCall(inst.cast(ir.Inst.Call).?, arch),
182308 .unreach => return MCValue{ .unreach = {} },
183309 .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),
185311 .ptrtoint => return self.genPtrToInt(inst.cast(ir.Inst.PtrToInt).?),
186312 .bitcast => return self.genBitCast(inst.cast(ir.Inst.BitCast).?),
187 .ret => return self.genRet(inst.cast(ir.Inst.Ret).?),
188 .retvoid => return self.genRetVoid(inst.cast(ir.Inst.RetVoid).?),
189 .cmp => return self.genCmp(inst.cast(ir.Inst.Cmp).?),
190 .condbr => return self.genCondBr(inst.cast(ir.Inst.CondBr).?),
191 .isnull => return self.genIsNull(inst.cast(ir.Inst.IsNull).?),
192 .isnonnull => return self.genIsNonNull(inst.cast(ir.Inst.IsNonNull).?),
313 .ret => return self.genRet(inst.cast(ir.Inst.Ret).?, arch),
314 .retvoid => return self.genRetVoid(inst.cast(ir.Inst.RetVoid).?, arch),
315 .cmp => return self.genCmp(inst.cast(ir.Inst.Cmp).?, arch),
316 .condbr => return self.genCondBr(inst.cast(ir.Inst.CondBr).?, arch),
317 .isnull => return self.genIsNull(inst.cast(ir.Inst.IsNull).?, arch),
318 .isnonnull => return self.genIsNonNull(inst.cast(ir.Inst.IsNonNull).?, arch),
193319 }
194320 }
195321
196 fn genAdd(self: *Function, inst: *ir.Inst.Add) !MCValue {
197 switch (self.target.cpu.arch) {
322 fn genAdd(self: *Function, inst: *ir.Inst.Add, comptime arch: std.Target.Cpu.Arch) !MCValue {
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 },
198337 else => return self.fail(inst.base.src, "TODO implement add for {}", .{self.target.cpu.arch}),
199338 }
200339 }
201340
202 fn genArg(self: *Function, src: usize) !MCValue {
203 switch (self.target.cpu.arch) {
204 else => return self.fail(src, "TODO implement function parameters for {}", .{self.target.cpu.arch}),
205 }
206 return .none;
341 fn genArg(self: *Function, inst: *ir.Inst.Arg) !MCValue {
342 return self.args[inst.args.index];
207343 }
208344
209 fn genBreakpoint(self: *Function, src: usize) !MCValue {
210 switch (self.target.cpu.arch) {
345 fn genBreakpoint(self: *Function, src: usize, comptime arch: std.Target.Cpu.Arch) !MCValue {
346 switch (arch) {
211347 .i386, .x86_64 => {
212348 try self.code.append(0xcc); // int3
213349 },
......@@ -216,8 +352,8 @@ const Function = struct {
216352 return .none;
217353 }
218354
219 fn genCall(self: *Function, inst: *ir.Inst.Call) !MCValue {
220 switch (self.target.cpu.arch) {
355 fn genCall(self: *Function, inst: *ir.Inst.Call, comptime arch: std.Target.Cpu.Arch) !MCValue {
356 switch (arch) {
221357 .x86_64, .i386 => {
222358 if (inst.args.func.cast(ir.Inst.Constant)) |func_inst| {
223359 if (inst.args.args.len != 0) {
......@@ -251,11 +387,11 @@ const Function = struct {
251387 }
252388 }
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 {
255391 if (mcv != .none) {
256392 return self.fail(src, "TODO implement return with non-void operand", .{});
257393 }
258 switch (self.target.cpu.arch) {
394 switch (arch) {
259395 .i386, .x86_64 => {
260396 try self.code.append(0xc3); // ret
261397 },
......@@ -264,43 +400,43 @@ const Function = struct {
264400 return .unreach;
265401 }
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 {
268404 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);
270406 }
271407
272 fn genRetVoid(self: *Function, inst: *ir.Inst.RetVoid) !MCValue {
273 return self.ret(inst.base.src, .none);
408 fn genRetVoid(self: *Function, inst: *ir.Inst.RetVoid, comptime arch: std.Target.Cpu.Arch) !MCValue {
409 return self.ret(inst.base.src, arch, .none);
274410 }
275411
276 fn genCmp(self: *Function, inst: *ir.Inst.Cmp) !MCValue {
277 switch (self.target.cpu.arch) {
412 fn genCmp(self: *Function, inst: *ir.Inst.Cmp, comptime arch: std.Target.Cpu.Arch) !MCValue {
413 switch (arch) {
278414 else => return self.fail(inst.base.src, "TODO implement cmp for {}", .{self.target.cpu.arch}),
279415 }
280416 }
281417
282 fn genCondBr(self: *Function, inst: *ir.Inst.CondBr) !MCValue {
283 switch (self.target.cpu.arch) {
418 fn genCondBr(self: *Function, inst: *ir.Inst.CondBr, comptime arch: std.Target.Cpu.Arch) !MCValue {
419 switch (arch) {
284420 else => return self.fail(inst.base.src, "TODO implement condbr for {}", .{self.target.cpu.arch}),
285421 }
286422 }
287423
288 fn genIsNull(self: *Function, inst: *ir.Inst.IsNull) !MCValue {
289 switch (self.target.cpu.arch) {
424 fn genIsNull(self: *Function, inst: *ir.Inst.IsNull, comptime arch: std.Target.Cpu.Arch) !MCValue {
425 switch (arch) {
290426 else => return self.fail(inst.base.src, "TODO implement isnull for {}", .{self.target.cpu.arch}),
291427 }
292428 }
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 {
295431 // Here you can specialize this instruction if it makes sense to, otherwise the default
296432 // will call genIsNull and invert the result.
297 switch (self.target.cpu.arch) {
433 switch (arch) {
298434 else => return self.fail(inst.base.src, "TODO call genIsNull and invert the result ", .{}),
299435 }
300436 }
301437
302 fn genRelativeFwdJump(self: *Function, src: usize, amount: u32) !void {
303 switch (self.target.cpu.arch) {
438 fn genRelativeFwdJump(self: *Function, src: usize, comptime arch: std.Target.Cpu.Arch, amount: u32) !void {
439 switch (arch) {
304440 .i386, .x86_64 => {
305441 // TODO x86 treats the operands as signed
306442 if (amount <= std.math.maxInt(u8)) {
......@@ -318,70 +454,13 @@ const Function = struct {
318454 }
319455 }
320456
321 fn genBlock(self: *Function, inst: *ir.Inst.Block) !MCValue {
322 switch (self.target.cpu.arch) {
457 fn genBlock(self: *Function, inst: *ir.Inst.Block, comptime arch: std.Target.Cpu.Arch) !MCValue {
458 switch (arch) {
323459 else => return self.fail(inst.base.src, "TODO implement codegen Block for {}", .{self.target.cpu.arch}),
324460 }
325461 }
326462
327 fn genAsm(self: *Function, inst: *ir.Inst.Assembly) !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 {
463 fn genAsm(self: *Function, inst: *ir.Inst.Assembly, comptime arch: Target.Cpu.Arch) !MCValue {
385464 if (arch != .x86_64 and arch != .i386) {
386465 return self.fail(inst.base.src, "TODO implement inline asm support for more architectures", .{});
387466 }
......@@ -607,6 +686,9 @@ const Function = struct {
607686 }
608687 }
609688 },
689 .stack_offset => |off| {
690 return self.fail(src, "TODO implement genSetReg for stack variables", .{});
691 },
610692 },
611693 else => return self.fail(src, "TODO implement genSetReg for more architectures", .{}),
612694 }
src-self-hosted/codegen/x86_64.zig+6-5
......@@ -1,20 +1,21 @@
1const Type = @import("../Type.zig");
2
13// 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.
46/// The registers are defined such that IDs go in descending order of 64-bit,
57/// 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:
79///
810/// Any 64-bit register can be turned into its 32-bit form by adding 16, and
911/// 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-bit
12/// works for all except for sp, bp, si, and di, which do *not* have an 8-bit
1113/// form.
1214///
1315/// If (register & 8) is set, the register is extended.
1416///
1517/// The ID can be easily determined by figuring out what range the register is
1618/// in, and then subtracting the base.
17///
1819pub const Register = enum(u8) {
1920 // 0 through 15, 64-bit registers. 8-15 are extended.
2021 // id is just the int value.
......@@ -66,4 +67,4 @@ pub const Register = enum(u8) {
6667 }
6768};
6869
69// zig fmt: on
70// zig fmt: on
\ No newline at end of file
src-self-hosted/type.zig+70
......@@ -535,6 +535,76 @@ pub const Type = extern union {
535535 };
536536 }
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
538608 pub fn isSinglePointer(self: Type) bool {
539609 return switch (self.tag()) {
540610 .u8,