Commit 4261fa3c49

Andrew Kelley <andrew@ziglang.org>
2019-11-26 00:46:17
move logic to the appropriate layers; add new compile error
1 parent 659c1bd
lib/std/os/wasi.zig
@@ -78,52 +78,6 @@ pub extern "wasi_unstable" fn sock_send(sock: fd_t, si_data: *const ciovec_t, si
 pub extern "wasi_unstable" fn sock_shutdown(sock: fd_t, how: sdflags_t) errno_t;
 
 /// Get the errno from a syscall return value, or 0 for no error.
-pub fn getErrno(r: usize) usize {
-    const signed_r = @bitCast(isize, r);
-    return if (signed_r > -4096 and signed_r < 0) @intCast(usize, -signed_r) else 0;
-}
-
-pub fn clock_getres(clock_id: i32, res: *timespec) errno_t {
-    var ts: timestamp_t = undefined;
-    const err = clock_res_get(@bitCast(u32, clock_id), &ts);
-    if (err != 0) {
-        return err;
-    }
-    res.* = .{
-        .tv_sec = @intCast(i64, ts / std.time.ns_per_s),
-        .tv_nsec = @intCast(isize, ts % std.time.ns_per_s),
-    };
-    return 0;
-}
-
-pub fn clock_gettime(clock_id: i32, tp: *timespec) errno_t {
-    var ts: timestamp_t = undefined;
-    const err = clock_time_get(@bitCast(u32, clock_id), 1, &ts);
-    if (err != 0) {
-        return err;
-    }
-    tp.* = .{
-        .tv_sec = @intCast(i64, ts / std.time.ns_per_s),
-        .tv_nsec = @intCast(isize, ts % std.time.ns_per_s),
-    };
-    return 0;
-}
-
-pub fn isatty(fd: fd_t) bool {
-    var statbuf: fdstat_t = undefined;
-    const err = fd_fdstat_get(fd, &statbuf);
-    if (err != 0) {
-        // errno = err;
-        return false;
-    }
-
-    // A tty is a character device that we can't seek or tell on.
-    if (statbuf.fs_filetype != FILETYPE_CHARACTER_DEVICE or
-        (statbuf.fs_rights_base & (RIGHT_FD_SEEK | RIGHT_FD_TELL)) != 0)
-    {
-        // errno = ENOTTY;
-        return false;
-    }
-
-    return true;
+pub fn getErrno(r: errno_t) usize {
+    return r;
 }
lib/std/heap.zig
@@ -273,17 +273,17 @@ const WasmPageAllocator = struct {
         if (new_end_index > num_pages * mem.page_size) {
             const required_memory = new_end_index - (num_pages * mem.page_size);
 
-            var num_pages: usize = required_memory / mem.page_size;
+            var inner_num_pages: usize = required_memory / mem.page_size;
             if (required_memory % mem.page_size != 0) {
-                num_pages += 1;
+                inner_num_pages += 1;
             }
 
-            const prev_page = @"llvm.wasm.memory.grow.i32"(0, @intCast(u32, num_pages));
+            const prev_page = @"llvm.wasm.memory.grow.i32"(0, @intCast(u32, inner_num_pages));
             if (prev_page == -1) {
                 return error.OutOfMemory;
             }
 
-            num_pages += num_pages;
+            num_pages += inner_num_pages;
         }
 
         const result = start_ptr[adjusted_index..new_end_index];
lib/std/os.zig
@@ -1527,7 +1527,22 @@ pub fn isatty(handle: fd_t) bool {
         return system.isatty(handle) != 0;
     }
     if (builtin.os == .wasi) {
-        return system.isatty(handle);
+        var statbuf: fdstat_t = undefined;
+        const err = system.fd_fdstat_get(handle, &statbuf);
+        if (err != 0) {
+            // errno = err;
+            return false;
+        }
+
+        // A tty is a character device that we can't seek or tell on.
+        if (statbuf.fs_filetype != FILETYPE_CHARACTER_DEVICE or
+            (statbuf.fs_rights_base & (RIGHT_FD_SEEK | RIGHT_FD_TELL)) != 0)
+        {
+            // errno = ENOTTY;
+            return false;
+        }
+
+        return true;
     }
     if (builtin.os == .linux) {
         var wsz: linux.winsize = undefined;
@@ -2720,6 +2735,20 @@ pub fn dl_iterate_phdr(
 pub const ClockGetTimeError = error{UnsupportedClock} || UnexpectedError;
 
 pub fn clock_gettime(clk_id: i32, tp: *timespec) ClockGetTimeError!void {
+    if (comptime std.Target.current.getOs() == .wasi) {
+        var ts: timestamp_t = undefined;
+        switch (system.clock_time_get(@bitCast(u32, clk_id), 1, &ts)) {
+            0 => {
+                tp.* = .{
+                    .tv_sec = @intCast(i64, ts / std.time.ns_per_s),
+                    .tv_nsec = @intCast(isize, ts % std.time.ns_per_s),
+                };
+            },
+            EINVAL => return error.UnsupportedClock,
+            else => |err| return unexpectedErrno(err),
+        }
+        return;
+    }
     switch (errno(system.clock_gettime(clk_id, tp))) {
         0 => return,
         EFAULT => unreachable,
@@ -2729,6 +2758,19 @@ pub fn clock_gettime(clk_id: i32, tp: *timespec) ClockGetTimeError!void {
 }
 
 pub fn clock_getres(clk_id: i32, res: *timespec) ClockGetTimeError!void {
+    if (comptime std.Target.current.getOs() == .wasi) {
+        var ts: timestamp_t = undefined;
+        switch (system.clock_res_get(@bitCast(u32, clk_id), &ts)) {
+            0 => res.* = .{
+                .tv_sec = @intCast(i64, ts / std.time.ns_per_s),
+                .tv_nsec = @intCast(isize, ts % std.time.ns_per_s),
+            },
+            EINVAL => return error.UnsupportedClock,
+            else => |err| return unexpectedErrno(err),
+        }
+        return;
+    }
+
     switch (errno(system.clock_getres(clk_id, res))) {
         0 => return,
         EFAULT => unreachable,
lib/std/target.zig
@@ -607,6 +607,10 @@ pub const Target = union(enum) {
         }
     }
 
+    pub fn supportsNewStackCall(self: Target) bool {
+        return !self.isWasm();
+    }
+
     pub const Executor = union(enum) {
         native,
         qemu: []const u8,
@@ -650,7 +654,7 @@ pub const Target = union(enum) {
             }
         }
 
-        if (self.isWasm()) {
+        if (self.getOs() == .wasi) {
             switch (self.getArchPtrBitWidth()) {
                 32 => return Executor{ .wasmtime = "wasmtime" },
                 else => return .unavailable,
src/analyze.cpp
@@ -978,7 +978,8 @@ bool want_first_arg_sret(CodeGen *g, FnTypeId *fn_type_id) {
     if (g->zig_target->arch == ZigLLVM_x86 ||
         g->zig_target->arch == ZigLLVM_x86_64 ||
         target_is_arm(g->zig_target) ||
-        target_is_riscv(g->zig_target))
+        target_is_riscv(g->zig_target) ||
+        target_is_wasm(g->zig_target))
     {
         X64CABIClass abi_class = type_c_abi_x86_64_class(g, fn_type_id->return_type);
         return abi_class == X64CABIClass_MEMORY || abi_class == X64CABIClass_MEMORY_nobyval;
src/ir.cpp
@@ -17095,6 +17095,14 @@ static IrInstruction *analyze_casted_new_stack(IrAnalyze *ira, IrInstructionCall
     if (call_instruction->new_stack == nullptr)
         return nullptr;
 
+    if (!call_instruction->is_async_call_builtin &&
+        arch_stack_pointer_register_name(ira->codegen->zig_target->arch) == nullptr)
+    {
+        ir_add_error(ira, &call_instruction->base,
+            buf_sprintf("target arch '%s' does not support @newStackCall",
+                target_arch_name(ira->codegen->zig_target->arch)));
+    }
+
     IrInstruction *new_stack = call_instruction->new_stack->child;
     if (type_is_invalid(new_stack->value->type))
         return ira->codegen->invalid_instruction;
src/target.cpp
@@ -1458,6 +1458,10 @@ const char *arch_stack_pointer_register_name(ZigLLVM_ArchType arch) {
         case ZigLLVM_mipsel:
             return "sp";
 
+        case ZigLLVM_wasm32:
+        case ZigLLVM_wasm64:
+            return nullptr; // known to be not available
+
         case ZigLLVM_amdgcn:
         case ZigLLVM_amdil:
         case ZigLLVM_amdil64:
@@ -1491,8 +1495,6 @@ const char *arch_stack_pointer_register_name(ZigLLVM_ArchType arch) {
         case ZigLLVM_systemz:
         case ZigLLVM_tce:
         case ZigLLVM_tcele:
-        case ZigLLVM_wasm32:
-        case ZigLLVM_wasm64:
         case ZigLLVM_xcore:
         case ZigLLVM_ppc:
         case ZigLLVM_ppc64:
test/stage1/behavior/asm.zig
@@ -1,5 +1,6 @@
+const std = @import("std");
 const config = @import("builtin");
-const expect = @import("std").testing.expect;
+const expect = std.testing.expect;
 
 comptime {
     if (config.arch == config.Arch.x86_64 and config.os == config.Os.linux) {
test/stage1/behavior/new_stack_call.zig
@@ -12,6 +12,9 @@ test "calling a function with a new stack" {
         // TODO: https://github.com/ziglang/zig/issues/3338
         return error.SkipZigTest;
     }
+    if (comptime !std.Target.current.supportsNewStackCall()) {
+        return error.SkipZigTest;
+    }
 
     const arg = 1234;
 
test/compile_errors.zig
@@ -2,6 +2,24 @@ const tests = @import("tests.zig");
 const builtin = @import("builtin");
 
 pub fn addCases(cases: *tests.CompileErrorContext) void {
+    cases.addCase(x: {
+        var tc = cases.create("@newStackCall on unsupported target",
+            \\export fn entry() void {
+            \\    var buf: [10]u8 align(16) = undefined;
+            \\    @newStackCall(&buf, foo);
+            \\}
+            \\fn foo() void {}
+        , "tmp.zig:3:5: error: target arch 'wasm32' does not support @newStackCall");
+        tc.target = tests.Target{
+            .Cross = tests.CrossTarget{
+                .arch = .wasm32,
+                .os = .wasi,
+                .abi = .none,
+            },
+        };
+        break :x tc;
+    });
+
     cases.add(
         "incompatible sentinels",
         \\export fn entry1(ptr: [*:255]u8) [*:0]u8 {
@@ -26,7 +44,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
         "tmp.zig:8:35: note: destination array requires a terminating '0' sentinel, but source array has a terminating '255' sentinel",
         "tmp.zig:11:31: error: expected type '[2:0]u8', found '[2]u8'",
         "tmp.zig:11:31: note: destination array requires a terminating '0' sentinel",
-
     );
 
     cases.add(