From f97c2f28fdc3061bc7e30ccfcafaccbee77993b6 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 24 May 2024 08:22:47 -0700 Subject: update the codebase for the new std.Progress API --- src/Module.zig | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'src/Module.zig') diff --git a/src/Module.zig b/src/Module.zig index c571c851fe..55b08701dc 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -2991,8 +2991,7 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void { try mod.deleteDeclExports(decl_index); } - var decl_prog_node = mod.sema_prog_node.start("", 0); - decl_prog_node.activate(); + const decl_prog_node = mod.sema_prog_node.start("", 0); defer decl_prog_node.end(); const sema_result: SemaDeclResult = blk: { @@ -5316,7 +5315,7 @@ fn handleUpdateExports( pub fn populateTestFunctions( mod: *Module, - main_progress_node: *std.Progress.Node, + main_progress_node: std.Progress.Node, ) !void { const gpa = mod.gpa; const ip = &mod.intern_pool; @@ -5333,7 +5332,6 @@ pub fn populateTestFunctions( // We have to call `ensureDeclAnalyzed` here in case `builtin.test_functions` // was not referenced by start code. mod.sema_prog_node = main_progress_node.start("Semantic Analysis", 0); - mod.sema_prog_node.activate(); defer { mod.sema_prog_node.end(); mod.sema_prog_node = undefined; -- cgit v1.2.3 From 352dc2c06a470d88c33dfbfdf3fdbb093097775c Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 24 May 2024 10:51:14 -0700 Subject: compiler: show decl name in progress node --- src/Module.zig | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'src/Module.zig') diff --git a/src/Module.zig b/src/Module.zig index 55b08701dc..a311118970 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -2942,11 +2942,12 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void { const tracy = trace(@src()); defer tracy.end(); + const ip = &mod.intern_pool; const decl = mod.declPtr(decl_index); log.debug("ensureDeclAnalyzed '{d}' (name '{}')", .{ @intFromEnum(decl_index), - decl.name.fmt(&mod.intern_pool), + decl.name.fmt(ip), }); // Determine whether or not this Decl is outdated, i.e. requires re-analysis @@ -2991,9 +2992,6 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void { try mod.deleteDeclExports(decl_index); } - const decl_prog_node = mod.sema_prog_node.start("", 0); - defer decl_prog_node.end(); - const sema_result: SemaDeclResult = blk: { if (decl.zir_decl_index == .none and !mod.declIsRoot(decl_index)) { // Anonymous decl. We don't semantically analyze these. @@ -3011,6 +3009,9 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void { }; } + const decl_prog_node = mod.sema_prog_node.start(decl.name.toSlice(ip), 0); + defer decl_prog_node.end(); + break :blk mod.semaDecl(decl_index) catch |err| switch (err) { error.AnalysisFail => { if (decl.analysis == .in_progress) { -- cgit v1.2.3 From d403d8cb7a147856232430afe9af8562d59de38b Mon Sep 17 00:00:00 2001 From: mlugg Date: Sun, 26 May 2024 01:58:26 +0100 Subject: Module: fix and improve progress reporting * correctly report time spent analyzing function bodies * print fully qualified decl names * also have a progress node for codegen The downside of these changes is that it's a bit flickerey, but the upside is that it's accurate; you can see what the compiler's doing! --- src/Compilation.zig | 3 +++ src/Module.zig | 20 ++++++++++++++++---- 2 files changed, 19 insertions(+), 4 deletions(-) (limited to 'src/Module.zig') diff --git a/src/Compilation.zig b/src/Compilation.zig index 1ec7664e8e..f7ea2434b3 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -3331,10 +3331,13 @@ pub fn performAllTheWork( try reportMultiModuleErrors(mod); try mod.flushRetryableFailures(); mod.sema_prog_node = main_progress_node.start("Semantic Analysis", 0); + mod.codegen_prog_node = main_progress_node.start("Code Generation", 0); } defer if (comp.module) |mod| { mod.sema_prog_node.end(); mod.sema_prog_node = undefined; + mod.codegen_prog_node.end(); + mod.codegen_prog_node = undefined; }; while (true) { diff --git a/src/Module.zig b/src/Module.zig index a311118970..d38a233a77 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -66,6 +66,7 @@ root_mod: *Package.Module, main_mod: *Package.Module, std_mod: *Package.Module, sema_prog_node: std.Progress.Node = undefined, +codegen_prog_node: std.Progress.Node = undefined, /// Used by AstGen worker to load and store ZIR cache. global_zir_cache: Compilation.Directory, @@ -3009,7 +3010,7 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void { }; } - const decl_prog_node = mod.sema_prog_node.start(decl.name.toSlice(ip), 0); + const decl_prog_node = mod.sema_prog_node.start((try decl.fullyQualifiedName(mod)).toSlice(ip), 0); defer decl_prog_node.end(); break :blk mod.semaDecl(decl_index) catch |err| switch (err) { @@ -3215,6 +3216,9 @@ pub fn ensureFuncBodyAnalyzed(zcu: *Zcu, maybe_coerced_func_index: InternPool.In }; } + const codegen_prog_node = zcu.codegen_prog_node.start((try decl.fullyQualifiedName(zcu)).toSlice(ip), 0); + defer codegen_prog_node.end(); + if (comp.bin_file) |lf| { lf.updateFunc(zcu, func_index, air, liveness) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, @@ -4500,6 +4504,9 @@ pub fn analyzeFnBody(mod: *Module, func_index: InternPool.Index, arena: Allocato log.debug("finish func name '{}'", .{(decl.fullyQualifiedName(mod) catch break :blk).fmt(ip)}); } + const decl_prog_node = mod.sema_prog_ndoe.start((try decl.fullyQualifiedName(mod)).toSlice(ip), 0); + defer decl_prog_node.end(); + mod.intern_pool.removeDependenciesForDepender(gpa, InternPool.Depender.wrap(.{ .func = func_index })); var comptime_err_ret_trace = std.ArrayList(SrcLoc).init(gpa); @@ -5333,9 +5340,12 @@ pub fn populateTestFunctions( // We have to call `ensureDeclAnalyzed` here in case `builtin.test_functions` // was not referenced by start code. mod.sema_prog_node = main_progress_node.start("Semantic Analysis", 0); + mod.codegen_prog_node = main_progress_node.start("Code Generation", 0); defer { mod.sema_prog_node.end(); mod.sema_prog_node = undefined; + mod.codegen_prog_node.end(); + mod.codegen_prog_node = undefined; } try mod.ensureDeclAnalyzed(decl_index); } @@ -5445,15 +5455,18 @@ pub fn populateTestFunctions( pub fn linkerUpdateDecl(zcu: *Zcu, decl_index: Decl.Index) !void { const comp = zcu.comp; + const decl = zcu.declPtr(decl_index); + + const codegen_prog_node = zcu.codegen_prog_node.start((try decl.fullyQualifiedName(zcu)).toSlice(&zcu.intern_pool), 0); + defer codegen_prog_node.end(); + if (comp.bin_file) |lf| { lf.updateDecl(zcu, decl_index) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, error.AnalysisFail => { - const decl = zcu.declPtr(decl_index); decl.analysis = .codegen_failure; }, else => { - const decl = zcu.declPtr(decl_index); const gpa = zcu.gpa; try zcu.failed_decls.ensureUnusedCapacity(gpa, 1); zcu.failed_decls.putAssumeCapacityNoClobber(decl_index, try ErrorMsg.create( @@ -5471,7 +5484,6 @@ pub fn linkerUpdateDecl(zcu: *Zcu, decl_index: Decl.Index) !void { llvm_object.updateDecl(zcu, decl_index) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, error.AnalysisFail => { - const decl = zcu.declPtr(decl_index); decl.analysis = .codegen_failure; }, }; -- cgit v1.2.3 From d77f5e7aaa94b66db4e3604f21c41b315743fb81 Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Sun, 26 May 2024 07:07:44 -0400 Subject: Progress: fix compile errors on windows Works for `zig build-exe`, IPC still not implemented yet. --- lib/std/Progress.zig | 79 ++++++++++++++++++++++++++++++++++++++-------------- lib/std/fmt.zig | 59 +++++++++++++++++++++++---------------- lib/std/io/tty.zig | 2 +- lib/std/process.zig | 5 +--- src/Module.zig | 2 +- 5 files changed, 96 insertions(+), 51 deletions(-) (limited to 'src/Module.zig') diff --git a/lib/std/Progress.zig b/lib/std/Progress.zig index 216460e6b7..af68899486 100644 --- a/lib/std/Progress.zig +++ b/lib/std/Progress.zig @@ -86,12 +86,20 @@ pub const Node = struct { name: [max_name_len]u8, fn getIpcFd(s: Storage) ?posix.fd_t { - return if (s.estimated_total_count != std.math.maxInt(u32)) null else @bitCast(s.completed_count); + return if (s.estimated_total_count == std.math.maxInt(u32)) switch (@typeInfo(posix.fd_t)) { + .Int => @bitCast(s.completed_count), + .Pointer => @ptrFromInt(s.completed_count), + else => @compileError("unsupported fd_t of " ++ @typeName(posix.fd_t)), + } else null; } fn setIpcFd(s: *Storage, fd: posix.fd_t) void { s.estimated_total_count = std.math.maxInt(u32); - s.completed_count = @bitCast(fd); + s.completed_count = switch (@typeInfo(posix.fd_t)) { + .Int => @bitCast(fd), + .Pointer => @intFromPtr(fd), + else => @compileError("unsupported fd_t of " ++ @typeName(posix.fd_t)), + }; } comptime { @@ -316,12 +324,16 @@ pub fn start(options: Options) Node { global_progress.initial_delay_ns = options.initial_delay_ns; if (std.process.parseEnvVarInt("ZIG_PROGRESS", u31, 10)) |ipc_fd| { - if (std.Thread.spawn(.{}, ipcThreadRun, .{ipc_fd})) |thread| { - global_progress.update_thread = thread; - } else |err| { + global_progress.update_thread = std.Thread.spawn(.{}, ipcThreadRun, .{ + @as(posix.fd_t, switch (@typeInfo(posix.fd_t)) { + .Int => ipc_fd, + .Pointer => @ptrFromInt(ipc_fd), + else => @compileError("unsupported fd_t of " ++ @typeName(posix.fd_t)), + }), + }) catch |err| { std.log.warn("failed to spawn IPC thread for communicating progress to parent: {s}", .{@errorName(err)}); return .{ .index = .none }; - } + }; } else |env_err| switch (env_err) { error.EnvironmentVariableNotFound => { if (options.disable_printing) { @@ -572,6 +584,20 @@ const SavedMetadata = struct { main_index: u16, start_index: u16, nodes_len: u16, + + fn getIpcFd(metadata: SavedMetadata) posix.fd_t { + return if (builtin.os.tag == .windows) + @ptrFromInt(@as(usize, metadata.ipc_fd) << 2) + else + metadata.ipc_fd; + } + + fn setIpcFd(fd: posix.fd_t) u16 { + return @intCast(if (builtin.os.tag == .windows) + @shrExact(@intFromPtr(fd), 2) + else + fd); + } }; fn serializeIpc(start_serialized_len: usize) usize { @@ -638,7 +664,7 @@ fn serializeIpc(start_serialized_len: usize) usize { // Remember in case the pipe is empty on next update. ipc_metadata[ipc_metadata_len] = .{ - .ipc_fd = @intCast(fd), + .ipc_fd = SavedMetadata.setIpcFd(fd), .start_index = @intCast(serialized_len), .nodes_len = @intCast(parents.len), .main_index = @intCast(main_index), @@ -687,7 +713,7 @@ fn copyRoot(dest: *Node.Storage, src: *align(2) Node.Storage) void { fn findOld(ipc_fd: posix.fd_t, old_metadata: []const SavedMetadata) ?*const SavedMetadata { for (old_metadata) |*m| { - if (m.ipc_fd == ipc_fd) + if (m.getIpcFd() == ipc_fd) return m; } return null; @@ -711,7 +737,7 @@ fn useSavedIpcData( const old_main_index = saved_metadata.main_index; ipc_metadata[ipc_metadata_len] = .{ - .ipc_fd = @intCast(ipc_fd), + .ipc_fd = SavedMetadata.setIpcFd(ipc_fd), .start_index = @intCast(start_serialized_len), .nodes_len = nodes_len, .main_index = @intCast(main_index), @@ -911,21 +937,32 @@ fn writeIpc(fd: posix.fd_t, serialized: Serialized) error{BrokenPipe}!void { fn maybeUpdateSize(resize_flag: bool) void { if (!resize_flag) return; - var winsize: posix.winsize = .{ - .ws_row = 0, - .ws_col = 0, - .ws_xpixel = 0, - .ws_ypixel = 0, - }; - const fd = (global_progress.terminal orelse return).handle; - const err = posix.system.ioctl(fd, posix.T.IOCGWINSZ, @intFromPtr(&winsize)); - if (posix.errno(err) == .SUCCESS) { - global_progress.rows = winsize.ws_row; - global_progress.cols = winsize.ws_col; + if (builtin.os.tag == .windows) { + var info: windows.CONSOLE_SCREEN_BUFFER_INFO = undefined; + + if (windows.kernel32.GetConsoleScreenBufferInfo(fd, &info) == windows.FALSE) { + @panic("TODO: handle this failure"); + } + + global_progress.rows = @intCast(info.dwSize.Y); + global_progress.cols = @intCast(info.dwSize.X); } else { - @panic("TODO: handle this failure"); + var winsize: posix.winsize = .{ + .ws_row = 0, + .ws_col = 0, + .ws_xpixel = 0, + .ws_ypixel = 0, + }; + + const err = posix.system.ioctl(fd, posix.T.IOCGWINSZ, @intFromPtr(&winsize)); + if (posix.errno(err) == .SUCCESS) { + global_progress.rows = winsize.ws_row; + global_progress.cols = winsize.ws_col; + } else { + @panic("TODO: handle this failure"); + } } } diff --git a/lib/std/fmt.zig b/lib/std/fmt.zig index 2d1f4402d6..1a7475e1c5 100644 --- a/lib/std/fmt.zig +++ b/lib/std/fmt.zig @@ -9,7 +9,7 @@ const assert = std.debug.assert; const mem = std.mem; const unicode = std.unicode; const meta = std.meta; -const lossyCast = std.math.lossyCast; +const lossyCast = math.lossyCast; const expectFmt = std.testing.expectFmt; pub const default_max_depth = 3; @@ -1494,10 +1494,20 @@ pub fn Formatter(comptime format_fn: anytype) type { /// Ignores '_' character in `buf`. /// See also `parseUnsigned`. pub fn parseInt(comptime T: type, buf: []const u8, base: u8) ParseIntError!T { + return parseIntWithGenericCharacter(T, u8, buf, base); +} + +/// Like `parseInt`, but with a generic `Character` type. +pub fn parseIntWithGenericCharacter( + comptime Result: type, + comptime Character: type, + buf: []const Character, + base: u8, +) ParseIntError!Result { if (buf.len == 0) return error.InvalidCharacter; - if (buf[0] == '+') return parseWithSign(T, buf[1..], base, .pos); - if (buf[0] == '-') return parseWithSign(T, buf[1..], base, .neg); - return parseWithSign(T, buf, base, .pos); + if (buf[0] == '+') return parseIntWithSign(Result, Character, buf[1..], base, .pos); + if (buf[0] == '-') return parseIntWithSign(Result, Character, buf[1..], base, .neg); + return parseIntWithSign(Result, Character, buf, base, .pos); } test parseInt { @@ -1560,12 +1570,13 @@ test parseInt { try std.testing.expectEqual(@as(i5, -16), try std.fmt.parseInt(i5, "-10", 16)); } -fn parseWithSign( - comptime T: type, - buf: []const u8, +fn parseIntWithSign( + comptime Result: type, + comptime Character: type, + buf: []const Character, base: u8, comptime sign: enum { pos, neg }, -) ParseIntError!T { +) ParseIntError!Result { if (buf.len == 0) return error.InvalidCharacter; var buf_base = base; @@ -1575,7 +1586,7 @@ fn parseWithSign( buf_base = 10; // Detect the base by looking at buf prefix. if (buf.len > 2 and buf[0] == '0') { - switch (std.ascii.toLower(buf[1])) { + if (math.cast(u8, buf[1])) |c| switch (std.ascii.toLower(c)) { 'b' => { buf_base = 2; buf_start = buf[2..]; @@ -1589,7 +1600,7 @@ fn parseWithSign( buf_start = buf[2..]; }, else => {}, - } + }; } } @@ -1598,33 +1609,33 @@ fn parseWithSign( .neg => math.sub, }; - // accumulate into U which is always 8 bits or larger. this prevents - // `buf_base` from overflowing T. - const info = @typeInfo(T); - const U = std.meta.Int(info.Int.signedness, @max(8, info.Int.bits)); - var x: U = 0; + // accumulate into Accumulate which is always 8 bits or larger. this prevents + // `buf_base` from overflowing Result. + const info = @typeInfo(Result); + const Accumulate = std.meta.Int(info.Int.signedness, @max(8, info.Int.bits)); + var accumulate: Accumulate = 0; if (buf_start[0] == '_' or buf_start[buf_start.len - 1] == '_') return error.InvalidCharacter; for (buf_start) |c| { if (c == '_') continue; - const digit = try charToDigit(c, buf_base); - if (x != 0) { - x = try math.mul(U, x, math.cast(U, buf_base) orelse return error.Overflow); + const digit = try charToDigit(math.cast(u8, c) orelse return error.InvalidCharacter, buf_base); + if (accumulate != 0) { + accumulate = try math.mul(Accumulate, accumulate, math.cast(Accumulate, buf_base) orelse return error.Overflow); } else if (sign == .neg) { // The first digit of a negative number. // Consider parsing "-4" as an i3. // This should work, but positive 4 overflows i3, so we can't cast the digit to T and subtract. - x = math.cast(U, -@as(i8, @intCast(digit))) orelse return error.Overflow; + accumulate = math.cast(Accumulate, -@as(i8, @intCast(digit))) orelse return error.Overflow; continue; } - x = try add(U, x, math.cast(U, digit) orelse return error.Overflow); + accumulate = try add(Accumulate, accumulate, math.cast(Accumulate, digit) orelse return error.Overflow); } - return if (T == U) - x + return if (Result == Accumulate) + accumulate else - math.cast(T, x) orelse return error.Overflow; + math.cast(Result, accumulate) orelse return error.Overflow; } /// Parses the string `buf` as unsigned representation in the specified base @@ -1639,7 +1650,7 @@ fn parseWithSign( /// Ignores '_' character in `buf`. /// See also `parseInt`. pub fn parseUnsigned(comptime T: type, buf: []const u8, base: u8) ParseIntError!T { - return parseWithSign(T, buf, base, .pos); + return parseIntWithSign(T, u8, buf, base, .pos); } test parseUnsigned { diff --git a/lib/std/io/tty.zig b/lib/std/io/tty.zig index baf54a1fdf..cdeaba81c5 100644 --- a/lib/std/io/tty.zig +++ b/lib/std/io/tty.zig @@ -24,7 +24,7 @@ pub fn detectConfig(file: File) Config { if (native_os == .windows and file.isTty()) { var info: windows.CONSOLE_SCREEN_BUFFER_INFO = undefined; - if (windows.kernel32.GetConsoleScreenBufferInfo(file.handle, &info) != windows.TRUE) { + if (windows.kernel32.GetConsoleScreenBufferInfo(file.handle, &info) == windows.FALSE) { return if (force_color == true) .escape_codes else .no_color; } return .{ .windows_api = .{ diff --git a/lib/std/process.zig b/lib/std/process.zig index e9de2cf517..7d1f817337 100644 --- a/lib/std/process.zig +++ b/lib/std/process.zig @@ -442,10 +442,7 @@ pub fn parseEnvVarInt(comptime key: []const u8, comptime I: type, base: u8) Pars if (native_os == .windows) { const key_w = comptime std.unicode.utf8ToUtf16LeStringLiteral(key); const text = getenvW(key_w) orelse return error.EnvironmentVariableNotFound; - // For this implementation perhaps std.fmt.parseInt can be expanded to be generic across - // []u8 and []u16 like how many std.mem functions work. - _ = text; - @compileError("TODO implement this"); + return std.fmt.parseIntWithGenericCharacter(I, u16, text, base); } else if (native_os == .wasi and !builtin.link_libc) { @compileError("parseEnvVarInt is not supported for WASI without libc"); } else { diff --git a/src/Module.zig b/src/Module.zig index d38a233a77..bfd79e6117 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -4504,7 +4504,7 @@ pub fn analyzeFnBody(mod: *Module, func_index: InternPool.Index, arena: Allocato log.debug("finish func name '{}'", .{(decl.fullyQualifiedName(mod) catch break :blk).fmt(ip)}); } - const decl_prog_node = mod.sema_prog_ndoe.start((try decl.fullyQualifiedName(mod)).toSlice(ip), 0); + const decl_prog_node = mod.sema_prog_node.start((try decl.fullyQualifiedName(mod)).toSlice(ip), 0); defer decl_prog_node.end(); mod.intern_pool.removeDependenciesForDepender(gpa, InternPool.Depender.wrap(.{ .func = func_index })); -- cgit v1.2.3 From d3b03ed64b9c3a4a963e6e5bef536c61c0e3e3c0 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 26 May 2024 12:20:50 -0700 Subject: frontend: fix use of undefined progress node This was causing a crash when running `zig test`. --- src/Module.zig | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'src/Module.zig') diff --git a/src/Module.zig b/src/Module.zig index bfd79e6117..ef410fad4e 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -5340,15 +5340,13 @@ pub fn populateTestFunctions( // We have to call `ensureDeclAnalyzed` here in case `builtin.test_functions` // was not referenced by start code. mod.sema_prog_node = main_progress_node.start("Semantic Analysis", 0); - mod.codegen_prog_node = main_progress_node.start("Code Generation", 0); defer { mod.sema_prog_node.end(); mod.sema_prog_node = undefined; - mod.codegen_prog_node.end(); - mod.codegen_prog_node = undefined; } try mod.ensureDeclAnalyzed(decl_index); } + const decl = mod.declPtr(decl_index); const test_fn_ty = decl.typeOf(mod).slicePtrFieldType(mod).childType(mod); @@ -5449,7 +5447,15 @@ pub fn populateTestFunctions( decl.val = new_val; decl.has_tv = true; } - try mod.linkerUpdateDecl(decl_index); + { + mod.codegen_prog_node = main_progress_node.start("Code Generation", 0); + defer { + mod.codegen_prog_node.end(); + mod.codegen_prog_node = undefined; + } + + try mod.linkerUpdateDecl(decl_index); + } } pub fn linkerUpdateDecl(zcu: *Zcu, decl_index: Decl.Index) !void { -- cgit v1.2.3