diff --git a/lib/compiler/build_runner.zig b/lib/compiler/build_runner.zig index 545cab6083..ae9eb53fb2 100644 --- a/lib/compiler/build_runner.zig +++ b/lib/compiler/build_runner.zig @@ -442,8 +442,7 @@ pub fn main() !void { if (builtin.single_threaded) fatal("'--webui' is not yet supported on single-threaded hosts", .{}); } - const stderr: std.fs.File = .stderr(); - const ttyconf = get_tty_conf(color, stderr); + const ttyconf = color.detectTtyConf(); switch (ttyconf) { .no_color => try graph.env_map.put("NO_COLOR", "1"), .escape_codes => try graph.env_map.put("CLICOLOR_FORCE", "1"), @@ -522,9 +521,9 @@ pub fn main() !void { .error_style = error_style, .multiline_errors = multiline_errors, .summary = summary orelse if (watch or webui_listen != null) .line else .failures, - .ttyconf = ttyconf, - .stderr = stderr, .thread_pool = undefined, + + .ttyconf = ttyconf, }; defer { run.memory_blocked_steps.deinit(gpa); @@ -563,9 +562,9 @@ pub fn main() !void { break :ws .init(.{ .gpa = gpa, .thread_pool = &run.thread_pool, + .ttyconf = ttyconf, .graph = &graph, .all_steps = run.step_stack.keys(), - .ttyconf = run.ttyconf, .root_prog_node = main_progress_node, .watch = watch, .listen_address = listen_address, @@ -578,7 +577,7 @@ pub fn main() !void { } rebuild: while (true) : (if (run.error_style.clearOnUpdate()) { - const bw = std.debug.lockStderrWriter(&stdio_buffer_allocation); + const bw, _ = std.debug.lockStderrWriter(&stdio_buffer_allocation); defer std.debug.unlockStderrWriter(); try bw.writeAll("\x1B[2J\x1B[3J\x1B[H"); }) { @@ -682,13 +681,14 @@ const Run = struct { /// Allocated into `gpa`. step_stack: std.AutoArrayHashMapUnmanaged(*Step, void), thread_pool: std.Thread.Pool, + /// Similar to the `tty.Config` returned by `std.debug.lockStderrWriter`, + /// but also respects the '--color' flag. + ttyconf: tty.Config, claimed_rss: usize, error_style: ErrorStyle, multiline_errors: MultilineErrors, summary: Summary, - ttyconf: tty.Config, - stderr: File, }; fn prepare( @@ -834,8 +834,6 @@ fn runStepNames( } } - const ttyconf = run.ttyconf; - if (fuzz) |mode| blk: { switch (builtin.os.tag) { // Current implementation depends on two things that need to be ported to Windows: @@ -863,9 +861,9 @@ fn runStepNames( gpa, io, thread_pool, + run.ttyconf, step_stack.keys(), parent_prog_node, - ttyconf, mode, ) catch |err| fatal("failed to start fuzzer: {s}", .{@errorName(err)}); defer f.deinit(); @@ -890,8 +888,9 @@ fn runStepNames( .none => break :summary, } - const w = std.debug.lockStderrWriter(&stdio_buffer_allocation); + const w, _ = std.debug.lockStderrWriter(&stdio_buffer_allocation); defer std.debug.unlockStderrWriter(); + const ttyconf = run.ttyconf; const total_count = success_count + failure_count + pending_count + skipped_count; ttyconf.setColor(w, .cyan) catch {}; @@ -1399,9 +1398,10 @@ fn workerMakeOneStep( const show_error_msgs = s.result_error_msgs.items.len > 0; const show_stderr = s.result_stderr.len > 0; if (show_error_msgs or show_compile_errors or show_stderr) { - const bw = std.debug.lockStderrWriter(&stdio_buffer_allocation); + const bw, _ = std.debug.lockStderrWriter(&stdio_buffer_allocation); defer std.debug.unlockStderrWriter(); - printErrorMessages(run.gpa, s, .{ .ttyconf = run.ttyconf }, bw, run.error_style, run.multiline_errors) catch {}; + const ttyconf = run.ttyconf; + printErrorMessages(run.gpa, s, .{}, bw, ttyconf, run.error_style, run.multiline_errors) catch {}; } handle_result: { @@ -1465,11 +1465,10 @@ pub fn printErrorMessages( failing_step: *Step, options: std.zig.ErrorBundle.RenderOptions, stderr: *Writer, + ttyconf: tty.Config, error_style: ErrorStyle, multiline_errors: MultilineErrors, ) !void { - const ttyconf = options.ttyconf; - if (error_style.verboseContext()) { // Provide context for where these error messages are coming from by // printing the corresponding Step subtree. @@ -1513,7 +1512,7 @@ pub fn printErrorMessages( } } - try failing_step.result_error_bundle.renderToWriter(options, stderr); + try failing_step.result_error_bundle.renderToWriter(options, stderr, ttyconf); for (failing_step.result_error_msgs.items) |msg| { try ttyconf.setColor(stderr, .red); @@ -1759,14 +1758,6 @@ const ErrorStyle = enum { const MultilineErrors = enum { indent, newline, none }; const Summary = enum { all, new, failures, line, none }; -fn get_tty_conf(color: Color, stderr: File) tty.Config { - return switch (color) { - .auto => tty.detectConfig(stderr), - .on => .escape_codes, - .off => .no_color, - }; -} - fn fatalWithHint(comptime f: []const u8, args: anytype) noreturn { std.debug.print(f ++ "\n access the help menu with 'zig build -h'\n", args); process.exit(1); diff --git a/lib/compiler/resinator/cli.zig b/lib/compiler/resinator/cli.zig index 2b31653cca..59568e9cef 100644 --- a/lib/compiler/resinator/cli.zig +++ b/lib/compiler/resinator/cli.zig @@ -124,10 +124,10 @@ pub const Diagnostics = struct { try self.errors.append(self.allocator, error_details); } - pub fn renderToStdErr(self: *Diagnostics, args: []const []const u8, config: std.Io.tty.Config) void { - const stderr = std.debug.lockStderrWriter(&.{}); + pub fn renderToStdErr(self: *Diagnostics, args: []const []const u8) void { + const stderr, const ttyconf = std.debug.lockStderrWriter(&.{}); defer std.debug.unlockStderrWriter(); - self.renderToWriter(args, stderr, config) catch return; + self.renderToWriter(args, stderr, ttyconf) catch return; } pub fn renderToWriter(self: *Diagnostics, args: []const []const u8, writer: *std.Io.Writer, config: std.Io.tty.Config) !void { diff --git a/lib/compiler/resinator/errors.zig b/lib/compiler/resinator/errors.zig index aad74a3ca3..f9ccc43a7f 100644 --- a/lib/compiler/resinator/errors.zig +++ b/lib/compiler/resinator/errors.zig @@ -67,20 +67,15 @@ pub const Diagnostics = struct { return @intCast(index); } - pub fn renderToStdErr(self: *Diagnostics, cwd: std.fs.Dir, source: []const u8, tty_config: std.Io.tty.Config, source_mappings: ?SourceMappings) void { + pub fn renderToStdErr(self: *Diagnostics, cwd: std.fs.Dir, source: []const u8, source_mappings: ?SourceMappings) void { const io = self.io; - const stderr = std.debug.lockStderrWriter(&.{}); + const stderr, const ttyconf = std.debug.lockStderrWriter(&.{}); defer std.debug.unlockStderrWriter(); for (self.errors.items) |err_details| { - renderErrorMessage(io, stderr, tty_config, cwd, err_details, source, self.strings.items, source_mappings) catch return; + renderErrorMessage(io, stderr, ttyconf, cwd, err_details, source, self.strings.items, source_mappings) catch return; } } - pub fn renderToStdErrDetectTTY(self: *Diagnostics, cwd: std.fs.Dir, source: []const u8, source_mappings: ?SourceMappings) void { - const tty_config = std.Io.tty.detectConfig(std.fs.File.stderr()); - return self.renderToStdErr(cwd, source, tty_config, source_mappings); - } - pub fn contains(self: *const Diagnostics, err: ErrorDetails.Error) bool { for (self.errors.items) |details| { if (details.err == err) return true; diff --git a/lib/compiler/resinator/main.zig b/lib/compiler/resinator/main.zig index b32237b06b..6d6819f45a 100644 --- a/lib/compiler/resinator/main.zig +++ b/lib/compiler/resinator/main.zig @@ -28,13 +28,11 @@ pub fn main() !void { defer arena_state.deinit(); const arena = arena_state.allocator(); - const stderr = std.fs.File.stderr(); - const stderr_config = std.Io.tty.detectConfig(stderr); - const args = try std.process.argsAlloc(arena); if (args.len < 2) { - try renderErrorMessage(std.debug.lockStderrWriter(&.{}), stderr_config, .err, "expected zig lib dir as first argument", .{}); + const w, const ttyconf = std.debug.lockStderrWriter(&.{}); + try renderErrorMessage(w, ttyconf, .err, "expected zig lib dir as first argument", .{}); std.process.exit(1); } const zig_lib_dir = args[1]; @@ -56,9 +54,7 @@ pub fn main() !void { .in = undefined, // won't be receiving messages }, }, - false => .{ - .tty = stderr_config, - }, + false => .stderr, }; var options = options: { @@ -75,12 +71,14 @@ pub fn main() !void { if (!zig_integration) { // print any warnings/notes - cli_diagnostics.renderToStdErr(cli_args, stderr_config); + cli_diagnostics.renderToStdErr(cli_args); // If there was something printed, then add an extra newline separator // so that there is a clear separation between the cli diagnostics and whatever // gets printed after if (cli_diagnostics.errors.items.len > 0) { - try stderr.writeAll("\n"); + const stderr, _ = std.debug.lockStderrWriter(&.{}); + defer std.debug.unlockStderrWriter(); + try stderr.writeByte('\n'); } } break :options options; @@ -130,17 +128,18 @@ pub fn main() !void { const aro_arena = aro_arena_state.allocator(); var stderr_buf: [512]u8 = undefined; - var stderr_writer = stderr.writer(&stderr_buf); - var diagnostics: aro.Diagnostics = switch (zig_integration) { - false => .{ .output = .{ .to_writer = .{ - .writer = &stderr_writer.interface, - .color = stderr_config, - } } }, - true => .{ .output = .{ .to_list = .{ - .arena = .init(gpa), - } } }, - }; - defer diagnostics.deinit(); + var diagnostics: aro.Diagnostics = .{ .output = output: { + if (zig_integration) break :output .{ .to_list = .{ .arena = .init(gpa) } }; + const w, const ttyconf = std.debug.lockStderrWriter(&stderr_buf); + break :output .{ .to_writer = .{ + .writer = w, + .color = ttyconf, + } }; + } }; + defer { + diagnostics.deinit(); + if (!zig_integration) std.debug.unlockStderrWriter(); + } var comp = aro.Compilation.init(aro_arena, aro_arena, io, &diagnostics, std.fs.cwd()); defer comp.deinit(); @@ -307,7 +306,7 @@ pub fn main() !void { // print any warnings/notes if (!zig_integration) { - diagnostics.renderToStdErr(std.fs.cwd(), final_input, stderr_config, mapping_results.mappings); + diagnostics.renderToStdErr(std.fs.cwd(), final_input, mapping_results.mappings); } // write the depfile @@ -660,7 +659,7 @@ const SourceMappings = @import("source_mapping.zig").SourceMappings; const ErrorHandler = union(enum) { server: std.zig.Server, - tty: std.Io.tty.Config, + stderr, pub fn emitCliDiagnostics( self: *ErrorHandler, @@ -675,9 +674,7 @@ const ErrorHandler = union(enum) { try server.serveErrorBundle(error_bundle); }, - .tty => { - diagnostics.renderToStdErr(args, self.tty); - }, + .stderr => diagnostics.renderToStdErr(args), } } @@ -698,11 +695,11 @@ const ErrorHandler = union(enum) { try server.serveErrorBundle(error_bundle); }, - .tty => { + .stderr => { // aro errors have already been emitted - const stderr = std.debug.lockStderrWriter(&.{}); + const stderr, const ttyconf = std.debug.lockStderrWriter(&.{}); defer std.debug.unlockStderrWriter(); - try renderErrorMessage(stderr, self.tty, .err, "{s}", .{fail_msg}); + try renderErrorMessage(stderr, ttyconf, .err, "{s}", .{fail_msg}); }, } } @@ -722,9 +719,7 @@ const ErrorHandler = union(enum) { try server.serveErrorBundle(error_bundle); }, - .tty => { - diagnostics.renderToStdErr(cwd, source, self.tty, mappings); - }, + .stderr => diagnostics.renderToStdErr(cwd, source, mappings), } } @@ -745,10 +740,10 @@ const ErrorHandler = union(enum) { try server.serveErrorBundle(error_bundle); }, - .tty => { - const stderr = std.debug.lockStderrWriter(&.{}); + .stderr => { + const stderr, const ttyconf = std.debug.lockStderrWriter(&.{}); defer std.debug.unlockStderrWriter(); - try renderErrorMessage(stderr, self.tty, msg_type, format, args); + try renderErrorMessage(stderr, ttyconf, msg_type, format, args); }, } } diff --git a/lib/compiler/std-docs.zig b/lib/compiler/std-docs.zig index e80c3d3dcd..f560e05cca 100644 --- a/lib/compiler/std-docs.zig +++ b/lib/compiler/std-docs.zig @@ -394,8 +394,7 @@ fn buildWasmBinary( } if (result_error_bundle.errorMessageCount() > 0) { - const color = std.zig.Color.auto; - result_error_bundle.renderToStdErr(color.renderOptions()); + result_error_bundle.renderToStdErr(.{}, true); std.log.err("the following command failed with {d} compilation errors:\n{s}", .{ result_error_bundle.errorMessageCount(), try std.Build.Step.allocPrintCmd(arena, null, argv.items), diff --git a/lib/std/Build.zig b/lib/std/Build.zig index e9d2e81fba..3b78fc6f71 100644 --- a/lib/std/Build.zig +++ b/lib/std/Build.zig @@ -2257,8 +2257,8 @@ pub const GeneratedFile = struct { pub fn getPath2(gen: GeneratedFile, src_builder: *Build, asking_step: ?*Step) []const u8 { return gen.path orelse { - const w = debug.lockStderrWriter(&.{}); - dumpBadGetPathHelp(gen.step, w, .detect(.stderr()), src_builder, asking_step) catch {}; + const w, const ttyconf = debug.lockStderrWriter(&.{}); + dumpBadGetPathHelp(gen.step, w, ttyconf, src_builder, asking_step) catch {}; debug.unlockStderrWriter(); @panic("misconfigured build script"); }; @@ -2466,8 +2466,8 @@ pub const LazyPath = union(enum) { var file_path: Cache.Path = .{ .root_dir = Cache.Directory.cwd(), .sub_path = gen.file.path orelse { - const w = debug.lockStderrWriter(&.{}); - dumpBadGetPathHelp(gen.file.step, w, .detect(.stderr()), src_builder, asking_step) catch {}; + const w, const ttyconf = debug.lockStderrWriter(&.{}); + dumpBadGetPathHelp(gen.file.step, w, ttyconf, src_builder, asking_step) catch {}; debug.unlockStderrWriter(); @panic("misconfigured build script"); }, @@ -2558,13 +2558,11 @@ fn dumpBadDirnameHelp( comptime msg: []const u8, args: anytype, ) anyerror!void { - const w = debug.lockStderrWriter(&.{}); + const w, const tty_config = debug.lockStderrWriter(&.{}); defer debug.unlockStderrWriter(); try w.print(msg, args); - const tty_config = std.Io.tty.detectConfig(.stderr()); - if (fail_step) |s| { tty_config.setColor(w, .red) catch {}; try w.writeAll(" The step was created by this stack trace:\n"); diff --git a/lib/std/Build/Fuzz.zig b/lib/std/Build/Fuzz.zig index d342628871..6dd4f70f9f 100644 --- a/lib/std/Build/Fuzz.zig +++ b/lib/std/Build/Fuzz.zig @@ -16,6 +16,7 @@ const build_runner = @import("root"); gpa: Allocator, io: Io, +ttyconf: tty.Config, mode: Mode, /// Allocated into `gpa`. @@ -25,7 +26,6 @@ wait_group: std.Thread.WaitGroup, root_prog_node: std.Progress.Node, prog_node: std.Progress.Node, thread_pool: *std.Thread.Pool, -ttyconf: tty.Config, /// Protects `coverage_files`. coverage_mutex: std.Thread.Mutex, @@ -79,9 +79,9 @@ pub fn init( gpa: Allocator, io: Io, thread_pool: *std.Thread.Pool, + ttyconf: tty.Config, all_steps: []const *Build.Step, root_prog_node: std.Progress.Node, - ttyconf: tty.Config, mode: Mode, ) Allocator.Error!Fuzz { const run_steps: []const *Step.Run = steps: { @@ -115,11 +115,11 @@ pub fn init( return .{ .gpa = gpa, .io = io, + .ttyconf = ttyconf, .mode = mode, .run_steps = run_steps, .wait_group = .{}, .thread_pool = thread_pool, - .ttyconf = ttyconf, .root_prog_node = root_prog_node, .prog_node = .none, .coverage_files = .empty, @@ -158,7 +158,7 @@ pub fn deinit(fuzz: *Fuzz) void { fuzz.gpa.free(fuzz.run_steps); } -fn rebuildTestsWorkerRun(run: *Step.Run, gpa: Allocator, ttyconf: std.Io.tty.Config, parent_prog_node: std.Progress.Node) void { +fn rebuildTestsWorkerRun(run: *Step.Run, gpa: Allocator, ttyconf: tty.Config, parent_prog_node: std.Progress.Node) void { rebuildTestsWorkerRunFallible(run, gpa, ttyconf, parent_prog_node) catch |err| { const compile = run.producer.?; log.err("step '{s}': failed to rebuild in fuzz mode: {s}", .{ @@ -167,7 +167,7 @@ fn rebuildTestsWorkerRun(run: *Step.Run, gpa: Allocator, ttyconf: std.Io.tty.Con }; } -fn rebuildTestsWorkerRunFallible(run: *Step.Run, gpa: Allocator, ttyconf: std.Io.tty.Config, parent_prog_node: std.Progress.Node) !void { +fn rebuildTestsWorkerRunFallible(run: *Step.Run, gpa: Allocator, ttyconf: tty.Config, parent_prog_node: std.Progress.Node) !void { const compile = run.producer.?; const prog_node = parent_prog_node.start(compile.step.name, 0); defer prog_node.end(); @@ -180,9 +180,9 @@ fn rebuildTestsWorkerRunFallible(run: *Step.Run, gpa: Allocator, ttyconf: std.Io if (show_error_msgs or show_compile_errors or show_stderr) { var buf: [256]u8 = undefined; - const w = std.debug.lockStderrWriter(&buf); + const w, _ = std.debug.lockStderrWriter(&buf); defer std.debug.unlockStderrWriter(); - build_runner.printErrorMessages(gpa, &compile.step, .{ .ttyconf = ttyconf }, w, .verbose, .indent) catch {}; + build_runner.printErrorMessages(gpa, &compile.step, .{}, w, ttyconf, .verbose, .indent) catch {}; } const rebuilt_bin_path = result catch |err| switch (err) { @@ -206,9 +206,9 @@ fn fuzzWorkerRun( run.rerunInFuzzMode(fuzz, unit_test_index, prog_node) catch |err| switch (err) { error.MakeFailed => { var buf: [256]u8 = undefined; - const w = std.debug.lockStderrWriter(&buf); + const w, _ = std.debug.lockStderrWriter(&buf); defer std.debug.unlockStderrWriter(); - build_runner.printErrorMessages(gpa, &run.step, .{ .ttyconf = fuzz.ttyconf }, w, .verbose, .indent) catch {}; + build_runner.printErrorMessages(gpa, &run.step, .{}, w, fuzz.ttyconf, .verbose, .indent) catch {}; return; }, else => { diff --git a/lib/std/Build/Step/Compile.zig b/lib/std/Build/Step/Compile.zig index 2188d8bfc7..a5f2d696be 100644 --- a/lib/std/Build/Step/Compile.zig +++ b/lib/std/Build/Step/Compile.zig @@ -1056,15 +1056,15 @@ fn getGeneratedFilePath(compile: *Compile, comptime tag_name: []const u8, asking const maybe_path: ?*GeneratedFile = @field(compile, tag_name); const generated_file = maybe_path orelse { - const w = std.debug.lockStderrWriter(&.{}); - std.Build.dumpBadGetPathHelp(&compile.step, w, .detect(.stderr()), compile.step.owner, asking_step) catch {}; + const w, const ttyconf = std.debug.lockStderrWriter(&.{}); + std.Build.dumpBadGetPathHelp(&compile.step, w, ttyconf, compile.step.owner, asking_step) catch {}; std.debug.unlockStderrWriter(); @panic("missing emit option for " ++ tag_name); }; const path = generated_file.path orelse { - const w = std.debug.lockStderrWriter(&.{}); - std.Build.dumpBadGetPathHelp(&compile.step, w, .detect(.stderr()), compile.step.owner, asking_step) catch {}; + const w, const ttyconf = std.debug.lockStderrWriter(&.{}); + std.Build.dumpBadGetPathHelp(&compile.step, w, ttyconf, compile.step.owner, asking_step) catch {}; std.debug.unlockStderrWriter(); @panic(tag_name ++ " is null. Is there a missing step dependency?"); }; @@ -2027,10 +2027,9 @@ fn checkCompileErrors(compile: *Compile) !void { var aw: std.Io.Writer.Allocating = .init(arena); defer aw.deinit(); try actual_eb.renderToWriter(.{ - .ttyconf = .no_color, .include_reference_trace = false, .include_source_line = false, - }, &aw.writer); + }, &aw.writer, .no_color); break :ae try aw.toOwnedSlice(); }; diff --git a/lib/std/Build/Step/Run.zig b/lib/std/Build/Step/Run.zig index 314862e201..eb1de3dd3b 100644 --- a/lib/std/Build/Step/Run.zig +++ b/lib/std/Build/Step/Run.zig @@ -1587,11 +1587,15 @@ fn spawnChildAndCollect( run.step.test_results = res.test_results; if (res.test_metadata) |tm| { run.cached_test_metadata = tm.toCachedTestMetadata(); - if (options.web_server) |ws| ws.updateTimeReportRunTest( - run, - &run.cached_test_metadata.?, - tm.ns_per_test, - ); + if (options.web_server) |ws| { + if (b.graph.time_report) { + ws.updateTimeReportRunTest( + run, + &run.cached_test_metadata.?, + tm.ns_per_test, + ); + } + } } return null; } else { diff --git a/lib/std/Build/WebServer.zig b/lib/std/Build/WebServer.zig index 50e304c950..4a136ccbf4 100644 --- a/lib/std/Build/WebServer.zig +++ b/lib/std/Build/WebServer.zig @@ -54,9 +54,9 @@ pub fn notifyUpdate(ws: *WebServer) void { pub const Options = struct { gpa: Allocator, thread_pool: *std.Thread.Pool, + ttyconf: Io.tty.Config, graph: *const std.Build.Graph, all_steps: []const *Build.Step, - ttyconf: Io.tty.Config, root_prog_node: std.Progress.Node, watch: bool, listen_address: net.IpAddress, @@ -101,10 +101,10 @@ pub fn init(opts: Options) WebServer { return .{ .gpa = opts.gpa, .thread_pool = opts.thread_pool, + .ttyconf = opts.ttyconf, .graph = opts.graph, .all_steps = all_steps, .listen_address = opts.listen_address, - .ttyconf = opts.ttyconf, .root_prog_node = opts.root_prog_node, .watch = opts.watch, @@ -236,9 +236,9 @@ pub fn finishBuild(ws: *WebServer, opts: struct { ws.gpa, ws.graph.io, ws.thread_pool, + ws.ttyconf, ws.all_steps, ws.root_prog_node, - ws.ttyconf, .{ .forever = .{ .ws = ws } }, ) catch |err| std.process.fatal("failed to start fuzzer: {s}", .{@errorName(err)}); ws.fuzz.?.start(); @@ -655,8 +655,7 @@ fn buildClientWasm(ws: *WebServer, arena: Allocator, optimize: std.builtin.Optim } if (result_error_bundle.errorMessageCount() > 0) { - const color = std.zig.Color.auto; - result_error_bundle.renderToStdErr(color.renderOptions()); + result_error_bundle.renderToStdErr(.{}, .auto); log.err("the following command failed with {d} compilation errors:\n{s}", .{ result_error_bundle.errorMessageCount(), try Build.Step.allocPrintCmd(arena, null, argv.items), diff --git a/lib/std/debug.zig b/lib/std/debug.zig index 3bb5d6d7ab..19b3a3c2fb 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -272,7 +272,7 @@ pub fn unlockStdErr() void { std.Progress.unlockStdErr(); } -/// Allows the caller to freely write to stderr until `unlockStdErr` is called. +/// Allows the caller to freely write to stderr until `unlockStderrWriter` is called. /// /// During the lock, any `std.Progress` information is cleared from the terminal. /// @@ -282,8 +282,16 @@ pub fn unlockStdErr() void { /// /// The returned `Writer` does not need to be manually flushed: flushing is performed automatically /// when the matching `unlockStderrWriter` call occurs. -pub fn lockStderrWriter(buffer: []u8) *Writer { - return std.Progress.lockStderrWriter(buffer); +pub fn lockStderrWriter(buffer: []u8) struct { *Writer, tty.Config } { + const global = struct { + var conf: ?tty.Config = null; + }; + const w = std.Progress.lockStderrWriter(buffer); + // The stderr lock also locks access to `global.conf`. + if (global.conf == null) { + global.conf = .detect(.stderr()); + } + return .{ w, global.conf.? }; } pub fn unlockStderrWriter() void { @@ -297,7 +305,7 @@ pub fn unlockStderrWriter() void { /// function returns. pub fn print(comptime fmt: []const u8, args: anytype) void { var buffer: [64]u8 = undefined; - const bw = lockStderrWriter(&buffer); + const bw, _ = lockStderrWriter(&buffer); defer unlockStderrWriter(); nosuspend bw.print(fmt, args) catch return; } @@ -314,9 +322,8 @@ pub inline fn getSelfDebugInfo() !*SelfInfo { /// Tries to print a hexadecimal view of the bytes, unbuffered, and ignores any error returned. /// Obtains the stderr mutex while dumping. pub fn dumpHex(bytes: []const u8) void { - const bw = lockStderrWriter(&.{}); + const bw, const ttyconf = lockStderrWriter(&.{}); defer unlockStderrWriter(); - const ttyconf = tty.detectConfig(.stderr()); dumpHexFallible(bw, ttyconf, bytes) catch {}; } @@ -538,9 +545,7 @@ pub fn defaultPanic( _ = panicking.fetchAdd(1, .seq_cst); trace: { - const tty_config = tty.detectConfig(.stderr()); - - const stderr = lockStderrWriter(&.{}); + const stderr, const tty_config = lockStderrWriter(&.{}); defer unlockStderrWriter(); if (builtin.single_threaded) { @@ -743,8 +748,7 @@ pub noinline fn writeCurrentStackTrace(options: StackUnwindOptions, writer: *Wri } /// A thin wrapper around `writeCurrentStackTrace` which writes to stderr and ignores write errors. pub fn dumpCurrentStackTrace(options: StackUnwindOptions) void { - const tty_config = tty.detectConfig(.stderr()); - const stderr = lockStderrWriter(&.{}); + const stderr, const tty_config = lockStderrWriter(&.{}); defer unlockStderrWriter(); writeCurrentStackTrace(.{ .first_address = a: { @@ -809,8 +813,7 @@ pub fn writeStackTrace(st: *const StackTrace, writer: *Writer, tty_config: tty.C } /// A thin wrapper around `writeStackTrace` which writes to stderr and ignores write errors. pub fn dumpStackTrace(st: *const StackTrace) void { - const tty_config = tty.detectConfig(.stderr()); - const stderr = lockStderrWriter(&.{}); + const stderr, const tty_config = lockStderrWriter(&.{}); defer unlockStderrWriter(); writeStackTrace(st, stderr, tty_config) catch |err| switch (err) { error.WriteFailed => {}, @@ -1552,9 +1555,7 @@ pub fn defaultHandleSegfault(addr: ?usize, name: []const u8, opt_ctx: ?CpuContex _ = panicking.fetchAdd(1, .seq_cst); trace: { - const tty_config = tty.detectConfig(.stderr()); - - const stderr = lockStderrWriter(&.{}); + const stderr, const tty_config = lockStderrWriter(&.{}); defer unlockStderrWriter(); if (addr) |a| { @@ -1612,7 +1613,7 @@ test "manage resources correctly" { &di, &discarding.writer, S.showMyTrace(), - tty.detectConfig(.stderr()), + .no_color, ); } @@ -1674,8 +1675,7 @@ pub fn ConfigurableTrace(comptime size: usize, comptime stack_frame_count: usize pub fn dump(t: @This()) void { if (!enabled) return; - const tty_config = tty.detectConfig(.stderr()); - const stderr = lockStderrWriter(&.{}); + const stderr, const tty_config = lockStderrWriter(&.{}); defer unlockStderrWriter(); const end = @min(t.index, size); for (t.addrs[0..end], 0..) |frames_array, i| { diff --git a/lib/std/json/dynamic.zig b/lib/std/json/dynamic.zig index 8aacf42865..c3cccd1a91 100644 --- a/lib/std/json/dynamic.zig +++ b/lib/std/json/dynamic.zig @@ -47,7 +47,7 @@ pub const Value = union(enum) { } pub fn dump(v: Value) void { - const w = std.debug.lockStderrWriter(&.{}); + const w, _ = std.debug.lockStderrWriter(&.{}); defer std.debug.unlockStderrWriter(); json.Stringify.value(v, .{}, w) catch return; diff --git a/lib/std/log.zig b/lib/std/log.zig index 113831e462..51b01fe47f 100644 --- a/lib/std/log.zig +++ b/lib/std/log.zig @@ -13,63 +13,15 @@ //! `const log = std.log.scoped(.libfoo);` to use .libfoo as the scope of its //! log messages. //! -//! An example `logFn` might look something like this: -//! +//! For an example implementation of the `logFn` function, see `defaultLog`, +//! which is the default implementation. It outputs to stderr, using color if +//! the detected `std.Io.tty.Config` supports it. Its output looks like this: //! ``` -//! const std = @import("std"); -//! -//! pub const std_options: std.Options = .{ -//! // Set the log level to info -//! .log_level = .info, -//! -//! // Define logFn to override the std implementation -//! .logFn = myLogFn, -//! }; -//! -//! pub fn myLogFn( -//! comptime level: std.log.Level, -//! comptime scope: @Type(.enum_literal), -//! comptime format: []const u8, -//! args: anytype, -//! ) void { -//! // Ignore all non-error logging from sources other than -//! // .my_project, .nice_library and the default -//! const scope_prefix = "(" ++ switch (scope) { -//! .my_project, .nice_library, std.log.default_log_scope => @tagName(scope), -//! else => if (@intFromEnum(level) <= @intFromEnum(std.log.Level.err)) -//! @tagName(scope) -//! else -//! return, -//! } ++ "): "; -//! -//! const prefix = "[" ++ comptime level.asText() ++ "] " ++ scope_prefix; -//! -//! // Print the message to stderr, silently ignoring any errors -//! std.debug.lockStdErr(); -//! defer std.debug.unlockStdErr(); -//! var stderr = std.fs.File.stderr().writer(&.{}); -//! nosuspend stderr.interface.print(prefix ++ format ++ "\n", args) catch return; -//! } -//! -//! pub fn main() void { -//! // Using the default scope: -//! std.log.debug("A borderline useless debug log message", .{}); // Won't be printed as log_level is .info -//! std.log.info("Flux capacitor is starting to overheat", .{}); -//! -//! // Using scoped logging: -//! const my_project_log = std.log.scoped(.my_project); -//! const nice_library_log = std.log.scoped(.nice_library); -//! const verbose_lib_log = std.log.scoped(.verbose_lib); -//! -//! my_project_log.debug("Starting up", .{}); // Won't be printed as log_level is .info -//! nice_library_log.warn("Something went very wrong, sorry", .{}); -//! verbose_lib_log.warn("Added 1 + 1: {}", .{1 + 1}); // Won't be printed as it gets filtered out by our log function -//! } -//! ``` -//! Which produces the following output: -//! ``` -//! [info] (default): Flux capacitor is starting to overheat -//! [warning] (nice_library): Something went very wrong, sorry +//! error: this is an error +//! error(scope): this is an error with a non-default scope +//! warning: this is a warning +//! info: this is an informative message +//! debug: this is a debugging message //! ``` const std = @import("std.zig"); @@ -104,37 +56,28 @@ pub const default_level: Level = switch (builtin.mode) { .ReleaseSafe, .ReleaseFast, .ReleaseSmall => .info, }; -const level = std.options.log_level; - pub const ScopeLevel = struct { scope: @Type(.enum_literal), level: Level, }; -const scope_levels = std.options.log_scope_levels; - fn log( - comptime message_level: Level, + comptime level: Level, comptime scope: @Type(.enum_literal), comptime format: []const u8, args: anytype, ) void { - if (comptime !logEnabled(message_level, scope)) return; + if (comptime !logEnabled(level, scope)) return; - std.options.logFn(message_level, scope, format, args); + std.options.logFn(level, scope, format, args); } /// Determine if a specific log message level and scope combination are enabled for logging. -pub fn logEnabled(comptime message_level: Level, comptime scope: @Type(.enum_literal)) bool { - inline for (scope_levels) |scope_level| { - if (scope_level.scope == scope) return @intFromEnum(message_level) <= @intFromEnum(scope_level.level); +pub fn logEnabled(comptime level: Level, comptime scope: @Type(.enum_literal)) bool { + inline for (std.options.log_scope_levels) |scope_level| { + if (scope_level.scope == scope) return @intFromEnum(level) <= @intFromEnum(scope_level.level); } - return @intFromEnum(message_level) <= @intFromEnum(level); -} - -/// Determine if a specific log message level using the default log scope is enabled for logging. -pub fn defaultLogEnabled(comptime message_level: Level) bool { - return comptime logEnabled(message_level, default_log_scope); + return @intFromEnum(level) <= @intFromEnum(std.options.log_level); } /// The default implementation for the log function. Custom log functions may @@ -143,17 +86,31 @@ pub fn defaultLogEnabled(comptime message_level: Level) bool { /// Uses a 64-byte buffer for formatted printing which is flushed before this /// function returns. pub fn defaultLog( - comptime message_level: Level, + comptime level: Level, comptime scope: @Type(.enum_literal), comptime format: []const u8, args: anytype, ) void { - const level_txt = comptime message_level.asText(); - const prefix2 = if (scope == .default) ": " else "(" ++ @tagName(scope) ++ "): "; var buffer: [64]u8 = undefined; - const stderr = std.debug.lockStderrWriter(&buffer); + const stderr, const ttyconf = std.debug.lockStderrWriter(&buffer); defer std.debug.unlockStderrWriter(); - nosuspend stderr.print(level_txt ++ prefix2 ++ format ++ "\n", args) catch return; + ttyconf.setColor(stderr, switch (level) { + .err => .red, + .warn => .yellow, + .info => .green, + .debug => .magenta, + }) catch {}; + ttyconf.setColor(stderr, .bold) catch {}; + stderr.writeAll(level.asText()) catch return; + ttyconf.setColor(stderr, .reset) catch {}; + ttyconf.setColor(stderr, .dim) catch {}; + ttyconf.setColor(stderr, .bold) catch {}; + if (scope != .default) { + stderr.print("({s})", .{@tagName(scope)}) catch return; + } + stderr.writeAll(": ") catch return; + ttyconf.setColor(stderr, .reset) catch {}; + stderr.print(format ++ "\n", args) catch return; } /// Returns a scoped logging namespace that logs all messages using the scope diff --git a/lib/std/testing.zig b/lib/std/testing.zig index 7cef6f9c58..b99542e7e5 100644 --- a/lib/std/testing.zig +++ b/lib/std/testing.zig @@ -355,7 +355,7 @@ test expectApproxEqRel { /// This function is intended to be used only in tests. When the two slices are not /// equal, prints diagnostics to stderr to show exactly how they are not equal (with /// the differences highlighted in red), then returns a test failure error. -/// The colorized output is optional and controlled by the return of `std.Io.tty.detectConfig()`. +/// The colorized output is optional and controlled by the return of `std.Io.tty.Config.detect`. /// If your inputs are UTF-8 encoded strings, consider calling `expectEqualStrings` instead. pub fn expectEqualSlices(comptime T: type, expected: []const T, actual: []const T) !void { const diff_index: usize = diff_index: { @@ -367,9 +367,9 @@ pub fn expectEqualSlices(comptime T: type, expected: []const T, actual: []const break :diff_index if (expected.len == actual.len) return else shortest; }; if (!backend_can_print) return error.TestExpectedEqual; - const stderr_w = std.debug.lockStderrWriter(&.{}); + const stderr_w, const ttyconf = std.debug.lockStderrWriter(&.{}); defer std.debug.unlockStderrWriter(); - failEqualSlices(T, expected, actual, diff_index, stderr_w) catch {}; + failEqualSlices(T, expected, actual, diff_index, stderr_w, ttyconf) catch {}; return error.TestExpectedEqual; } @@ -379,6 +379,7 @@ fn failEqualSlices( actual: []const T, diff_index: usize, w: *std.Io.Writer, + ttyconf: std.Io.tty.Config, ) !void { try w.print("slices differ. first difference occurs at index {d} (0x{X})\n", .{ diff_index, diff_index }); @@ -398,7 +399,6 @@ fn failEqualSlices( const actual_window = actual[window_start..@min(actual.len, window_start + max_window_size)]; const actual_truncated = window_start + actual_window.len < actual.len; - const ttyconf = std.Io.tty.detectConfig(.stderr()); var differ = if (T == u8) BytesDiffer{ .expected = expected_window, .actual = actual_window, diff --git a/lib/std/zig.zig b/lib/std/zig.zig index 34851709ab..dcdc727ae2 100644 --- a/lib/std/zig.zig +++ b/lib/std/zig.zig @@ -53,17 +53,18 @@ pub const Color = enum { /// Assume stderr is a terminal. on, - pub fn get_tty_conf(color: Color) Io.tty.Config { + pub fn getTtyConf(color: Color, detected: Io.tty.Config) Io.tty.Config { return switch (color) { - .auto => Io.tty.detectConfig(std.fs.File.stderr()), + .auto => detected, .on => .escape_codes, .off => .no_color, }; } - - pub fn renderOptions(color: Color) std.zig.ErrorBundle.RenderOptions { - return .{ - .ttyconf = get_tty_conf(color), + pub fn detectTtyConf(color: Color) Io.tty.Config { + return switch (color) { + .auto => .detect(.stderr()), + .on => .escape_codes, + .off => .no_color, }; } }; @@ -606,7 +607,7 @@ pub fn printAstErrorsToStderr(gpa: Allocator, tree: Ast, path: []const u8, color var error_bundle = try wip_errors.toOwnedBundle(""); defer error_bundle.deinit(gpa); - error_bundle.renderToStdErr(color.renderOptions()); + error_bundle.renderToStdErr(.{}, color); } pub fn putAstErrorsIntoBundle( diff --git a/lib/std/zig/ErrorBundle.zig b/lib/std/zig/ErrorBundle.zig index 2b2ad396de..bcef7f407c 100644 --- a/lib/std/zig/ErrorBundle.zig +++ b/lib/std/zig/ErrorBundle.zig @@ -157,23 +157,22 @@ pub fn nullTerminatedString(eb: ErrorBundle, index: String) [:0]const u8 { } pub const RenderOptions = struct { - ttyconf: Io.tty.Config, include_reference_trace: bool = true, include_source_line: bool = true, include_log_text: bool = true, }; -pub fn renderToStdErr(eb: ErrorBundle, options: RenderOptions) void { +pub fn renderToStdErr(eb: ErrorBundle, options: RenderOptions, color: std.zig.Color) void { var buffer: [256]u8 = undefined; - const w = std.debug.lockStderrWriter(&buffer); + const w, const ttyconf = std.debug.lockStderrWriter(&buffer); defer std.debug.unlockStderrWriter(); - renderToWriter(eb, options, w) catch return; + renderToWriter(eb, options, w, color.getTtyConf(ttyconf)) catch return; } -pub fn renderToWriter(eb: ErrorBundle, options: RenderOptions, w: *Writer) (Writer.Error || std.posix.UnexpectedError)!void { +pub fn renderToWriter(eb: ErrorBundle, options: RenderOptions, w: *Writer, ttyconf: Io.tty.Config) (Writer.Error || std.posix.UnexpectedError)!void { if (eb.extra.len == 0) return; for (eb.getMessages()) |err_msg| { - try renderErrorMessageToWriter(eb, options, err_msg, w, "error", .red, 0); + try renderErrorMessageToWriter(eb, options, err_msg, w, ttyconf, "error", .red, 0); } if (options.include_log_text) { @@ -190,11 +189,11 @@ fn renderErrorMessageToWriter( options: RenderOptions, err_msg_index: MessageIndex, w: *Writer, + ttyconf: Io.tty.Config, kind: []const u8, color: Io.tty.Color, indent: usize, ) (Writer.Error || std.posix.UnexpectedError)!void { - const ttyconf = options.ttyconf; const err_msg = eb.getErrorMessage(err_msg_index); if (err_msg.src_loc != .none) { const src = eb.extraData(SourceLocation, @intFromEnum(err_msg.src_loc)); @@ -251,7 +250,7 @@ fn renderErrorMessageToWriter( try ttyconf.setColor(w, .reset); } for (eb.getNotes(err_msg_index)) |note| { - try renderErrorMessageToWriter(eb, options, note, w, "note", .cyan, indent); + try renderErrorMessageToWriter(eb, options, note, w, ttyconf, "note", .cyan, indent); } if (src.data.reference_trace_len > 0 and options.include_reference_trace) { try ttyconf.setColor(w, .reset); @@ -300,7 +299,7 @@ fn renderErrorMessageToWriter( } try ttyconf.setColor(w, .reset); for (eb.getNotes(err_msg_index)) |note| { - try renderErrorMessageToWriter(eb, options, note, w, "note", .cyan, indent + 4); + try renderErrorMessageToWriter(eb, options, note, w, ttyconf, "note", .cyan, indent + 4); } } } diff --git a/lib/std/zig/parser_test.zig b/lib/std/zig/parser_test.zig index d08f5b60ba..c3451f5238 100644 --- a/lib/std/zig/parser_test.zig +++ b/lib/std/zig/parser_test.zig @@ -6386,7 +6386,7 @@ var fixed_buffer_mem: [100 * 1024]u8 = undefined; fn testParse(source: [:0]const u8, allocator: mem.Allocator, anything_changed: *bool) ![]u8 { var buffer: [64]u8 = undefined; - const stderr = std.debug.lockStderrWriter(&buffer); + const stderr, _ = std.debug.lockStderrWriter(&buffer); defer std.debug.unlockStderrWriter(); var tree = try std.zig.Ast.parse(allocator, source, .zig); diff --git a/src/Air/print.zig b/src/Air/print.zig index 7f3758d47b..73cf2ed9b3 100644 --- a/src/Air/print.zig +++ b/src/Air/print.zig @@ -73,13 +73,13 @@ pub fn writeInst( } pub fn dump(air: Air, pt: Zcu.PerThread, liveness: ?Air.Liveness) void { - const stderr_bw = std.debug.lockStderrWriter(&.{}); + const stderr_bw, _ = std.debug.lockStderrWriter(&.{}); defer std.debug.unlockStderrWriter(); air.write(stderr_bw, pt, liveness); } pub fn dumpInst(air: Air, inst: Air.Inst.Index, pt: Zcu.PerThread, liveness: ?Air.Liveness) void { - const stderr_bw = std.debug.lockStderrWriter(&.{}); + const stderr_bw, _ = std.debug.lockStderrWriter(&.{}); defer std.debug.unlockStderrWriter(); air.writeInst(stderr_bw, inst, pt, liveness); } diff --git a/src/Compilation.zig b/src/Compilation.zig index 3670bc51b5..c72ef32fb5 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -2093,7 +2093,7 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic, if (options.verbose_llvm_cpu_features) { if (options.root_mod.resolved_target.llvm_cpu_features) |cf| print: { - const stderr_w = std.debug.lockStderrWriter(&.{}); + const stderr_w, _ = std.debug.lockStderrWriter(&.{}); defer std.debug.unlockStderrWriter(); stderr_w.print("compilation: {s}\n", .{options.root_name}) catch break :print; stderr_w.print(" target: {s}\n", .{try target.zigTriple(arena)}) catch break :print; @@ -4270,7 +4270,7 @@ pub fn getAllErrorsAlloc(comp: *Compilation) error{OutOfMemory}!ErrorBundle { // However, we haven't reported any such error. // This is a compiler bug. print_ctx: { - var stderr_w = std.debug.lockStderrWriter(&.{}); + var stderr_w, _ = std.debug.lockStderrWriter(&.{}); defer std.debug.unlockStderrWriter(); stderr_w.writeAll("referenced transitive analysis errors, but none actually emitted\n") catch break :print_ctx; stderr_w.print("{f} [transitive failure]\n", .{zcu.fmtAnalUnit(failed_unit)}) catch break :print_ctx; @@ -7752,7 +7752,7 @@ pub fn lockAndSetMiscFailure( pub fn dump_argv(argv: []const []const u8) void { var buffer: [64]u8 = undefined; - const stderr = std.debug.lockStderrWriter(&buffer); + const stderr, _ = std.debug.lockStderrWriter(&buffer); defer std.debug.unlockStderrWriter(); nosuspend { for (argv, 0..) |arg, i| { diff --git a/src/InternPool.zig b/src/InternPool.zig index a595fa502c..2a5436787c 100644 --- a/src/InternPool.zig +++ b/src/InternPool.zig @@ -11330,7 +11330,7 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void { fn dumpAllFallible(ip: *const InternPool) anyerror!void { var buffer: [4096]u8 = undefined; - const stderr_bw = std.debug.lockStderrWriter(&buffer); + const stderr_bw, _ = std.debug.lockStderrWriter(&buffer); defer std.debug.unlockStderrWriter(); for (ip.locals, 0..) |*local, tid| { const items = local.shared.items.view(); @@ -11462,7 +11462,7 @@ pub fn dumpGenericInstancesFallible(ip: *const InternPool, allocator: Allocator) } var buffer: [4096]u8 = undefined; - const stderr_bw = std.debug.lockStderrWriter(&buffer); + const stderr_bw, _ = std.debug.lockStderrWriter(&buffer); defer std.debug.unlockStderrWriter(); const SortContext = struct { diff --git a/src/Package/Fetch.zig b/src/Package/Fetch.zig index 46be6fa069..83d8aa7e5e 100644 --- a/src/Package/Fetch.zig +++ b/src/Package/Fetch.zig @@ -2043,7 +2043,7 @@ const UnpackResult = struct { defer errors.deinit(gpa); var aw: Io.Writer.Allocating = .init(gpa); defer aw.deinit(); - try errors.renderToWriter(.{ .ttyconf = .no_color }, &aw.writer); + try errors.renderToWriter(.{}, &aw.writer, .no_color); try std.testing.expectEqualStrings( \\error: unable to unpack \\ note: unable to create symlink from 'dir2/file2' to 'filename': SymlinkError @@ -2360,7 +2360,7 @@ const TestFetchBuilder = struct { } var aw: Io.Writer.Allocating = .init(std.testing.allocator); defer aw.deinit(); - try errors.renderToWriter(.{ .ttyconf = .no_color }, &aw.writer); + try errors.renderToWriter(.{}, &aw.writer, .no_color); try std.testing.expectEqualStrings(msg, aw.written()); } }; diff --git a/src/Sema.zig b/src/Sema.zig index 341cb1c855..4016041d82 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -2631,7 +2631,7 @@ pub fn failWithOwnedErrorMsg(sema: *Sema, block: ?*Block, err_msg: *Zcu.ErrorMsg Compilation.addModuleErrorMsg(zcu, &wip_errors, err_msg.*, false) catch @panic("out of memory"); std.debug.print("compile error during Sema:\n", .{}); var error_bundle = wip_errors.toOwnedBundle("") catch @panic("out of memory"); - error_bundle.renderToStdErr(.{ .ttyconf = .no_color }); + error_bundle.renderToStdErr(.{}, .auto); std.debug.panicExtra(@returnAddress(), "unexpected compile error occurred", .{}); } diff --git a/src/Zcu/PerThread.zig b/src/Zcu/PerThread.zig index 474ccc710d..20aaa3d3c2 100644 --- a/src/Zcu/PerThread.zig +++ b/src/Zcu/PerThread.zig @@ -4473,7 +4473,7 @@ fn runCodegenInner(pt: Zcu.PerThread, func_index: InternPool.Index, air: *Air) e defer if (liveness) |*l| l.deinit(gpa); if (build_options.enable_debug_extensions and comp.verbose_air) { - const stderr = std.debug.lockStderrWriter(&.{}); + const stderr, _ = std.debug.lockStderrWriter(&.{}); defer std.debug.unlockStderrWriter(); stderr.print("# Begin Function AIR: {f}:\n", .{fqn.fmt(ip)}) catch {}; air.write(stderr, pt, liveness); diff --git a/src/codegen/aarch64/Disassemble.zig b/src/codegen/aarch64/Disassemble.zig index 8aecb8128e..e2d00e3bb3 100644 --- a/src/codegen/aarch64/Disassemble.zig +++ b/src/codegen/aarch64/Disassemble.zig @@ -74,10 +74,10 @@ pub fn printInstruction(dis: Disassemble, inst: aarch64.encoding.Instruction, wr dis.operands_separator, imm12, }); - return if (!elide_shift) writer.print("{s}{f} #{s}", .{ + return if (!elide_shift) writer.print("{s}{f} #{t}", .{ dis.operands_separator, fmtCase(.lsl, dis.case), - @tagName(sh), + sh, }); }, .add_subtract_immediate_with_tags => |add_subtract_immediate_with_tags| { @@ -176,10 +176,10 @@ pub fn printInstruction(dis: Disassemble, inst: aarch64.encoding.Instruction, wr dis.operands_separator, imm16, }); - return if (!elide_shift) writer.print("{s}{f} #{s}", .{ + return if (!elide_shift) writer.print("{s}{f} #{t}", .{ dis.operands_separator, fmtCase(.lsl, dis.case), - @tagName(hw), + hw, }); }, .bitfield => |bitfield| { @@ -833,8 +833,36 @@ pub fn printInstruction(dis: Disassemble, inst: aarch64.encoding.Instruction, wr }, .rotate_right_into_flags => {}, .evaluate_into_flags => {}, - .conditional_compare_register => {}, - .conditional_compare_immediate => {}, + .conditional_compare_register => |conditional_compare_register| { + const group = conditional_compare_register.group; + const sf = group.sf; + return writer.print("{f}{s}{f}{s}{f}{s}#0x{x}{s}{f}", .{ + fmtCase(group.op, dis.case), + dis.mnemonic_operands_separator, + group.Rn.decode(.{}).general(sf).fmtCase(dis.case), + dis.operands_separator, + group.Rm.decode(.{}).general(sf).fmtCase(dis.case), + dis.operands_separator, + @as(u4, @bitCast(group.nzcv)), + dis.operands_separator, + fmtCase(group.cond, dis.case), + }); + }, + .conditional_compare_immediate => |conditional_compare_immediate| { + const group = conditional_compare_immediate.group; + const sf = group.sf; + return writer.print("{f}{s}{f}{s}#0x{x}{s}#0x{x}{s}{f}", .{ + fmtCase(group.op, dis.case), + dis.mnemonic_operands_separator, + group.Rn.decode(.{}).general(sf).fmtCase(dis.case), + dis.operands_separator, + group.imm5, + dis.operands_separator, + @as(u4, @bitCast(group.nzcv)), + dis.operands_separator, + fmtCase(group.cond, dis.case), + }); + }, .conditional_select => |conditional_select| { const decoded = conditional_select.decode(); if (decoded == .unallocated) break :unallocated; diff --git a/src/codegen/aarch64/Mir.zig b/src/codegen/aarch64/Mir.zig index 3e89e28825..d71c410b1d 100644 --- a/src/codegen/aarch64/Mir.zig +++ b/src/codegen/aarch64/Mir.zig @@ -107,6 +107,7 @@ pub fn emit( mir.body[nav_reloc.reloc.label], body_end - Instruction.size * (1 + nav_reloc.reloc.label), nav_reloc.reloc.addend, + if (ip.getNav(nav_reloc.nav).getExtern(ip)) |_| .got_load else .direct, ); for (mir.uav_relocs) |uav_reloc| try emitReloc( lf, @@ -124,6 +125,7 @@ pub fn emit( mir.body[uav_reloc.reloc.label], body_end - Instruction.size * (1 + uav_reloc.reloc.label), uav_reloc.reloc.addend, + .direct, ); for (mir.lazy_relocs) |lazy_reloc| try emitReloc( lf, @@ -136,10 +138,11 @@ pub fn emit( mf.getZigObject().?.getOrCreateMetadataForLazySymbol(mf, pt, lazy_reloc.symbol) catch |err| return zcu.codegenFail(func.owner_nav, "{s} creating lazy symbol", .{@errorName(err)}) else - return zcu.codegenFail(func.owner_nav, "external symbols unimplemented for {s}", .{@tagName(lf.tag)}), + return zcu.codegenFail(func.owner_nav, "external symbols unimplemented for {t}", .{lf.tag}), mir.body[lazy_reloc.reloc.label], body_end - Instruction.size * (1 + lazy_reloc.reloc.label), lazy_reloc.reloc.addend, + .direct, ); for (mir.global_relocs) |global_reloc| try emitReloc( lf, @@ -150,10 +153,11 @@ pub fn emit( else if (lf.cast(.macho)) |mf| try mf.getGlobalSymbol(std.mem.span(global_reloc.name), null) else - return zcu.codegenFail(func.owner_nav, "external symbols unimplemented for {s}", .{@tagName(lf.tag)}), + return zcu.codegenFail(func.owner_nav, "external symbols unimplemented for {t}", .{lf.tag}), mir.body[global_reloc.reloc.label], body_end - Instruction.size * (1 + global_reloc.reloc.label), global_reloc.reloc.addend, + .direct, ); const literal_reloc_offset: i19 = @intCast(mir.epilogue.len + literals_align_gap); for (mir.literal_relocs) |literal_reloc| { @@ -188,6 +192,7 @@ fn emitReloc( instruction: Instruction, offset: u32, addend: u64, + kind: enum { direct, got_load }, ) !void { const gpa = zcu.gpa; switch (instruction.decode()) { @@ -198,11 +203,20 @@ fn emitReloc( const r_type: std.elf.R_AARCH64 = switch (decoded.decode()) { else => unreachable, .pc_relative_addressing => |pc_relative_addressing| switch (pc_relative_addressing.group.op) { - .adr => .ADR_PREL_LO21, - .adrp => .ADR_PREL_PG_HI21, + .adr => switch (kind) { + .direct => .ADR_PREL_LO21, + .got_load => unreachable, + }, + .adrp => switch (kind) { + .direct => .ADR_PREL_PG_HI21, + .got_load => .ADR_GOT_PAGE, + }, }, .add_subtract_immediate => |add_subtract_immediate| switch (add_subtract_immediate.group.op) { - .add => .ADD_ABS_LO12_NC, + .add => switch (kind) { + .direct => .ADD_ABS_LO12_NC, + .got_load => unreachable, + }, .sub => unreachable, }, }; @@ -223,7 +237,10 @@ fn emitReloc( .offset = offset, .target = sym_index, .addend = @bitCast(addend), - .type = .page, + .type = switch (kind) { + .direct => .page, + .got_load => .got_load_page, + }, .meta = .{ .pcrel = true, .has_subtractor = false, @@ -238,7 +255,10 @@ fn emitReloc( .offset = offset, .target = sym_index, .addend = @bitCast(addend), - .type = .pageoff, + .type = switch (kind) { + .direct => .pageoff, + .got_load => .got_load_pageoff, + }, .meta = .{ .pcrel = false, .has_subtractor = false, @@ -285,20 +305,39 @@ fn emitReloc( const r_type: std.elf.R_AARCH64 = switch (decoded.decode().register_unsigned_immediate.decode()) { .integer => |integer| switch (integer.decode()) { .unallocated, .prfm => unreachable, - .strb, .ldrb, .ldrsb => .LDST8_ABS_LO12_NC, - .strh, .ldrh, .ldrsh => .LDST16_ABS_LO12_NC, - .ldrsw => .LDST32_ABS_LO12_NC, - inline .str, .ldr => |encoded| switch (encoded.sf) { + .strb, .ldrb, .ldrsb => switch (kind) { + .direct => .LDST8_ABS_LO12_NC, + .got_load => unreachable, + }, + .strh, .ldrh, .ldrsh => switch (kind) { + .direct => .LDST16_ABS_LO12_NC, + .got_load => unreachable, + }, + .ldrsw => switch (kind) { + .direct => .LDST32_ABS_LO12_NC, + .got_load => unreachable, + }, + inline .str, .ldr => |encoded, mnemonic| switch (encoded.sf) { .word => .LDST32_ABS_LO12_NC, - .doubleword => .LDST64_ABS_LO12_NC, + .doubleword => switch (kind) { + .direct => .LDST64_ABS_LO12_NC, + .got_load => switch (mnemonic) { + else => comptime unreachable, + .str => unreachable, + .ldr => .LD64_GOT_LO12_NC, + }, + }, }, }, - .vector => |vector| switch (vector.group.opc1.decode(vector.group.size)) { - .byte => .LDST8_ABS_LO12_NC, - .half => .LDST16_ABS_LO12_NC, - .single => .LDST32_ABS_LO12_NC, - .double => .LDST64_ABS_LO12_NC, - .quad => .LDST128_ABS_LO12_NC, + .vector => |vector| switch (kind) { + .direct => switch (vector.group.opc1.decode(vector.group.size)) { + .byte => .LDST8_ABS_LO12_NC, + .half => .LDST16_ABS_LO12_NC, + .single => .LDST32_ABS_LO12_NC, + .double => .LDST64_ABS_LO12_NC, + .quad => .LDST128_ABS_LO12_NC, + }, + .got_load => unreachable, }, }; try atom.addReloc(gpa, .{ @@ -314,7 +353,10 @@ fn emitReloc( .offset = offset, .target = sym_index, .addend = @bitCast(addend), - .type = .pageoff, + .type = switch (kind) { + .direct => .pageoff, + .got_load => .got_load_pageoff, + }, .meta = .{ .pcrel = false, .has_subtractor = false, diff --git a/src/codegen/aarch64/Select.zig b/src/codegen/aarch64/Select.zig index 43edde274c..4fe798271f 100644 --- a/src/codegen/aarch64/Select.zig +++ b/src/codegen/aarch64/Select.zig @@ -961,7 +961,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, .inst_index = undefined, }; air_tag: switch (air.next().?) { - else => |air_tag| return isel.fail("unimplemented {s}", .{@tagName(air_tag)}), + else => |air_tag| return isel.fail("unimplemented {t}", .{air_tag}), .arg => { const arg_vi = isel.live_values.fetchRemove(air.inst_index).?.value; defer arg_vi.deref(isel); @@ -1117,12 +1117,12 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, const bin_op = air.data(air.inst_index).bin_op; const ty = isel.air.typeOf(bin_op.lhs, ip); - if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }); + if (!ty.isAbiInt(zcu)) return isel.fail("bad {t} {f}", .{ air_tag, isel.fmtType(ty) }); const int_info = ty.intInfo(zcu); switch (int_info.bits) { 0 => unreachable, 32, 64 => |bits| switch (int_info.signedness) { - .signed => return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }), + .signed => return isel.fail("bad {t} {f}", .{ air_tag, isel.fmtType(ty) }), .unsigned => { const res_ra = try res_vi.value.defReg(isel) orelse break :unused; const lhs_vi = try isel.use(bin_op.lhs); @@ -1160,7 +1160,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, try lhs_mat.finish(isel); }, }, - else => return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }), + else => return isel.fail("too big {t} {f}", .{ air_tag, isel.fmtType(ty) }), } } if (air.next()) |next_air_tag| continue :air_tag next_air_tag; @@ -1172,7 +1172,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, const bin_op = air.data(air.inst_index).bin_op; const ty = isel.air.typeOf(bin_op.lhs, ip); if (!ty.isRuntimeFloat()) { - if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }); + if (!ty.isAbiInt(zcu)) return isel.fail("bad {t} {f}", .{ air_tag, isel.fmtType(ty) }); const int_info = ty.intInfo(zcu); switch (int_info.bits) { 0 => unreachable, @@ -1318,7 +1318,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, try rhs_lo64_mat.finish(isel); try lhs_lo64_mat.finish(isel); }, - else => return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }), + else => return isel.fail("too big {t} {f}", .{ air_tag, isel.fmtType(ty) }), } } else switch (ty.floatBits(isel.target)) { else => unreachable, @@ -1421,7 +1421,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, const bin_op = air.data(air.inst_index).bin_op; const ty = isel.air.typeOf(bin_op.lhs, ip); - if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }); + if (!ty.isAbiInt(zcu)) return isel.fail("bad {t} {f}", .{ air_tag, isel.fmtType(ty) }); const int_info = ty.intInfo(zcu); switch (int_info.signedness) { .signed => switch (int_info.bits) { @@ -1443,7 +1443,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, try rhs_mat.finish(isel); try lhs_mat.finish(isel); }, - else => return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }), + else => return isel.fail("too big {t} {f}", .{ air_tag, isel.fmtType(ty) }), }, .unsigned => switch (int_info.bits) { 0 => unreachable, @@ -1545,8 +1545,8 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, try rhs_mat.finish(isel); try lhs_mat.finish(isel); }, - 65...128 => return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }), - else => return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }), + 65...128 => return isel.fail("bad {t} {f}", .{ air_tag, isel.fmtType(ty) }), + else => return isel.fail("too big {t} {f}", .{ air_tag, isel.fmtType(ty) }), }, } } @@ -1558,7 +1558,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, const bin_op = air.data(air.inst_index).bin_op; const ty = isel.air.typeOf(bin_op.lhs, ip); - if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }); + if (!ty.isAbiInt(zcu)) return isel.fail("bad {t} {f}", .{ air_tag, isel.fmtType(ty) }); const int_info = ty.intInfo(zcu); switch (int_info.bits) { 0 => unreachable, @@ -1784,7 +1784,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, try rhs_mat.finish(isel); try lhs_mat.finish(isel); }, - else => return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }), + else => return isel.fail("too big {t} {f}", .{ air_tag, isel.fmtType(ty) }), } } if (air.next()) |next_air_tag| continue :air_tag next_air_tag; @@ -1897,7 +1897,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, const bin_op = air.data(air.inst_index).bin_op; const ty = isel.air.typeOf(bin_op.lhs, ip); if (!ty.isRuntimeFloat()) { - if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }); + if (!ty.isAbiInt(zcu)) return isel.fail("bad {t} {f}", .{ air_tag, isel.fmtType(ty) }); const int_info = ty.intInfo(zcu); switch (int_info.bits) { 0 => unreachable, @@ -1970,7 +1970,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, else => unreachable, .div_trunc, .div_exact => {}, .div_floor => switch (int_info.signedness) { - .signed => return isel.fail("unimplemented {s}", .{@tagName(air_tag)}), + .signed => return isel.fail("unimplemented {t}", .{air_tag}), .unsigned => {}, }, } @@ -2012,7 +2012,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, try call.paramLiveOut(isel, lhs_lo64_vi.?, .r0); try call.finishParams(isel); }, - else => return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }), + else => return isel.fail("too big {t} {f}", .{ air_tag, isel.fmtType(ty) }), } } else switch (ty.floatBits(isel.target)) { else => unreachable, @@ -2169,9 +2169,9 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, const bin_op = air.data(air.inst_index).bin_op; const ty = isel.air.typeOf(bin_op.lhs, ip); if (!ty.isRuntimeFloat()) { - if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }); + if (!ty.isAbiInt(zcu)) return isel.fail("bad {t} {f}", .{ air_tag, isel.fmtType(ty) }); const int_info = ty.intInfo(zcu); - if (int_info.bits > 64) return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }); + if (int_info.bits > 64) return isel.fail("too big {t} {f}", .{ air_tag, isel.fmtType(ty) }); const res_ra = try res_vi.value.defReg(isel) orelse break :unused; const lhs_vi = try isel.use(bin_op.lhs); @@ -2494,9 +2494,9 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, const bin_op = air.data(air.inst_index).bin_op; const ty = isel.air.typeOf(bin_op.lhs, ip); if (!ty.isRuntimeFloat()) { - if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }); + if (!ty.isAbiInt(zcu)) return isel.fail("bad {t} {f}", .{ air_tag, isel.fmtType(ty) }); const int_info = ty.intInfo(zcu); - if (int_info.bits > 64) return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }); + if (int_info.bits > 64) return isel.fail("too big {t} {f}", .{ air_tag, isel.fmtType(ty) }); const res_ra = try res_vi.value.defReg(isel) orelse break :unused; const lhs_vi = try isel.use(bin_op.lhs); @@ -2920,8 +2920,8 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, else if (ty.isAbiInt(zcu)) ty.intInfo(zcu) else - return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }); - if (int_info.bits > 128) return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }); + return isel.fail("bad {t} {f}", .{ air_tag, isel.fmtType(ty) }); + if (int_info.bits > 128) return isel.fail("too big {t} {f}", .{ air_tag, isel.fmtType(ty) }); const lhs_vi = try isel.use(bin_op.lhs); const rhs_vi = try isel.use(bin_op.rhs); @@ -2968,7 +2968,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, const bin_op = air.data(air.inst_index).bin_op; const ty = isel.air.typeOf(bin_op.lhs, ip); - if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }); + if (!ty.isAbiInt(zcu)) return isel.fail("bad {t} {f}", .{ air_tag, isel.fmtType(ty) }); const int_info = ty.intInfo(zcu); switch (int_info.bits) { 0 => unreachable, @@ -3161,7 +3161,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, try lhs_hi64_mat.finish(isel); break :unused; }, - else => return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }), + else => return isel.fail("too big {t} {f}", .{ air_tag, isel.fmtType(ty) }), } } if (air.next()) |next_air_tag| continue :air_tag next_air_tag; @@ -3174,10 +3174,10 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, const ty = ty_op.ty.toType(); const int_info: std.builtin.Type.Int = int_info: { if (ty_op.ty == .bool_type) break :int_info .{ .signedness = .unsigned, .bits = 1 }; - if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }); + if (!ty.isAbiInt(zcu)) return isel.fail("bad {t} {f}", .{ air_tag, isel.fmtType(ty) }); break :int_info ty.intInfo(zcu); }; - if (int_info.bits > 128) return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }); + if (int_info.bits > 128) return isel.fail("too big {t} {f}", .{ air_tag, isel.fmtType(ty) }); const src_vi = try isel.use(ty_op.operand); var offset = res_vi.value.size(isel); @@ -3302,7 +3302,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, } }, 128 => try dst_vi.value.move(isel, ty_op.operand), - else => return isel.fail("bad {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) }), + else => return isel.fail("bad {t} {f} {f}", .{ air_tag, isel.fmtType(dst_ty), isel.fmtType(src_ty) }), } } else if ((dst_ty.isPtrAtRuntime(zcu) or dst_ty.isAbiInt(zcu)) and (src_ty.isPtrAtRuntime(zcu) or src_ty.isAbiInt(zcu))) { try dst_vi.value.move(isel, ty_op.operand); @@ -3313,7 +3313,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, src_ty.errorUnionSet(zcu).hasRuntimeBitsIgnoreComptime(zcu)); if (dst_ty.errorUnionPayload(zcu).toIntern() == src_ty.errorUnionPayload(zcu).toIntern()) { try dst_vi.value.move(isel, ty_op.operand); - } else return isel.fail("bad {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) }); + } else return isel.fail("bad {t} {f} {f}", .{ air_tag, isel.fmtType(dst_ty), isel.fmtType(src_ty) }); } else if (dst_tag == .float and src_tag == .float) { assert(dst_ty.floatBits(isel.target) == src_ty.floatBits(isel.target)); try dst_vi.value.move(isel, ty_op.operand); @@ -3483,7 +3483,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, try call.paramAddress(isel, src_vi, .r1); try call.paramAddress(isel, dst_vi.value, .r0); try call.finishParams(isel); - } else return isel.fail("bad {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) }); + } else return isel.fail("bad {t} {f} {f}", .{ air_tag, isel.fmtType(dst_ty), isel.fmtType(src_ty) }); } else if (dst_tag == .array and dst_ty.childType(zcu).isAbiInt(zcu) and src_ty.isAbiInt(zcu)) { const dst_child_int_info = dst_ty.childType(zcu).intInfo(zcu); const src_int_info = src_ty.intInfo(zcu); @@ -3510,8 +3510,8 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, try call.paramAddress(isel, src_vi, .r1); try call.paramAddress(isel, dst_vi.value, .r0); try call.finishParams(isel); - } else return isel.fail("bad {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) }); - } else return isel.fail("bad {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) }); + } else return isel.fail("bad {t} {f} {f}", .{ air_tag, isel.fmtType(dst_ty), isel.fmtType(src_ty) }); + } else return isel.fail("bad {t} {f} {f}", .{ air_tag, isel.fmtType(dst_ty), isel.fmtType(src_ty) }); } if (air.next()) |next_air_tag| continue :air_tag next_air_tag; }, @@ -3737,7 +3737,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, const ty_op = air.data(air.inst_index).ty_op; const ty = isel.air.typeOf(ty_op.operand, ip); - if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }); + if (!ty.isAbiInt(zcu)) return isel.fail("bad {t} {f}", .{ air_tag, isel.fmtType(ty) }); const int_info = ty.intInfo(zcu); switch (int_info.bits) { 0 => unreachable, @@ -3769,7 +3769,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, try src_hi64_mat.finish(isel); try src_lo64_mat.finish(isel); }, - else => return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }), + else => return isel.fail("too big {t} {f}", .{ air_tag, isel.fmtType(ty) }), } } if (air.next()) |next_air_tag| continue :air_tag next_air_tag; @@ -3780,7 +3780,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, const ty_op = air.data(air.inst_index).ty_op; const ty = isel.air.typeOf(ty_op.operand, ip); - if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }); + if (!ty.isAbiInt(zcu)) return isel.fail("bad {t} {f}", .{ air_tag, isel.fmtType(ty) }); const int_info = ty.intInfo(zcu); switch (int_info.bits) { 0 => unreachable, @@ -3812,7 +3812,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, try src_hi64_mat.finish(isel); try src_lo64_mat.finish(isel); }, - else => return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }), + else => return isel.fail("too big {t} {f}", .{ air_tag, isel.fmtType(ty) }), } } if (air.next()) |next_air_tag| continue :air_tag next_air_tag; @@ -3823,9 +3823,9 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, const ty_op = air.data(air.inst_index).ty_op; const ty = isel.air.typeOf(ty_op.operand, ip); - if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }); + if (!ty.isAbiInt(zcu)) return isel.fail("bad {t} {f}", .{ air_tag, isel.fmtType(ty) }); const int_info = ty.intInfo(zcu); - if (int_info.bits > 64) return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }); + if (int_info.bits > 64) return isel.fail("too big {t} {f}", .{ air_tag, isel.fmtType(ty) }); const res_ra = try res_vi.value.defReg(isel) orelse break :unused; const src_vi = try isel.use(ty_op.operand); @@ -3877,9 +3877,9 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, const ty_op = air.data(air.inst_index).ty_op; const ty = ty_op.ty.toType(); - if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }); + if (!ty.isAbiInt(zcu)) return isel.fail("bad {t} {f}", .{ air_tag, isel.fmtType(ty) }); const int_info = ty.intInfo(zcu); - if (int_info.bits > 64) return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }); + if (int_info.bits > 64) return isel.fail("too big {t} {f}", .{ air_tag, isel.fmtType(ty) }); if (int_info.bits == 8) break :unused try res_vi.value.move(isel, ty_op.operand); const res_ra = try res_vi.value.defReg(isel) orelse break :unused; @@ -3941,9 +3941,9 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, const ty_op = air.data(air.inst_index).ty_op; const ty = ty_op.ty.toType(); - if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }); + if (!ty.isAbiInt(zcu)) return isel.fail("bad {t} {f}", .{ air_tag, isel.fmtType(ty) }); const int_info = ty.intInfo(zcu); - if (int_info.bits > 64) return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }); + if (int_info.bits > 64) return isel.fail("too big {t} {f}", .{ air_tag, isel.fmtType(ty) }); const res_ra = try res_vi.value.defReg(isel) orelse break :unused; const src_vi = try isel.use(ty_op.operand); @@ -4244,7 +4244,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, const ty_op = air.data(air.inst_index).ty_op; const ty = ty_op.ty.toType(); if (!ty.isRuntimeFloat()) { - if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }); + if (!ty.isAbiInt(zcu)) return isel.fail("bad {t} {f}", .{ air_tag, isel.fmtType(ty) }); switch (ty.intInfo(zcu).bits) { 0 => unreachable, 1...32 => { @@ -4306,7 +4306,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, try src_lo64_mat.finish(isel); try src_hi64_mat.finish(isel); }, - else => return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }), + else => return isel.fail("too big {t} {f}", .{ air_tag, isel.fmtType(ty) }), } } else switch (ty.floatBits(isel.target)) { else => unreachable, @@ -4465,216 +4465,61 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: { defer res_vi.value.deref(isel); - var bin_op = air.data(air.inst_index).bin_op; + const bin_op = air.data(air.inst_index).bin_op; const ty = isel.air.typeOf(bin_op.lhs, ip); - if (!ty.isRuntimeFloat()) { - const int_info: std.builtin.Type.Int = if (ty.toIntern() == .bool_type) - .{ .signedness = .unsigned, .bits = 1 } - else if (ty.isAbiInt(zcu)) - ty.intInfo(zcu) - else if (ty.isPtrAtRuntime(zcu)) - .{ .signedness = .unsigned, .bits = 64 } - else - return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }); - if (int_info.bits > 256) return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }); - - const res_ra = try res_vi.value.defReg(isel) orelse break :unused; - try isel.emit(.csinc(res_ra.w(), .wzr, .wzr, .invert(cond: switch (air_tag) { + switch (ip.indexToKey(ty.toIntern())) { + else => {}, + .opt_type => |payload_ty| switch (air_tag) { else => unreachable, - .cmp_lt => switch (int_info.signedness) { - .signed => .lt, - .unsigned => .lo, + .cmp_eq, .cmp_neq => if (!ty.optionalReprIsPayload(zcu)) { + const lhs_vi = try isel.use(bin_op.lhs); + const rhs_vi = try isel.use(bin_op.rhs); + const payload_size = ZigType.abiSize(.fromInterned(payload_ty), zcu); + var lhs_payload_part_it = lhs_vi.field(ty, 0, payload_size); + const lhs_payload_part_vi = try lhs_payload_part_it.only(isel); + var rhs_payload_part_it = rhs_vi.field(ty, 0, payload_size); + const rhs_payload_part_vi = try rhs_payload_part_it.only(isel); + const cmp_info = try isel.cmp( + try res_vi.value.defReg(isel) orelse break :unused, + .fromInterned(payload_ty), + lhs_payload_part_vi.?, + air_tag.toCmpOp().?, + rhs_payload_part_vi.?, + ); + try isel.emit(.@"b."( + .vc, + @intCast((isel.instructions.items.len + 1 - cmp_info.cset_label) << 2), + )); + var lhs_has_value_part_it = lhs_vi.field(ty, payload_size, 1); + const lhs_has_value_part_vi = try lhs_has_value_part_it.only(isel); + const lhs_has_value_part_mat = try lhs_has_value_part_vi.?.matReg(isel); + var rhs_has_value_part_it = rhs_vi.field(ty, payload_size, 1); + const rhs_has_value_part_vi = try rhs_has_value_part_it.only(isel); + const rhs_has_value_part_mat = try rhs_has_value_part_vi.?.matReg(isel); + try isel.emit(.ccmp( + lhs_has_value_part_mat.ra.w(), + .{ .register = rhs_has_value_part_mat.ra.w() }, + .{ .n = false, .z = false, .c = false, .v = true }, + .eq, + )); + try isel.emit(.ands( + .wzr, + lhs_has_value_part_mat.ra.w(), + .{ .register = rhs_has_value_part_mat.ra.w() }, + )); + try rhs_has_value_part_mat.finish(isel); + try lhs_has_value_part_mat.finish(isel); + break :unused; }, - .cmp_lte => switch (int_info.bits) { - else => unreachable, - 1...64 => switch (int_info.signedness) { - .signed => .le, - .unsigned => .ls, - }, - 65...128 => { - std.mem.swap(Air.Inst.Ref, &bin_op.lhs, &bin_op.rhs); - continue :cond .cmp_gte; - }, - }, - .cmp_eq => .eq, - .cmp_gte => switch (int_info.signedness) { - .signed => .ge, - .unsigned => .hs, - }, - .cmp_gt => switch (int_info.bits) { - else => unreachable, - 1...64 => switch (int_info.signedness) { - .signed => .gt, - .unsigned => .hi, - }, - 65...128 => { - std.mem.swap(Air.Inst.Ref, &bin_op.lhs, &bin_op.rhs); - continue :cond .cmp_lt; - }, - }, - .cmp_neq => .ne, - }))); - - const lhs_vi = try isel.use(bin_op.lhs); - const rhs_vi = try isel.use(bin_op.rhs); - var part_offset = lhs_vi.size(isel); - while (part_offset > 0) { - const part_size = @min(part_offset, 8); - part_offset -= part_size; - var lhs_part_it = lhs_vi.field(ty, part_offset, part_size); - const lhs_part_vi = try lhs_part_it.only(isel); - const lhs_part_mat = try lhs_part_vi.?.matReg(isel); - var rhs_part_it = rhs_vi.field(ty, part_offset, part_size); - const rhs_part_vi = try rhs_part_it.only(isel); - const rhs_part_mat = try rhs_part_vi.?.matReg(isel); - try isel.emit(switch (part_size) { - else => unreachable, - 1...4 => switch (part_offset) { - 0 => .subs(.wzr, lhs_part_mat.ra.w(), .{ .register = rhs_part_mat.ra.w() }), - else => switch (air_tag) { - else => unreachable, - .cmp_lt, .cmp_lte, .cmp_gte, .cmp_gt => .sbcs( - .wzr, - lhs_part_mat.ra.w(), - rhs_part_mat.ra.w(), - ), - .cmp_eq, .cmp_neq => .ccmp( - lhs_part_mat.ra.w(), - .{ .register = rhs_part_mat.ra.w() }, - .{ .n = false, .z = false, .c = false, .v = false }, - .eq, - ), - }, - }, - 5...8 => switch (part_offset) { - 0 => .subs(.xzr, lhs_part_mat.ra.x(), .{ .register = rhs_part_mat.ra.x() }), - else => switch (air_tag) { - else => unreachable, - .cmp_lt, .cmp_lte, .cmp_gte, .cmp_gt => .sbcs( - .xzr, - lhs_part_mat.ra.x(), - rhs_part_mat.ra.x(), - ), - .cmp_eq, .cmp_neq => .ccmp( - lhs_part_mat.ra.x(), - .{ .register = rhs_part_mat.ra.x() }, - .{ .n = false, .z = false, .c = false, .v = false }, - .eq, - ), - }, - }, - }); - try rhs_part_mat.finish(isel); - try lhs_part_mat.finish(isel); - } - } else switch (ty.floatBits(isel.target)) { - else => unreachable, - 16, 32, 64 => |bits| { - const res_ra = try res_vi.value.defReg(isel) orelse break :unused; - const need_fcvt = switch (bits) { - else => unreachable, - 16 => !isel.target.cpu.has(.aarch64, .fullfp16), - 32, 64 => false, - }; - try isel.emit(.csinc(res_ra.w(), .wzr, .wzr, .invert(switch (air_tag) { - else => unreachable, - .cmp_lt => .lo, - .cmp_lte => .ls, - .cmp_eq => .eq, - .cmp_gte => .ge, - .cmp_gt => .gt, - .cmp_neq => .ne, - }))); - - const lhs_vi = try isel.use(bin_op.lhs); - const rhs_vi = try isel.use(bin_op.rhs); - const lhs_mat = try lhs_vi.matReg(isel); - const rhs_mat = try rhs_vi.matReg(isel); - const lhs_ra = if (need_fcvt) try isel.allocVecReg() else lhs_mat.ra; - defer if (need_fcvt) isel.freeReg(lhs_ra); - const rhs_ra = if (need_fcvt) try isel.allocVecReg() else rhs_mat.ra; - defer if (need_fcvt) isel.freeReg(rhs_ra); - try isel.emit(bits: switch (bits) { - else => unreachable, - 16 => if (need_fcvt) - continue :bits 32 - else - .fcmp(lhs_ra.h(), .{ .register = rhs_ra.h() }), - 32 => .fcmp(lhs_ra.s(), .{ .register = rhs_ra.s() }), - 64 => .fcmp(lhs_ra.d(), .{ .register = rhs_ra.d() }), - }); - if (need_fcvt) { - try isel.emit(.fcvt(rhs_ra.s(), rhs_mat.ra.h())); - try isel.emit(.fcvt(lhs_ra.s(), lhs_mat.ra.h())); - } - try rhs_mat.finish(isel); - try lhs_mat.finish(isel); - }, - 80, 128 => |bits| { - const res_ra = try res_vi.value.defReg(isel) orelse break :unused; - - try call.prepareReturn(isel); - try call.returnFill(isel, .r0); - try isel.emit(.csinc(res_ra.w(), .wzr, .wzr, .invert(cond: switch (air_tag) { - else => unreachable, - .cmp_lt => .lt, - .cmp_lte => .le, - .cmp_eq => .eq, - .cmp_gte => { - std.mem.swap(Air.Inst.Ref, &bin_op.lhs, &bin_op.rhs); - continue :cond .cmp_lte; - }, - .cmp_gt => { - std.mem.swap(Air.Inst.Ref, &bin_op.lhs, &bin_op.rhs); - continue :cond .cmp_lt; - }, - .cmp_neq => .ne, - }))); - try isel.emit(.subs(.wzr, .w0, .{ .immediate = 0 })); - try call.finishReturn(isel); - - try call.prepareCallee(isel); - try isel.global_relocs.append(gpa, .{ - .name = switch (bits) { - else => unreachable, - 16 => "__cmphf2", - 32 => "__cmpsf2", - 64 => "__cmpdf2", - 80 => "__cmpxf2", - 128 => "__cmptf2", - }, - .reloc = .{ .label = @intCast(isel.instructions.items.len) }, - }); - try isel.emit(.bl(0)); - try call.finishCallee(isel); - - try call.prepareParams(isel); - const lhs_vi = try isel.use(bin_op.lhs); - const rhs_vi = try isel.use(bin_op.rhs); - switch (bits) { - else => unreachable, - 16, 32, 64, 128 => { - try call.paramLiveOut(isel, rhs_vi, .v1); - try call.paramLiveOut(isel, lhs_vi, .v0); - }, - 80 => { - var rhs_hi16_it = rhs_vi.field(ty, 8, 8); - const rhs_hi16_vi = try rhs_hi16_it.only(isel); - try call.paramLiveOut(isel, rhs_hi16_vi.?, .r3); - var rhs_lo64_it = rhs_vi.field(ty, 0, 8); - const rhs_lo64_vi = try rhs_lo64_it.only(isel); - try call.paramLiveOut(isel, rhs_lo64_vi.?, .r2); - var lhs_hi16_it = lhs_vi.field(ty, 8, 8); - const lhs_hi16_vi = try lhs_hi16_it.only(isel); - try call.paramLiveOut(isel, lhs_hi16_vi.?, .r1); - var lhs_lo64_it = lhs_vi.field(ty, 0, 8); - const lhs_lo64_vi = try lhs_lo64_it.only(isel); - try call.paramLiveOut(isel, lhs_lo64_vi.?, .r0); - }, - } - try call.finishParams(isel); }, } + _ = try isel.cmp( + try res_vi.value.defReg(isel) orelse break :unused, + ty, + try isel.use(bin_op.lhs), + air_tag.toCmpOp().?, + try isel.use(bin_op.rhs), + ); } if (air.next()) |next_air_tag| continue :air_tag next_air_tag; }, @@ -5497,7 +5342,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, try src_mat.finish(isel); }, }; - } else return isel.fail("too big {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) }); + } else return isel.fail("too big {t} {f} {f}", .{ air_tag, isel.fmtType(dst_ty), isel.fmtType(src_ty) }); } if (air.next()) |next_air_tag| continue :air_tag next_air_tag; }, @@ -5517,7 +5362,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, .int => .integer_out_of_bounds, .@"enum" => { if (!dst_ty.isNonexhaustiveEnum(zcu)) { - return isel.fail("bad {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) }); + return isel.fail("bad {t} {f} {f}", .{ air_tag, isel.fmtType(dst_ty), isel.fmtType(src_ty) }); } break :panic_id .invalid_enum_value; }, @@ -5599,7 +5444,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, try src_mat.finish(isel); } } - } else return isel.fail("too big {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) }); + } else return isel.fail("too big {t} {f} {f}", .{ air_tag, isel.fmtType(dst_ty), isel.fmtType(src_ty) }); } if (air.next()) |next_air_tag| continue :air_tag next_air_tag; }, @@ -5610,7 +5455,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, const ty_op = air.data(air.inst_index).ty_op; const dst_ty = ty_op.ty.toType(); const src_ty = isel.air.typeOf(ty_op.operand, ip); - if (!dst_ty.isAbiInt(zcu) or !src_ty.isAbiInt(zcu)) return isel.fail("bad {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) }); + if (!dst_ty.isAbiInt(zcu) or !src_ty.isAbiInt(zcu)) return isel.fail("bad {t} {f} {f}", .{ air_tag, isel.fmtType(dst_ty), isel.fmtType(src_ty) }); const dst_int_info = dst_ty.intInfo(zcu); switch (dst_int_info.bits) { 0 => unreachable, @@ -5683,9 +5528,9 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, try src_lo64_vi.?.liveOut(isel, dst_lo64_ra); } }, - else => return isel.fail("too big {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) }), + else => return isel.fail("too big {t} {f} {f}", .{ air_tag, isel.fmtType(dst_ty), isel.fmtType(src_ty) }), }, - else => return isel.fail("too big {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) }), + else => return isel.fail("too big {t} {f} {f}", .{ air_tag, isel.fmtType(dst_ty), isel.fmtType(src_ty) }), } } if (air.next()) |next_air_tag| continue :air_tag next_air_tag; @@ -6487,7 +6332,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, const ty_op = air.data(air.inst_index).ty_op; const dst_ty = ty_op.ty.toType(); const src_ty = isel.air.typeOf(ty_op.operand, ip); - if (!dst_ty.isAbiInt(zcu)) return isel.fail("bad {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) }); + if (!dst_ty.isAbiInt(zcu)) return isel.fail("bad {t} {f} {f}", .{ air_tag, isel.fmtType(dst_ty), isel.fmtType(src_ty) }); const dst_int_info = dst_ty.intInfo(zcu); const src_bits = src_ty.floatBits(isel.target); switch (@max(dst_int_info.bits, src_bits)) { @@ -6617,7 +6462,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, } try call.finishParams(isel); }, - else => return isel.fail("too big {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) }), + else => return isel.fail("too big {t} {f} {f}", .{ air_tag, isel.fmtType(dst_ty), isel.fmtType(src_ty) }), } } if (air.next()) |next_air_tag| continue :air_tag next_air_tag; @@ -6630,7 +6475,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, const dst_ty = ty_op.ty.toType(); const src_ty = isel.air.typeOf(ty_op.operand, ip); const dst_bits = dst_ty.floatBits(isel.target); - if (!src_ty.isAbiInt(zcu)) return isel.fail("bad {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) }); + if (!src_ty.isAbiInt(zcu)) return isel.fail("bad {t} {f} {f}", .{ air_tag, isel.fmtType(dst_ty), isel.fmtType(src_ty) }); const src_int_info = src_ty.intInfo(zcu); switch (@max(dst_bits, src_int_info.bits)) { 0 => unreachable, @@ -6757,7 +6602,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, } try call.finishParams(isel); }, - else => return isel.fail("too big {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) }), + else => return isel.fail("too big {t} {f} {f}", .{ air_tag, isel.fmtType(dst_ty), isel.fmtType(src_ty) }), } } if (air.next()) |next_air_tag| continue :air_tag next_air_tag; @@ -6836,7 +6681,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, break :air_tag if (air.next()) |next_air_tag| continue :air_tag next_air_tag; }, - else => return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty) }), + else => return isel.fail("too big {t} {f}", .{ air_tag, isel.fmtType(dst_ty) }), } }; @@ -7157,7 +7002,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, else => unreachable, }, }), - else => return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(union_ty) }), + else => return isel.fail("too big {t} {f}", .{ air_tag, isel.fmtType(union_ty) }), } } var payload_it = union_vi.value.field(union_ty, union_layout.payloadOffset(), union_layout.payload_size); @@ -7412,7 +7257,10 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, .nav = ty_nav.nav, .reloc = .{ .label = @intCast(isel.instructions.items.len) }, }); - try isel.emit(.add(ptr_ra.x(), ptr_ra.x(), .{ .immediate = 0 })); + if (ip.getNav(ty_nav.nav).getExtern(ip)) |_| + try isel.emit(.ldr(ptr_ra.x(), .{ .unsigned_offset = .{ .base = ptr_ra.x(), .offset = 0 } })) + else + try isel.emit(.add(ptr_ra.x(), ptr_ra.x(), .{ .immediate = 0 })); try isel.nav_relocs.append(gpa, .{ .nav = ty_nav.nav, .reloc = .{ .label = @intCast(isel.instructions.items.len) }, @@ -8499,6 +8347,217 @@ fn ctzLimb( } } +fn cmp( + isel: *Select, + res_ra: Register.Alias, + ty: ZigType, + orig_lhs_vi: Value.Index, + op: std.math.CompareOperator, + orig_rhs_vi: Value.Index, +) !struct { cset_label: usize } { + var lhs_vi = orig_lhs_vi; + var rhs_vi = orig_rhs_vi; + if (!ty.isRuntimeFloat()) { + const int_info: std.builtin.Type.Int = if (ty.toIntern() == .bool_type) + .{ .signedness = .unsigned, .bits = 1 } + else if (ty.isAbiInt(isel.pt.zcu)) + ty.intInfo(isel.pt.zcu) + else if (ty.isPtrAtRuntime(isel.pt.zcu)) + .{ .signedness = .unsigned, .bits = 64 } + else + return isel.fail("bad cmp_{t} {f}", .{ op, isel.fmtType(ty) }); + if (int_info.bits > 256) return isel.fail("too big cmp_{t} {f}", .{ op, isel.fmtType(ty) }); + try isel.emit(.csinc(res_ra.w(), .wzr, .wzr, .invert(cond: switch (op) { + .lt => switch (int_info.signedness) { + .signed => .lt, + .unsigned => .lo, + }, + .lte => switch (int_info.bits) { + else => unreachable, + 1...64 => switch (int_info.signedness) { + .signed => .le, + .unsigned => .ls, + }, + 65...128 => { + std.mem.swap(Value.Index, &lhs_vi, &rhs_vi); + continue :cond .gte; + }, + }, + .eq => .eq, + .gte => switch (int_info.signedness) { + .signed => .ge, + .unsigned => .hs, + }, + .gt => switch (int_info.bits) { + else => unreachable, + 1...64 => switch (int_info.signedness) { + .signed => .gt, + .unsigned => .hi, + }, + 65...128 => { + std.mem.swap(Value.Index, &lhs_vi, &rhs_vi); + continue :cond .lt; + }, + }, + .neq => .ne, + }))); + const cset_label = isel.instructions.items.len; + + var part_offset = lhs_vi.size(isel); + while (part_offset > 0) { + const part_size = @min(part_offset, 8); + part_offset -= part_size; + var lhs_part_it = lhs_vi.field(ty, part_offset, part_size); + const lhs_part_vi = try lhs_part_it.only(isel); + const lhs_part_mat = try lhs_part_vi.?.matReg(isel); + var rhs_part_it = rhs_vi.field(ty, part_offset, part_size); + const rhs_part_vi = try rhs_part_it.only(isel); + const rhs_part_mat = try rhs_part_vi.?.matReg(isel); + try isel.emit(switch (part_size) { + else => unreachable, + 1...4 => switch (part_offset) { + 0 => .subs(.wzr, lhs_part_mat.ra.w(), .{ .register = rhs_part_mat.ra.w() }), + else => switch (op) { + .lt, .lte, .gte, .gt => .sbcs( + .wzr, + lhs_part_mat.ra.w(), + rhs_part_mat.ra.w(), + ), + .eq, .neq => .ccmp( + lhs_part_mat.ra.w(), + .{ .register = rhs_part_mat.ra.w() }, + .{ .n = false, .z = false, .c = false, .v = false }, + .eq, + ), + }, + }, + 5...8 => switch (part_offset) { + 0 => .subs(.xzr, lhs_part_mat.ra.x(), .{ .register = rhs_part_mat.ra.x() }), + else => switch (op) { + .lt, .lte, .gte, .gt => .sbcs( + .xzr, + lhs_part_mat.ra.x(), + rhs_part_mat.ra.x(), + ), + .eq, .neq => .ccmp( + lhs_part_mat.ra.x(), + .{ .register = rhs_part_mat.ra.x() }, + .{ .n = false, .z = false, .c = false, .v = false }, + .eq, + ), + }, + }, + }); + try rhs_part_mat.finish(isel); + try lhs_part_mat.finish(isel); + } + return .{ .cset_label = cset_label }; + } + switch (ty.floatBits(isel.target)) { + else => unreachable, + 16, 32, 64 => |bits| { + const need_fcvt = switch (bits) { + else => unreachable, + 16 => !isel.target.cpu.has(.aarch64, .fullfp16), + 32, 64 => false, + }; + try isel.emit(.csinc(res_ra.w(), .wzr, .wzr, .invert(switch (op) { + .lt => .lo, + .lte => .ls, + .eq => .eq, + .gte => .ge, + .gt => .gt, + .neq => .ne, + }))); + const cset_label = isel.instructions.items.len; + + const lhs_mat = try lhs_vi.matReg(isel); + const rhs_mat = try rhs_vi.matReg(isel); + const lhs_ra = if (need_fcvt) try isel.allocVecReg() else lhs_mat.ra; + defer if (need_fcvt) isel.freeReg(lhs_ra); + const rhs_ra = if (need_fcvt) try isel.allocVecReg() else rhs_mat.ra; + defer if (need_fcvt) isel.freeReg(rhs_ra); + try isel.emit(bits: switch (bits) { + else => unreachable, + 16 => if (need_fcvt) + continue :bits 32 + else + .fcmp(lhs_ra.h(), .{ .register = rhs_ra.h() }), + 32 => .fcmp(lhs_ra.s(), .{ .register = rhs_ra.s() }), + 64 => .fcmp(lhs_ra.d(), .{ .register = rhs_ra.d() }), + }); + if (need_fcvt) { + try isel.emit(.fcvt(rhs_ra.s(), rhs_mat.ra.h())); + try isel.emit(.fcvt(lhs_ra.s(), lhs_mat.ra.h())); + } + try rhs_mat.finish(isel); + try lhs_mat.finish(isel); + return .{ .cset_label = cset_label }; + }, + 80, 128 => |bits| { + try call.prepareReturn(isel); + try call.returnFill(isel, .r0); + try isel.emit(.csinc(res_ra.w(), .wzr, .wzr, .invert(cond: switch (op) { + .lt => .lt, + .lte => .le, + .eq => .eq, + .gte => { + std.mem.swap(Value.Index, &lhs_vi, &rhs_vi); + continue :cond .lte; + }, + .gt => { + std.mem.swap(Value.Index, &lhs_vi, &rhs_vi); + continue :cond .lt; + }, + .neq => .ne, + }))); + const cset_label = isel.instructions.items.len; + try isel.emit(.subs(.wzr, .w0, .{ .immediate = 0 })); + try call.finishReturn(isel); + + try call.prepareCallee(isel); + try isel.global_relocs.append(isel.pt.zcu.gpa, .{ + .name = switch (bits) { + else => unreachable, + 16 => "__cmphf2", + 32 => "__cmpsf2", + 64 => "__cmpdf2", + 80 => "__cmpxf2", + 128 => "__cmptf2", + }, + .reloc = .{ .label = @intCast(isel.instructions.items.len) }, + }); + try isel.emit(.bl(0)); + try call.finishCallee(isel); + + try call.prepareParams(isel); + switch (bits) { + else => unreachable, + 16, 32, 64, 128 => { + try call.paramLiveOut(isel, rhs_vi, .v1); + try call.paramLiveOut(isel, lhs_vi, .v0); + }, + 80 => { + var rhs_hi16_it = rhs_vi.field(ty, 8, 8); + const rhs_hi16_vi = try rhs_hi16_it.only(isel); + try call.paramLiveOut(isel, rhs_hi16_vi.?, .r3); + var rhs_lo64_it = rhs_vi.field(ty, 0, 8); + const rhs_lo64_vi = try rhs_lo64_it.only(isel); + try call.paramLiveOut(isel, rhs_lo64_vi.?, .r2); + var lhs_hi16_it = lhs_vi.field(ty, 8, 8); + const lhs_hi16_vi = try lhs_hi16_it.only(isel); + try call.paramLiveOut(isel, lhs_hi16_vi.?, .r1); + var lhs_lo64_it = lhs_vi.field(ty, 0, 8); + const lhs_lo64_vi = try lhs_lo64_it.only(isel); + try call.paramLiveOut(isel, lhs_lo64_vi.?, .r0); + }, + } + try call.finishParams(isel); + return .{ .cset_label = cset_label }; + }, + } +} + fn loadReg( isel: *Select, ra: Register.Alias, @@ -9272,9 +9331,9 @@ pub const Value = struct { opts: AddOrSubtractOptions, ) !void { const zcu = isel.pt.zcu; - if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(op), isel.fmtType(ty) }); + if (!ty.isAbiInt(zcu)) return isel.fail("bad {t} {f}", .{ op, isel.fmtType(ty) }); const int_info = ty.intInfo(zcu); - if (int_info.bits > 128) return isel.fail("too big {s} {f}", .{ @tagName(op), isel.fmtType(ty) }); + if (int_info.bits > 128) return isel.fail("too big {t} {f}", .{ op, isel.fmtType(ty) }); var part_offset = res_vi.size(isel); var need_wrap = switch (opts.overflow) { .@"unreachable" => false, @@ -10783,7 +10842,7 @@ pub const Value = struct { .err_name => continue :constant_key .{ .undef = error_union_type.payload_type }, .payload => |payload| { constant = payload; - constant_key = ip.indexToKey(payload); + constant_key = ip.indexToKey(constant); continue :constant_key constant_key; }, } @@ -10915,7 +10974,10 @@ pub const Value = struct { .addend = ptr.byte_offset, }, }); - try isel.emit(.add(mat.ra.x(), mat.ra.x(), .{ .immediate = 0 })); + if (ip.getNav(nav).getExtern(ip)) |_| + try isel.emit(.ldr(mat.ra.x(), .{ .unsigned_offset = .{ .base = mat.ra.x(), .offset = 0 } })) + else + try isel.emit(.add(mat.ra.x(), mat.ra.x(), .{ .immediate = 0 })); try isel.nav_relocs.append(zcu.gpa, .{ .nav = nav, .reloc = .{ @@ -11017,7 +11079,7 @@ pub const Value = struct { } } else .{ .undef = child_ty }, else => |child| { constant = child; - constant_key = ip.indexToKey(child); + constant_key = ip.indexToKey(constant); continue :constant_key constant_key; }, }; @@ -11040,7 +11102,7 @@ pub const Value = struct { }, .repeated_elem => |repeated_elem| { constant = repeated_elem; - constant_key = ip.indexToKey(repeated_elem); + constant_key = ip.indexToKey(constant); continue :constant_key constant_key; }, }; @@ -11099,6 +11161,28 @@ pub const Value = struct { } }, }, + .un => |un| { + const loaded_union = ip.loadUnionType(un.ty); + const union_layout = ZigType.getUnionLayout(loaded_union, zcu); + if (loaded_union.hasTag(ip)) { + const tag_offset = union_layout.tagOffset(); + if (offset >= tag_offset and offset + size <= tag_offset + union_layout.tag_size) { + offset -= tag_offset; + continue :constant_key switch (ip.indexToKey(un.tag)) { + else => unreachable, + .int => |int| .{ .int = int }, + .enum_tag => |enum_tag| .{ .enum_tag = enum_tag }, + }; + } + } + const payload_offset = union_layout.payloadOffset(); + if (offset >= payload_offset and offset + size <= payload_offset + union_layout.payload_size) { + offset -= payload_offset; + constant = un.val; + constant_key = ip.indexToKey(constant); + continue :constant_key constant_key; + } + }, else => {}, } var buffer: [16]u8 = @splat(0); @@ -11188,7 +11272,7 @@ fn initValueAdvanced( } pub fn dumpValues(isel: *Select, which: enum { only_referenced, all }) void { errdefer |err| @panic(@errorName(err)); - const stderr = std.debug.lockStderrWriter(&.{}); + const stderr, _ = std.debug.lockStderrWriter(&.{}); defer std.debug.unlockStderrWriter(); const zcu = isel.pt.zcu; @@ -11259,7 +11343,7 @@ pub fn dumpValues(isel: *Select, which: enum { only_referenced, all }) void { first = false; }; if (reverse_live_registers.get(vi)) |ra| { - try stderr.print("{s}{s}", .{ if (first) " <- " else ", ", @tagName(ra) }); + try stderr.print("{s}{t}", .{ if (first) " <- " else ", ", ra }); first = false; } } @@ -11267,8 +11351,8 @@ pub fn dumpValues(isel: *Select, which: enum { only_referenced, all }) void { switch (value.flags.parent_tag) { .unallocated => if (value.offset_from_parent != 0) try stderr.print(" +0x{x}", .{value.offset_from_parent}), .stack_slot => { - try stderr.print(" [{s}, #{s}0x{x}", .{ - @tagName(value.parent_payload.stack_slot.base), + try stderr.print(" [{t}, #{s}0x{x}", .{ + value.parent_payload.stack_slot.base, if (value.parent_payload.stack_slot.offset < 0) "-" else "", @abs(value.parent_payload.stack_slot.offset), }); @@ -11282,7 +11366,7 @@ pub fn dumpValues(isel: *Select, which: enum { only_referenced, all }) void { isel.fmtConstant(value.parent_payload.constant), }), } - try stderr.print(" align({s})", .{@tagName(value.flags.alignment)}); + try stderr.print(" align({t})", .{value.flags.alignment}); switch (value.flags.location_tag) { .large => try stderr.print(" size=0x{x} large", .{value.location_payload.large.size}), .small => { @@ -11292,8 +11376,8 @@ pub fn dumpValues(isel: *Select, which: enum { only_referenced, all }) void { .unsigned => {}, .signed => try stderr.writeAll(" signed"), } - if (loc.hint != .zr) try stderr.print(" hint={s}", .{@tagName(loc.hint)}); - if (loc.register != .zr) try stderr.print(" loc={s}", .{@tagName(loc.register)}); + if (loc.hint != .zr) try stderr.print(" hint={t}", .{loc.hint}); + if (loc.register != .zr) try stderr.print(" loc={t}", .{loc.register}); }, } try stderr.print(" refs={d}\n", .{value.refs}); diff --git a/src/crash_report.zig b/src/crash_report.zig index b051752c7a..d525d4b3b5 100644 --- a/src/crash_report.zig +++ b/src/crash_report.zig @@ -95,7 +95,7 @@ fn dumpCrashContext() Io.Writer.Error!void { // TODO: this does mean that a different thread could grab the stderr mutex between the context // and the actual panic printing, which would be quite confusing. - const stderr = std.debug.lockStderrWriter(&.{}); + const stderr, _ = std.debug.lockStderrWriter(&.{}); defer std.debug.unlockStderrWriter(); try stderr.writeAll("Compiler crash context:\n"); diff --git a/src/fmt.zig b/src/fmt.zig index 344a89d6ed..80925200d6 100644 --- a/src/fmt.zig +++ b/src/fmt.zig @@ -124,7 +124,7 @@ pub fn run(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8) ! try wip_errors.addZirErrorMessages(zir, tree, source_code, ""); var error_bundle = try wip_errors.toOwnedBundle(""); defer error_bundle.deinit(gpa); - error_bundle.renderToStdErr(color.renderOptions()); + error_bundle.renderToStdErr(.{}, color); process.exit(2); } } else { @@ -138,7 +138,7 @@ pub fn run(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8) ! try wip_errors.addZoirErrorMessages(zoir, tree, source_code, ""); var error_bundle = try wip_errors.toOwnedBundle(""); defer error_bundle.deinit(gpa); - error_bundle.renderToStdErr(color.renderOptions()); + error_bundle.renderToStdErr(.{}, color); process.exit(2); } } @@ -317,7 +317,7 @@ fn fmtPathFile( try wip_errors.addZirErrorMessages(zir, tree, source_code, file_path); var error_bundle = try wip_errors.toOwnedBundle(""); defer error_bundle.deinit(gpa); - error_bundle.renderToStdErr(fmt.color.renderOptions()); + error_bundle.renderToStdErr(.{}, fmt.color); fmt.any_error = true; } }, @@ -332,7 +332,7 @@ fn fmtPathFile( try wip_errors.addZoirErrorMessages(zoir, tree, source_code, file_path); var error_bundle = try wip_errors.toOwnedBundle(""); defer error_bundle.deinit(gpa); - error_bundle.renderToStdErr(fmt.color.renderOptions()); + error_bundle.renderToStdErr(.{}, fmt.color); fmt.any_error = true; } }, diff --git a/src/libs/mingw.zig b/src/libs/mingw.zig index 1773c321e1..e45e6c2856 100644 --- a/src/libs/mingw.zig +++ b/src/libs/mingw.zig @@ -312,7 +312,7 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void { const include_dir = try comp.dirs.zig_lib.join(arena, &.{ "libc", "mingw", "def-include" }); if (comp.verbose_cc) print: { - var stderr = std.debug.lockStderrWriter(&.{}); + var stderr, _ = std.debug.lockStderrWriter(&.{}); defer std.debug.unlockStderrWriter(); nosuspend stderr.print("def file: {s}\n", .{def_file_path}) catch break :print; nosuspend stderr.print("include dir: {s}\n", .{include_dir}) catch break :print; @@ -332,11 +332,11 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void { if (aro_comp.diagnostics.output.to_list.messages.items.len != 0) { var buffer: [64]u8 = undefined; - const w = std.debug.lockStderrWriter(&buffer); + const w, const ttyconf = std.debug.lockStderrWriter(&buffer); defer std.debug.unlockStderrWriter(); for (aro_comp.diagnostics.output.to_list.messages.items) |msg| { if (msg.kind == .@"fatal error" or msg.kind == .@"error") { - msg.write(w, .detect(std.fs.File.stderr()), true) catch {}; + msg.write(w, ttyconf, true) catch {}; return error.AroPreprocessorFailed; } } @@ -356,7 +356,7 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void { error.OutOfMemory => |e| return e, error.ParseError => { var buffer: [64]u8 = undefined; - const w = std.debug.lockStderrWriter(&buffer); + const w, _ = std.debug.lockStderrWriter(&buffer); defer std.debug.unlockStderrWriter(); try w.writeAll("error: "); try def_diagnostics.writeMsg(w, input); diff --git a/src/libs/mingw/def.zig b/src/libs/mingw/def.zig index 98ea1a5396..24dc95c13c 100644 --- a/src/libs/mingw/def.zig +++ b/src/libs/mingw/def.zig @@ -1028,7 +1028,7 @@ fn testParse(machine_type: std.coff.IMAGE.FILE.MACHINE, source: [:0]const u8, ex const module = parse(std.testing.allocator, source, machine_type, .mingw, &diagnostics) catch |err| switch (err) { error.OutOfMemory => |e| return e, error.ParseError => { - const stderr = std.debug.lockStderrWriter(&.{}); + const stderr, _ = std.debug.lockStderrWriter(&.{}); defer std.debug.unlockStderrWriter(); try diagnostics.writeMsg(stderr, source); try stderr.writeByte('\n'); diff --git a/src/link.zig b/src/link.zig index 7cf8e5c1a6..5c4354411b 100644 --- a/src/link.zig +++ b/src/link.zig @@ -2215,7 +2215,7 @@ fn resolvePathInputLib( var error_bundle = try wip_errors.toOwnedBundle(""); defer error_bundle.deinit(gpa); - error_bundle.renderToStdErr(color.renderOptions()); + error_bundle.renderToStdErr(.{}, color); std.process.exit(1); } diff --git a/src/link/Coff.zig b/src/link/Coff.zig index 32889684dc..9dbbccf70e 100644 --- a/src/link/Coff.zig +++ b/src/link/Coff.zig @@ -2335,7 +2335,7 @@ pub fn deleteExport(coff: *Coff, exported: Zcu.Exported, name: InternPool.NullTe } pub fn dump(coff: *Coff, tid: Zcu.PerThread.Id) void { - const w = std.debug.lockStderrWriter(&.{}); + const w, _ = std.debug.lockStderrWriter(&.{}); defer std.debug.unlockStderrWriter(); coff.printNode(tid, w, .root, 0) catch {}; } diff --git a/src/link/Elf2.zig b/src/link/Elf2.zig index 93fa490907..6f1f9d6f0e 100644 --- a/src/link/Elf2.zig +++ b/src/link/Elf2.zig @@ -1965,7 +1965,7 @@ pub fn deleteExport(elf: *Elf, exported: Zcu.Exported, name: InternPool.NullTerm } pub fn dump(elf: *Elf, tid: Zcu.PerThread.Id) void { - const w = std.debug.lockStderrWriter(&.{}); + const w, _ = std.debug.lockStderrWriter(&.{}); defer std.debug.unlockStderrWriter(); elf.printNode(tid, w, .root, 0) catch {}; } diff --git a/src/main.zig b/src/main.zig index 03d42ba898..d134dd9bd2 100644 --- a/src/main.zig +++ b/src/main.zig @@ -4520,7 +4520,7 @@ fn updateModule(comp: *Compilation, color: Color, prog_node: std.Progress.Node) defer errors.deinit(comp.gpa); if (errors.errorMessageCount() > 0) { - errors.renderToStdErr(color.renderOptions()); + errors.renderToStdErr(.{}, color); return error.CompileErrorsReported; } } @@ -4573,7 +4573,7 @@ fn cmdTranslateC( return; } else { const color: Color = .auto; - result.errors.renderToStdErr(color.renderOptions()); + result.errors.renderToStdErr(.{}, color); process.exit(1); } } @@ -5199,7 +5199,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8) if (fetch.error_bundle.root_list.items.len > 0) { var errors = try fetch.error_bundle.toOwnedBundle(""); - errors.renderToStdErr(color.renderOptions()); + errors.renderToStdErr(.{}, color); process.exit(1); } @@ -6135,7 +6135,7 @@ fn cmdAstCheck(arena: Allocator, io: Io, args: []const []const u8) !void { try wip_errors.init(arena); try wip_errors.addZirErrorMessages(zir, tree, source, display_path); var error_bundle = try wip_errors.toOwnedBundle(""); - error_bundle.renderToStdErr(color.renderOptions()); + error_bundle.renderToStdErr(.{}, color); if (zir.loweringFailed()) { process.exit(1); } @@ -6206,7 +6206,7 @@ fn cmdAstCheck(arena: Allocator, io: Io, args: []const []const u8) !void { try wip_errors.init(arena); try wip_errors.addZoirErrorMessages(zoir, tree, source, display_path); var error_bundle = try wip_errors.toOwnedBundle(""); - error_bundle.renderToStdErr(color.renderOptions()); + error_bundle.renderToStdErr(.{}, color); process.exit(1); } @@ -6479,7 +6479,7 @@ fn cmdChangelist(arena: Allocator, io: Io, args: []const []const u8) !void { try wip_errors.init(arena); try wip_errors.addZirErrorMessages(old_zir, old_tree, old_source, old_source_path); var error_bundle = try wip_errors.toOwnedBundle(""); - error_bundle.renderToStdErr(color.renderOptions()); + error_bundle.renderToStdErr(.{}, color); process.exit(1); } @@ -6491,7 +6491,7 @@ fn cmdChangelist(arena: Allocator, io: Io, args: []const []const u8) !void { try wip_errors.init(arena); try wip_errors.addZirErrorMessages(new_zir, new_tree, new_source, new_source_path); var error_bundle = try wip_errors.toOwnedBundle(""); - error_bundle.renderToStdErr(color.renderOptions()); + error_bundle.renderToStdErr(.{}, color); process.exit(1); } @@ -6948,7 +6948,7 @@ fn cmdFetch( if (fetch.error_bundle.root_list.items.len > 0) { var errors = try fetch.error_bundle.toOwnedBundle(""); - errors.renderToStdErr(color.renderOptions()); + errors.renderToStdErr(.{}, color); process.exit(1); } @@ -7304,7 +7304,7 @@ fn loadManifest( var error_bundle = try wip_errors.toOwnedBundle(""); defer error_bundle.deinit(gpa); - error_bundle.renderToStdErr(options.color.renderOptions()); + error_bundle.renderToStdErr(.{}, options.color); process.exit(2); } diff --git a/test/behavior/enum.zig b/test/behavior/enum.zig index 8fb5d288e3..175449b566 100644 --- a/test/behavior/enum.zig +++ b/test/behavior/enum.zig @@ -899,7 +899,6 @@ test "enum value allocation" { } test "enum literal casting to tagged union" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO @@ -935,7 +934,6 @@ test "enum literal casting to error union with payload enum" { } test "constant enum initialization with differing sizes" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; diff --git a/test/behavior/optional.zig b/test/behavior/optional.zig index d8d26d6a0f..7c70101c57 100644 --- a/test/behavior/optional.zig +++ b/test/behavior/optional.zig @@ -149,7 +149,6 @@ test "nested optional field in struct" { } test "equality compare optionals and non-optionals" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; @@ -209,7 +208,6 @@ test "equality compare optionals and non-optionals" { } test "compare optionals with modified payloads" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var lhs: ?bool = false; diff --git a/test/behavior/switch.zig b/test/behavior/switch.zig index b5540664c9..170e8d9778 100644 --- a/test/behavior/switch.zig +++ b/test/behavior/switch.zig @@ -576,7 +576,6 @@ test "switch with null and T peer types and inferred result location type" { } test "switch prongs with cases with identical payload types" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO @@ -824,7 +823,6 @@ test "comptime inline switch" { } test "switch capture peer type resolution" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const U = union(enum) { diff --git a/test/behavior/tuple.zig b/test/behavior/tuple.zig index dfd72fea7a..54d73eee8a 100644 --- a/test/behavior/tuple.zig +++ b/test/behavior/tuple.zig @@ -496,7 +496,6 @@ test "anon tuple field referencing comptime var isn't comptime" { } test "tuple with runtime value coerced into a slice with a sentinel" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; diff --git a/test/behavior/union.zig b/test/behavior/union.zig index b4477990aa..27663feeb6 100644 --- a/test/behavior/union.zig +++ b/test/behavior/union.zig @@ -208,7 +208,6 @@ const Payload = union(Letter) { }; test "union with specified enum tag" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; @@ -219,7 +218,6 @@ test "union with specified enum tag" { } test "packed union generates correctly aligned type" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; @@ -605,7 +603,6 @@ fn returnAnInt(x: i32) TaggedFoo { } test "tagged union with all void fields but a meaningful tag" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO @@ -1032,7 +1029,6 @@ test "containers with single-field enums" { } test "@unionInit on union with tag but no fields" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO @@ -1446,8 +1442,6 @@ test "access the tag of a global tagged union" { } test "coerce enum literal to union in result loc" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - const U = union(enum) { a, b: u8, diff --git a/tools/gen_spirv_spec.zig b/tools/gen_spirv_spec.zig index 702866824c..c211d1022e 100644 --- a/tools/gen_spirv_spec.zig +++ b/tools/gen_spirv_spec.zig @@ -89,10 +89,9 @@ pub fn main() !void { const output = allocating.written()[0 .. allocating.written().len - 1 :0]; var tree = try std.zig.Ast.parse(allocator, output, .zig); - var color: std.zig.Color = .on; if (tree.errors.len != 0) { - try std.zig.printAstErrorsToStderr(allocator, tree, "", color); + try std.zig.printAstErrorsToStderr(allocator, tree, "", .auto); return; } @@ -104,7 +103,7 @@ pub fn main() !void { try wip_errors.addZirErrorMessages(zir, tree, output, ""); var error_bundle = try wip_errors.toOwnedBundle(""); defer error_bundle.deinit(allocator); - error_bundle.renderToStdErr(color.renderOptions()); + error_bundle.renderToStdErr(.{}, .auto); } const formatted_output = try tree.renderAlloc(allocator); @@ -931,7 +930,7 @@ fn parseHexInt(text: []const u8) !u31 { } fn usageAndExit(arg0: []const u8, code: u8) noreturn { - const stderr = std.debug.lockStderrWriter(&.{}); + const stderr, _ = std.debug.lockStderrWriter(&.{}); stderr.print( \\Usage: {s} \\ diff --git a/tools/generate_linux_syscalls.zig b/tools/generate_linux_syscalls.zig index 2705618a7d..e009715e2f 100644 --- a/tools/generate_linux_syscalls.zig +++ b/tools/generate_linux_syscalls.zig @@ -177,7 +177,9 @@ pub fn main() !void { const args = try std.process.argsAlloc(gpa); if (args.len < 2 or mem.eql(u8, args[1], "--help")) { - usage(std.debug.lockStderrWriter(&.{}), args[0]) catch std.process.exit(2); + const w, _ = std.debug.lockStderrWriter(&.{}); + defer std.debug.unlockStderrWriter(); + usage(w, args[0]) catch std.process.exit(2); std.process.exit(1); } const linux_path = args[1]; diff --git a/tools/incr-check.zig b/tools/incr-check.zig index 22031e147a..dffd3ccb34 100644 --- a/tools/incr-check.zig +++ b/tools/incr-check.zig @@ -340,8 +340,7 @@ const Eval = struct { .unknown => return, .compile_errors => |ce| ce, .stdout, .exit_code => { - const color: std.zig.Color = .auto; - error_bundle.renderToStdErr(color.renderOptions()); + error_bundle.renderToStdErr(.{}, .auto); eval.fatal("update '{s}': unexpected compile errors", .{update.name}); }, }; @@ -350,8 +349,7 @@ const Eval = struct { for (error_bundle.getMessages()) |err_idx| { if (expected_idx == expected.errors.len) { - const color: std.zig.Color = .auto; - error_bundle.renderToStdErr(color.renderOptions()); + error_bundle.renderToStdErr(.{}, .auto); eval.fatal("update '{s}': more errors than expected", .{update.name}); } try eval.checkOneError(update, error_bundle, expected.errors[expected_idx], false, err_idx); @@ -359,8 +357,7 @@ const Eval = struct { for (error_bundle.getNotes(err_idx)) |note_idx| { if (expected_idx == expected.errors.len) { - const color: std.zig.Color = .auto; - error_bundle.renderToStdErr(color.renderOptions()); + error_bundle.renderToStdErr(.{}, .auto); eval.fatal("update '{s}': more error notes than expected", .{update.name}); } try eval.checkOneError(update, error_bundle, expected.errors[expected_idx], true, note_idx); @@ -369,8 +366,7 @@ const Eval = struct { } if (!std.mem.eql(u8, error_bundle.getCompileLogOutput(), expected.compile_log_output)) { - const color: std.zig.Color = .auto; - error_bundle.renderToStdErr(color.renderOptions()); + error_bundle.renderToStdErr(.{}, .auto); eval.fatal("update '{s}': unexpected compile log output", .{update.name}); } } @@ -404,8 +400,7 @@ const Eval = struct { expected.column != src.column + 1 or !std.mem.eql(u8, expected.msg, msg)) { - const color: std.zig.Color = .auto; - eb.renderToStdErr(color.renderOptions()); + eb.renderToStdErr(.{}, .auto); eval.fatal("update '{s}': compile error did not match expected error", .{update.name}); } } diff --git a/tools/update_clang_options.zig b/tools/update_clang_options.zig index 9b054478a2..c8b941cbfa 100644 --- a/tools/update_clang_options.zig +++ b/tools/update_clang_options.zig @@ -961,7 +961,9 @@ fn objectLessThan(context: void, a: *json.ObjectMap, b: *json.ObjectMap) bool { } fn printUsageAndExit(arg0: []const u8) noreturn { - printUsage(std.debug.lockStderrWriter(&.{}), arg0) catch std.process.exit(2); + const w, _ = std.debug.lockStderrWriter(&.{}); + defer std.debug.unlockStderrWriter(); + printUsage(w, arg0) catch std.process.exit(2); std.process.exit(1); } diff --git a/tools/update_cpu_features.zig b/tools/update_cpu_features.zig index 786c78544d..eeaa2bb393 100644 --- a/tools/update_cpu_features.zig +++ b/tools/update_cpu_features.zig @@ -2167,7 +2167,7 @@ fn processOneTarget(job: Job) void { } fn usageAndExit(arg0: []const u8, code: u8) noreturn { - const stderr = std.debug.lockStderrWriter(&.{}); + const stderr, _ = std.debug.lockStderrWriter(&.{}); stderr.print( \\Usage: {s} /path/to/llvm-tblgen /path/git/llvm-project /path/git/zig [zig_name filter] \\ diff --git a/tools/update_crc_catalog.zig b/tools/update_crc_catalog.zig index a973a1b75a..4c8614e02f 100644 --- a/tools/update_crc_catalog.zig +++ b/tools/update_crc_catalog.zig @@ -190,7 +190,9 @@ pub fn main() anyerror!void { } fn printUsageAndExit(arg0: []const u8) noreturn { - printUsage(std.debug.lockStderrWriter(&.{}), arg0) catch std.process.exit(2); + const w, _ = std.debug.lockStderrWriter(&.{}); + defer std.debug.unlockStderrWriter(); + printUsage(w, arg0) catch std.process.exit(2); std.process.exit(1); }