From 4261fa3c49be715355c9623102bad0bf93d537a3 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 25 Nov 2019 18:46:17 -0500 Subject: [PATCH] move logic to the appropriate layers; add new compile error --- lib/std/heap.zig | 8 ++-- lib/std/os.zig | 44 +++++++++++++++++++++- lib/std/os/wasi.zig | 50 +------------------------ lib/std/target.zig | 6 ++- src/analyze.cpp | 3 +- src/ir.cpp | 8 ++++ src/target.cpp | 6 ++- test/compile_errors.zig | 19 +++++++++- test/stage1/behavior/asm.zig | 3 +- test/stage1/behavior/new_stack_call.zig | 3 ++ 10 files changed, 91 insertions(+), 59 deletions(-) diff --git a/lib/std/heap.zig b/lib/std/heap.zig index 259c29f6e..997f1fa06 100644 --- a/lib/std/heap.zig +++ b/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]; diff --git a/lib/std/os.zig b/lib/std/os.zig index a616fbc49..22d52b24a 100644 --- a/lib/std/os.zig +++ b/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, diff --git a/lib/std/os/wasi.zig b/lib/std/os/wasi.zig index 1ffc9610f..c417097c7 100644 --- a/lib/std/os/wasi.zig +++ b/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; } diff --git a/lib/std/target.zig b/lib/std/target.zig index 9652d5b6e..4d19fa627 100644 --- a/lib/std/target.zig +++ b/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, diff --git a/src/analyze.cpp b/src/analyze.cpp index e47b67a49..e1b086059 100644 --- a/src/analyze.cpp +++ b/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; diff --git a/src/ir.cpp b/src/ir.cpp index f4bcfb633..7e867f1c9 100644 --- a/src/ir.cpp +++ b/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; diff --git a/src/target.cpp b/src/target.cpp index 8fd7d7055..538f836f2 100644 --- a/src/target.cpp +++ b/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: diff --git a/test/compile_errors.zig b/test/compile_errors.zig index dd0f80b25..c1e2d579a 100644 --- a/test/compile_errors.zig +++ b/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( diff --git a/test/stage1/behavior/asm.zig b/test/stage1/behavior/asm.zig index 9278d45d5..d1404c6f4 100644 --- a/test/stage1/behavior/asm.zig +++ b/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) { diff --git a/test/stage1/behavior/new_stack_call.zig b/test/stage1/behavior/new_stack_call.zig index a2f3773af..b057566d9 100644 --- a/test/stage1/behavior/new_stack_call.zig +++ b/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;