authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2026-10-08 01:49:12-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-10-21 10:04:01-07:00
logf08a8f0fc217914690a58035291da8bcc7a86e47
tree64f17ff2fcdef605d510f8370fde1b41a4eb4b51
parent77576c960388f0ad6712f1e15b97ca689892d708

main: reimplement compiler debug flags

* Add `.llvmbc`/`.llvmir` to `ObjectFormat` for emitting unoptimized IR * Replace `--verbose-air`, `--verbose-intern-pool`, `--verbose-generic-instances`, `--verbose-llvm-ir`, and `--verbose-llvm-bc` with various `--debug-log` scopes * `--debug-log illegal-air`: pre-legalized Air * `--debug-log legal-air`: post-legalized Air * `--debug-log air`: final Air with liveness * `--debug-log ip-stats`: InternPool statistics * `--debug-log ip-values`: InternPool values * `--debug-log ip-generic-instances`: InternPool generic instances * `--debug-log llvm-ir`: pre-optimized LLVM IR * `--debug-log opt-llvm-ir`: post-optimized LLVM IR * Delete `--verbose-cimport` which does nothing * Delete `--verbose-llvm-cpu-features` which is equivalent to looking at the outputs of `--show-builtin` and `--debug-log llvm-ir`

49 files changed, 1392 insertions(+), 1464 deletions(-)

CMakeLists.txt+1-1
...@@ -330,7 +330,7 @@ set(ZIG_STAGE2_SOURCES...@@ -330,7 +330,7 @@ set(ZIG_STAGE2_SOURCES
330 src/Air/Legalize.zig330 src/Air/Legalize.zig
331 src/Air/Liveness.zig331 src/Air/Liveness.zig
332 src/Air/Liveness/Verify.zig332 src/Air/Liveness/Verify.zig
333 src/Air/print.zig333 src/Air/Print.zig
334 src/Builtin.zig334 src/Builtin.zig
335 src/Compilation.zig335 src/Compilation.zig
336 src/Compilation/Config.zig336 src/Compilation/Config.zig
bootstrap.c+1-1
...@@ -179,7 +179,7 @@ int main(int argc, char **argv) {...@@ -179,7 +179,7 @@ int main(int argc, char **argv) {
179 "pub const version: [:0]const u8 = \"%s\";\n"179 "pub const version: [:0]const u8 = \"%s\";\n"
180 "pub const semver = @import(\"std\").SemanticVersion.parse(version) catch unreachable;\n"180 "pub const semver = @import(\"std\").SemanticVersion.parse(version) catch unreachable;\n"
181 "pub const enable_debug_extensions = false;\n"181 "pub const enable_debug_extensions = false;\n"
182 "pub const enable_logging = false;\n"182 "pub const log_level: @import(\"std\").log.Level = .err;\n"
183 "pub const enable_link_snapshots = false;\n"183 "pub const enable_link_snapshots = false;\n"
184 "pub const enable_tracy = false;\n"184 "pub const enable_tracy = false;\n"
185 "pub const value_tracing = false;\n"185 "pub const value_tracing = false;\n"
build.zig+17-7
...@@ -25,6 +25,10 @@ pub fn build(b: *std.Build) !void {...@@ -25,6 +25,10 @@ pub fn build(b: *std.Build) !void {
25 },25 },
26 });26 });
27 const optimize = b.standardOptimizeOption(.{});27 const optimize = b.standardOptimizeOption(.{});
28 const is_debug = switch (optimize) {
29 .debug => true,
30 .safe, .fast, .small => false,
31 };
2832
29 const flat = b.option(bool, "flat", "Put files into the installation prefix in a manner suited for upstream distribution rather than a posix file system hierarchy standard") orelse false;33 const flat = b.option(bool, "flat", "Put files into the installation prefix in a manner suited for upstream distribution rather than a posix file system hierarchy standard") orelse false;
30 const single_threaded = b.option(bool, "single-threaded", "Build artifacts that run in single threaded mode");34 const single_threaded = b.option(bool, "single-threaded", "Build artifacts that run in single threaded mode");
...@@ -205,9 +209,9 @@ pub fn build(b: *std.Build) !void {...@@ -205,9 +209,9 @@ pub fn build(b: *std.Build) !void {
205 const value_tracing = b.option(bool, "value-tracing", "Enable extra state tracking to help troubleshoot bugs in the compiler (using the std.debug.Trace API)") orelse false;209 const value_tracing = b.option(bool, "value-tracing", "Enable extra state tracking to help troubleshoot bugs in the compiler (using the std.debug.Trace API)") orelse false;
206210
207 const mem_leak_frames: u32 = b.option(u32, "mem-leak-frames", "How many stack frames to print when a memory leak occurs. Tests get 2x this amount.") orelse blk: {211 const mem_leak_frames: u32 = b.option(u32, "mem-leak-frames", "How many stack frames to print when a memory leak occurs. Tests get 2x this amount.") orelse blk: {
208 if (strip == true) break :blk @as(u32, 0);212 if (strip == true) break :blk 0;
209 if (optimize != .debug) break :blk 0;213 if (is_debug) break :blk 4;
210 break :blk 4;214 break :blk 0;
211 };215 };
212216
213 const exe = addCompilerStep(b, .{217 const exe = addCompilerStep(b, .{
...@@ -255,9 +259,15 @@ pub fn build(b: *std.Build) !void {...@@ -255,9 +259,15 @@ pub fn build(b: *std.Build) !void {
255 exe.root_module.link_libc = true;259 exe.root_module.link_libc = true;
256 }260 }
257261
258 const is_debug = optimize == .debug;
259 const enable_debug_extensions = b.option(bool, "debug-extensions", "Enable commands and options useful for debugging the compiler") orelse is_debug;262 const enable_debug_extensions = b.option(bool, "debug-extensions", "Enable commands and options useful for debugging the compiler") orelse is_debug;
260 const enable_logging = b.option(bool, "log", "Enable debug logging with --debug-log") orelse is_debug;263 const log_level: std.log.Level = b.option(std.log.Level, "log", "Enable logs of the given or higher severity. Passing 'debug' still requires passing '--debug-log' to actually see any debug logs.") orelse switch (enable_debug_extensions) {
264 true => .debug,
265 false => switch (optimize) {
266 .debug => .debug,
267 .safe, .fast => .info,
268 .small => .err,
269 },
270 };
261271
262 const opt_version_string = b.option([]const u8, "version-string", "Override Zig version string. Default is to find out with git.");272 const opt_version_string = b.option([]const u8, "version-string", "Override Zig version string. Default is to find out with git.");
263 const version_slice = if (opt_version_string) |version| version else v: {273 const version_slice = if (opt_version_string) |version| version else v: {
...@@ -398,7 +408,7 @@ pub fn build(b: *std.Build) !void {...@@ -398,7 +408,7 @@ pub fn build(b: *std.Build) !void {
398 exe_options.addOption(std.SemanticVersion, "semver", semver);408 exe_options.addOption(std.SemanticVersion, "semver", semver);
399409
400 exe_options.addOption(bool, "enable_debug_extensions", enable_debug_extensions);410 exe_options.addOption(bool, "enable_debug_extensions", enable_debug_extensions);
401 exe_options.addOption(bool, "enable_logging", enable_logging);411 exe_options.addOption(std.log.Level, "log_level", log_level);
402 exe_options.addOption(bool, "enable_tracy", tracy != null);412 exe_options.addOption(bool, "enable_tracy", tracy != null);
403 exe_options.addOption(bool, "enable_tracy_callstack", tracy_callstack);413 exe_options.addOption(bool, "enable_tracy_callstack", tracy_callstack);
404 exe_options.addOption(bool, "enable_tracy_allocation", tracy_allocation);414 exe_options.addOption(bool, "enable_tracy_allocation", tracy_allocation);
...@@ -837,7 +847,7 @@ fn addWasiUpdateStep(b: *std.Build, version: [:0]const u8) !void {...@@ -837,7 +847,7 @@ fn addWasiUpdateStep(b: *std.Build, version: [:0]const u8) !void {
837 exe_options.addOption([:0]const u8, "version", version);847 exe_options.addOption([:0]const u8, "version", version);
838 exe_options.addOption(std.SemanticVersion, "semver", semver);848 exe_options.addOption(std.SemanticVersion, "semver", semver);
839 exe_options.addOption(bool, "enable_debug_extensions", false);849 exe_options.addOption(bool, "enable_debug_extensions", false);
840 exe_options.addOption(bool, "enable_logging", false);850 exe_options.addOption(std.log.Level, "log_level", .err);
841 exe_options.addOption(bool, "enable_tracy", false);851 exe_options.addOption(bool, "enable_tracy", false);
842 exe_options.addOption(bool, "enable_tracy_callstack", false);852 exe_options.addOption(bool, "enable_tracy_callstack", false);
843 exe_options.addOption(bool, "enable_tracy_allocation", false);853 exe_options.addOption(bool, "enable_tracy_allocation", false);
lib/compiler/Maker.zig-4
...@@ -509,14 +509,10 @@ pub fn main(init: process.Init.Minimal) !void {...@@ -509,14 +509,10 @@ pub fn main(init: process.Init.Minimal) !void {
509 } else if (mem.eql(u8, arg, "--libc-runtimes") or mem.eql(u8, arg, "--glibc-runtimes")) {509 } else if (mem.eql(u8, arg, "--libc-runtimes") or mem.eql(u8, arg, "--glibc-runtimes")) {
510 // --glibc-runtimes was the old name of the flag; kept for compatibility for now.510 // --glibc-runtimes was the old name of the flag; kept for compatibility for now.
511 graph.libc_runtimes_dir = nextArgOrFatal(args, &arg_i);511 graph.libc_runtimes_dir = nextArgOrFatal(args, &arg_i);
512 } else if (mem.eql(u8, arg, "--verbose-air")) {
513 graph.verbose_air = true;
514 } else if (mem.eql(u8, arg, "--verbose-cc")) {512 } else if (mem.eql(u8, arg, "--verbose-cc")) {
515 graph.verbose_cc = true;513 graph.verbose_cc = true;
516 } else if (mem.eql(u8, arg, "--verbose-link")) {514 } else if (mem.eql(u8, arg, "--verbose-link")) {
517 graph.verbose_link = true;515 graph.verbose_link = true;
518 } else if (mem.eql(u8, arg, "--verbose-llvm-ir")) {
519 graph.verbose_llvm_ir = true;
520 } else if (mem.eql(u8, arg, "--watch")) {516 } else if (mem.eql(u8, arg, "--watch")) {
521 watch_flag = true;517 watch_flag = true;
522 } else if (mem.eql(u8, arg, "--time-report")) {518 } else if (mem.eql(u8, arg, "--time-report")) {
lib/compiler/Maker/Graph.zig-3
...@@ -32,11 +32,8 @@ debug_compile_errors: bool = false,...@@ -32,11 +32,8 @@ debug_compile_errors: bool = false,
32debug_incremental: bool = false,32debug_incremental: bool = false,
33fuzzing: bool = false,33fuzzing: bool = false,
34verbose: bool = false,34verbose: bool = false,
35verbose_air: bool = false,
36verbose_cc: bool = false,35verbose_cc: bool = false,
37verbose_link: bool = false,36verbose_link: bool = false,
38verbose_llvm_cpu_features: bool = false,
39verbose_llvm_ir: bool = false,
40libc_file: ?[]const u8 = null,37libc_file: ?[]const u8 = null,
41/// What does this do? Nobody bothered to document it, and I think it's a38/// What does this do? Nobody bothered to document it, and I think it's a
42/// smelly option. So unless somebody deletes these passive aggressive comments39/// smelly option. So unless somebody deletes these passive aggressive comments
lib/compiler/Maker/ScannedConfig.zig+2-6
...@@ -351,6 +351,8 @@ const general_usage =...@@ -351,6 +351,8 @@ const general_usage =
351 \\ preferred optimization mode: fast, safe, small351 \\ preferred optimization mode: fast, safe, small
352 \\352 \\
353 \\ --verbose Print commands before executing them353 \\ --verbose Print commands before executing them
354 \\ --verbose-cc Print C compiler commands before executing them
355 \\ --verbose-link Print linker commands before executing them
354 \\ --color [auto|off|on] Enable or disable colored error messages356 \\ --color [auto|off|on] Enable or disable colored error messages
355 \\ --error-style [style] Control how build errors are printed357 \\ --error-style [style] Control how build errors are printed
356 \\ verbose (Default) Report errors with full context358 \\ verbose (Default) Report errors with full context
...@@ -417,11 +419,5 @@ const general_usage =...@@ -417,11 +419,5 @@ const general_usage =
417 \\ none (default) No build ID419 \\ none (default) No build ID
418 \\ --debug-log [scope] Enable debugging the compiler420 \\ --debug-log [scope] Enable debugging the compiler
419 \\ --debug-pkg-config Fail if unknown pkg-config flags encountered421 \\ --debug-pkg-config Fail if unknown pkg-config flags encountered
420 \\ --verbose-link Enable compiler debug output for linking
421 \\ --verbose-air Enable compiler debug output for Zig AIR
422 \\ --verbose-llvm-ir Enable compiler debug output for LLVM IR
423 \\ --verbose-cimport Enable compiler debug output for C imports
424 \\ --verbose-cc Enable compiler debug output for C compilation
425 \\ --verbose-llvm-cpu-features Enable compiler debug output for LLVM CPU features
426 \\422 \\
427;423;
lib/compiler/Maker/Step/Compile.zig+1-4
...@@ -608,11 +608,8 @@ fn lowerZigArgs(...@@ -608,11 +608,8 @@ fn lowerZigArgs(
608608
609 try addBool(gpa, zig_args, "--debug-compile-errors", graph.debug_compile_errors);609 try addBool(gpa, zig_args, "--debug-compile-errors", graph.debug_compile_errors);
610 try addBool(gpa, zig_args, "--debug-incremental", graph.debug_incremental);610 try addBool(gpa, zig_args, "--debug-incremental", graph.debug_incremental);
611 try addBool(gpa, zig_args, "--verbose-air", graph.verbose_air);
612 try addBool(gpa, zig_args, "--verbose-llvm-ir", graph.verbose_llvm_ir);
613 try addBool(gpa, zig_args, "--verbose-link", graph.verbose_link or conf_comp.flags.verbose_link);
614 try addBool(gpa, zig_args, "--verbose-cc", graph.verbose_cc or conf_comp.flags.verbose_cc);611 try addBool(gpa, zig_args, "--verbose-cc", graph.verbose_cc or conf_comp.flags.verbose_cc);
615 try addBool(gpa, zig_args, "--verbose-llvm-cpu-features", graph.verbose_llvm_cpu_features);612 try addBool(gpa, zig_args, "--verbose-link", graph.verbose_link or conf_comp.flags.verbose_link);
616 try addBool(gpa, zig_args, "--time-report", graph.time_report);613 try addBool(gpa, zig_args, "--time-report", graph.time_report);
617614
618 if (conf_comp.generated_bin.value == null) try zig_args.append(gpa, "-fno-emit-bin");615 if (conf_comp.generated_bin.value == null) try zig_args.append(gpa, "-fno-emit-bin");
lib/compiler/aro/aro/Driver.zig+1-1
...@@ -927,7 +927,7 @@ pub fn parseArgs(...@@ -927,7 +927,7 @@ pub fn parseArgs(
927 break :debug switch (d.comp.target.ofmt) {927 break :debug switch (d.comp.target.ofmt) {
928 .elf, .macho, .wasm => .{ .dwarf = .@"32" },928 .elf, .macho, .wasm => .{ .dwarf = .@"32" },
929 .coff => .code_view,929 .coff => .code_view,
930 .c => switch (d.comp.target.os.tag) {930 .c, .llvmbc, .llvmir => switch (d.comp.target.os.tag) {
931 .windows, .uefi => .code_view,931 .windows, .uefi => .code_view,
932 else => .{ .dwarf = .@"32" },932 else => .{ .dwarf = .@"32" },
933 },933 },
lib/std/Build/Configuration.zig+2
...@@ -2519,6 +2519,8 @@ pub const TargetQuery = struct {...@@ -2519,6 +2519,8 @@ pub const TargetQuery = struct {
2519 coff,2519 coff,
2520 elf,2520 elf,
2521 hex,2521 hex,
2522 llvmbc,
2523 llvmir,
2522 macho,2524 macho,
2523 plan9,2525 plan9,
2524 raw,2526 raw,
lib/std/Target.zig+6
...@@ -1043,6 +1043,10 @@ pub const ObjectFormat = enum {...@@ -1043,6 +1043,10 @@ pub const ObjectFormat = enum {
1043 elf,1043 elf,
1044 /// The Intel HEX format for storing binary code in ASCII text.1044 /// The Intel HEX format for storing binary code in ASCII text.
1045 hex,1045 hex,
1046 /// LLVM binary intermediate representation.
1047 llvmbc,
1048 /// LLVM text intermediate representation.
1049 llvmir,
1046 /// The Mach object format used by macOS and other Apple platforms.1050 /// The Mach object format used by macOS and other Apple platforms.
1047 macho,1051 macho,
1048 /// The a.out format used by Plan 9 from Bell Labs.1052 /// The a.out format used by Plan 9 from Bell Labs.
...@@ -1060,6 +1064,8 @@ pub const ObjectFormat = enum {...@@ -1060,6 +1064,8 @@ pub const ObjectFormat = enum {
1060 .coff => ".obj",1064 .coff => ".obj",
1061 .elf, .macho, .wasm => ".o",1065 .elf, .macho, .wasm => ".o",
1062 .hex => ".ihex",1066 .hex => ".ihex",
1067 .llvmbc => ".bc",
1068 .llvmir => ".ll",
1063 .plan9 => arch.plan9Ext(),1069 .plan9 => arch.plan9Ext(),
1064 .raw => ".bin",1070 .raw => ".bin",
1065 .spirv => ".spv",1071 .spirv => ".spv",
lib/std/debug.zig+1-1
...@@ -76,7 +76,7 @@ pub fn TargetInfo(os: std.Target.Os.Tag, arch: std.Target.Cpu.Arch) type {...@@ -76,7 +76,7 @@ pub fn TargetInfo(os: std.Target.Os.Tag, arch: std.Target.Cpu.Arch) type {
76 },76 },
77 .macho => @import("debug/SelfInfo/MachO.zig"),77 .macho => @import("debug/SelfInfo/MachO.zig"),
78 .plan9, .spirv, .wasm, .raw, .hex => void,78 .plan9, .spirv, .wasm, .raw, .hex => void,
79 .c => unreachable,79 .c, .llvmbc, .llvmir => unreachable,
80 };80 };
81}81}
8282
lib/std/fmt.zig+7-1
...@@ -285,7 +285,13 @@ pub fn Alt(...@@ -285,7 +285,13 @@ pub fn Alt(
285pub fn alt(285pub fn alt(
286 context: anytype,286 context: anytype,
287 comptime func_name: @EnumLiteral(),287 comptime func_name: @EnumLiteral(),
288) Alt(@TypeOf(context), @field(@TypeOf(context), @tagName(func_name))) {288) Alt(@TypeOf(context), @field(switch (@typeInfo(@TypeOf(context))) {
289 else => @TypeOf(context),
290 .pointer => |pointer| switch (pointer.size) {
291 else => @TypeOf(context),
292 .one => pointer.child,
293 },
294}, @tagName(func_name))) {
289 return .{ .data = context };295 return .{ .data = context };
290}296}
291297
lib/std/zig.zig+2
...@@ -218,6 +218,8 @@ pub fn binNameAlloc(allocator: Allocator, options: BinNameOptions) error{OutOfMe...@@ -218,6 +218,8 @@ pub fn binNameAlloc(allocator: Allocator, options: BinNameOptions) error{OutOfMe
218 },218 },
219 .Obj => return std.fmt.allocPrint(allocator, "{s}.o", .{root_name}),219 .Obj => return std.fmt.allocPrint(allocator, "{s}.o", .{root_name}),
220 },220 },
221 .llvmbc => return std.fmt.allocPrint(allocator, "{s}.bc", .{root_name}),
222 .llvmir => return std.fmt.allocPrint(allocator, "{s}.ll", .{root_name}),
221 .macho => switch (options.output_mode) {223 .macho => switch (options.output_mode) {
222 .Exe => return allocator.dupe(u8, root_name),224 .Exe => return allocator.dupe(u8, root_name),
223 .Lib => {225 .Lib => {
lib/std/zig/llvm/Builder.zig+16-5
...@@ -10855,11 +10855,22 @@ pub fn resolveAlignmentForwardReference(b: *Builder, fwd_ref: Alignment.Lazy, va...@@ -10855,11 +10855,22 @@ pub fn resolveAlignmentForwardReference(b: *Builder, fwd_ref: Alignment.Lazy, va
10855 b.alignment_forward_references.items[index] = value;10855 b.alignment_forward_references.items[index] = value;
10856}10856}
1085710857
10858pub fn dump(b: *Builder, io: Io) void {10858pub const Print = struct {
10859 var buffer: [4000]u8 = undefined;10859 name: []const u8,
10860 const stderr: Io.File = .stderr();10860 builder: *Builder,
10861 b.printToFile(io, stderr, &buffer) catch {};10861 err: ?Allocator.Error,
10862}10862
10863 pub fn format(p: *Print, w: *Writer) Writer.Error!void {
10864 try w.print("{q}", .{p.name});
10865 p.builder.print(w) catch |err| switch (err) {
10866 error.WriteFailed => |e| return e,
10867 error.OutOfMemory => |e| {
10868 p.err = e;
10869 return error.WriteFailed;
10870 },
10871 };
10872 }
10873};
1086310874
10864pub fn printToFilePath(b: *Builder, io: Io, dir: Io.Dir, path: []const u8) !void {10875pub fn printToFilePath(b: *Builder, io: Io, dir: Io.Dir, path: []const u8) !void {
10865 var buffer: [4000]u8 = undefined;10876 var buffer: [4000]u8 = undefined;
src/Air.zig+5-5
...@@ -13,10 +13,10 @@ const InternPool = @import("InternPool.zig");...@@ -13,10 +13,10 @@ const InternPool = @import("InternPool.zig");
13const Type = @import("Type.zig");13const Type = @import("Type.zig");
14const Value = @import("Value.zig");14const Value = @import("Value.zig");
15const Zcu = @import("Zcu.zig");15const Zcu = @import("Zcu.zig");
16const print = @import("Air/print.zig");
1716
18pub const Legalize = @import("Air/Legalize.zig");17pub const Legalize = @import("Air/Legalize.zig");
19pub const Liveness = @import("Air/Liveness.zig");18pub const Liveness = @import("Air/Liveness.zig");
19pub const Print = @import("Air/Print.zig");
20pub const Verify = @import("Air/Verify.zig");20pub const Verify = @import("Air/Verify.zig");
2121
22instructions: std.MultiArrayList(Inst).Slice,22instructions: std.MultiArrayList(Inst).Slice,
...@@ -2517,10 +2517,10 @@ pub fn unwrapShuffleTwo(air: *const Air, zcu: *const Zcu, inst_index: Inst.Index...@@ -2517,10 +2517,10 @@ pub fn unwrapShuffleTwo(air: *const Air, zcu: *const Zcu, inst_index: Inst.Index
2517}2517}
25182518
2519pub const legalize = Legalize.legalize;2519pub const legalize = Legalize.legalize;
2520pub const write = print.write;2520pub const write = Print.write;
2521pub const writeInst = print.writeInst;2521pub const writeInst = Print.writeInst;
2522pub const dump = print.dump;2522pub const dump = Print.dump;
2523pub const dumpInst = print.dumpInst;2523pub const dumpInst = Print.dumpInst;
25242524
2525pub const CoveragePoint = enum(u1) {2525pub const CoveragePoint = enum(u1) {
2526 /// Indicates the block is not a place of interest corresponding to2526 /// Indicates the block is not a place of interest corresponding to
src/Air/Print.zig created+1059
...@@ -0,0 +1,1059 @@
1const std = @import("std");
2const Allocator = std.mem.Allocator;
3const assert = std.debug.assert;
4
5const build_options = @import("build_options");
6const Zcu = @import("../Zcu.zig");
7const Value = @import("../Value.zig");
8const Type = @import("../Type.zig");
9const Air = @import("../Air.zig");
10const InternPool = @import("../InternPool.zig");
11const Printer = @This();
12
13zcu: *Zcu,
14fqn: InternPool.NullTerminatedString,
15air: *const Air,
16liveness: *const ?Air.Liveness,
17
18pub fn format(p: *const Printer, w: *std.Io.Writer) std.Io.Writer.Error!void {
19 try w.print("{qf}:\n", .{p.fqn.fmt(&p.zcu.intern_pool)});
20 try p.air.write(w, p.zcu, p.liveness.*);
21}
22
23pub fn write(air: Air, stream: *std.Io.Writer, zcu: *Zcu, liveness: ?Air.Liveness) !void {
24 comptime assert(build_options.log_level == .debug);
25 const instruction_bytes = air.instructions.len *
26 // Here we don't use @sizeOf(Air.Inst.Data) because it would include
27 // the debug safety tag but we want to measure release size.
28 (@sizeOf(Air.Inst.Tag) + 8);
29 const extra_bytes = air.extra.items.len * @sizeOf(u32);
30 const tomb_bytes = if (liveness) |l| l.tomb_bits.len * @sizeOf(usize) else 0;
31 const liveness_extra_bytes = if (liveness) |l| l.extra.len * @sizeOf(u32) else 0;
32 const liveness_special_bytes = if (liveness) |l| l.special.count() * 8 else 0;
33 const total_bytes = @sizeOf(Air) + instruction_bytes + extra_bytes +
34 @sizeOf(Air.Liveness) + liveness_extra_bytes +
35 liveness_special_bytes + tomb_bytes;
36
37 // zig fmt: off
38 try stream.print(
39 \\# Total AIR+Liveness bytes: {Bi}
40 \\# AIR Instructions: {d} ({Bi})
41 \\# AIR Extra Data: {d} ({Bi})
42 \\# Liveness tomb_bits: {Bi}
43 \\# Liveness Extra Data: {d} ({Bi})
44 \\# Liveness special table: {d} ({Bi})
45 \\
46 , .{
47 total_bytes,
48 air.instructions.len, instruction_bytes,
49 air.extra.items.len, extra_bytes,
50 tomb_bytes,
51 if (liveness) |l| l.extra.len else 0, liveness_extra_bytes,
52 if (liveness) |l| l.special.count() else 0, liveness_special_bytes,
53 });
54 // zig fmt: on
55
56 var writer: Writer = .{
57 .zcu = zcu,
58 .gpa = zcu.comp.gpa,
59 .air = air,
60 .liveness = liveness,
61 .indent = 2,
62 .skip_body = false,
63 };
64 try writer.writeBody(stream, air.getMainBody());
65}
66
67pub fn writeInst(
68 air: Air,
69 stream: *std.Io.Writer,
70 inst: Air.Inst.Index,
71 zcu: *Zcu,
72 liveness: ?Air.Liveness,
73) void {
74 comptime assert(build_options.log_level == .debug);
75 var writer: Writer = .{
76 .zcu = zcu,
77 .gpa = zcu.comp.gpa,
78 .air = air,
79 .liveness = liveness,
80 .indent = 2,
81 .skip_body = true,
82 };
83 writer.writeInst(stream, inst) catch return;
84}
85
86pub fn dump(air: Air, pt: Zcu.PerThread, liveness: ?Air.Liveness) void {
87 var buffer: [4096]u8 = undefined;
88 const stderr = std.debug.lockStderr(&buffer);
89 defer std.debug.unlockStderr();
90 const w = &stderr.file_writer.interface;
91 air.write(w, pt, liveness) catch return;
92}
93
94pub fn dumpInst(air: Air, inst: Air.Inst.Index, pt: Zcu.PerThread, liveness: ?Air.Liveness) void {
95 var buffer: [4096]u8 = undefined;
96 const stderr = std.debug.lockStderr(&buffer);
97 defer std.debug.unlockStderr();
98 const w = &stderr.file_writer.interface;
99 air.writeInst(w, inst, pt, liveness) catch return;
100}
101
102const Writer = struct {
103 zcu: *Zcu,
104 gpa: Allocator,
105 air: Air,
106 liveness: ?Air.Liveness,
107 indent: usize,
108 skip_body: bool,
109
110 const Error = std.Io.Writer.Error;
111
112 fn writeBody(w: *Writer, s: *std.Io.Writer, body: []const Air.Inst.Index) Error!void {
113 for (body) |inst| {
114 try w.writeInst(s, inst);
115 try s.writeByte('\n');
116 }
117 }
118
119 fn writeInst(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
120 const tag = w.air.instructions.items(.tag)[@backingInt(inst)];
121 try s.splatByteAll(' ', w.indent);
122 try s.print("{f}{c}= {s}(", .{
123 inst,
124 @as(u8, if (if (w.liveness) |liveness| liveness.isUnused(inst) else false) '!' else ' '),
125 @tagName(tag),
126 });
127 switch (tag) {
128 .add,
129 .add_optimized,
130 .add_safe,
131 .add_wrap,
132 .add_sat,
133 .sub,
134 .sub_optimized,
135 .sub_safe,
136 .sub_wrap,
137 .sub_sat,
138 .mul,
139 .mul_optimized,
140 .mul_safe,
141 .mul_wrap,
142 .mul_sat,
143 .div_float,
144 .div_trunc,
145 .div_floor,
146 .div_ceil,
147 .div_exact,
148 .rem,
149 .mod,
150 .bit_and,
151 .bit_or,
152 .xor,
153 .cmp_lt,
154 .cmp_lte,
155 .cmp_eq,
156 .cmp_gte,
157 .cmp_gt,
158 .cmp_neq,
159 .store,
160 .store_safe,
161 .array_elem_val,
162 .slice_elem_val,
163 .ptr_elem_val,
164 .shl,
165 .shl_exact,
166 .shl_sat,
167 .shr,
168 .shr_exact,
169 .set_union_tag,
170 .min,
171 .max,
172 .div_float_optimized,
173 .div_trunc_optimized,
174 .div_floor_optimized,
175 .div_ceil_optimized,
176 .div_exact_optimized,
177 .rem_optimized,
178 .mod_optimized,
179 .cmp_lt_optimized,
180 .cmp_lte_optimized,
181 .cmp_eq_optimized,
182 .cmp_gte_optimized,
183 .cmp_gt_optimized,
184 .cmp_neq_optimized,
185 .memcpy,
186 .memmove,
187 .memset,
188 .memset_safe,
189 .legalize_vec_elem_val,
190 => try w.writeBinOp(s, inst),
191
192 .is_null,
193 .is_non_null,
194 .is_null_ptr,
195 .is_non_null_ptr,
196 .is_err,
197 .is_non_err,
198 .is_err_ptr,
199 .is_non_err_ptr,
200 .ret,
201 .ret_safe,
202 .ret_load,
203 .is_named_enum_value,
204 .tag_name,
205 .error_name,
206 .sqrt,
207 .sin,
208 .cos,
209 .tan,
210 .exp,
211 .exp2,
212 .log,
213 .log2,
214 .log10,
215 .floor,
216 .ceil,
217 .round,
218 .trunc_float,
219 .neg,
220 .neg_optimized,
221 .cmp_lte_errors_len,
222 .set_err_return_trace,
223 .c_va_end,
224 => try w.writeUnOp(s, inst),
225
226 .trap,
227 .breakpoint,
228 .dbg_empty_stmt,
229 .unreach,
230 .ret_addr,
231 .frame_addr,
232 .save_err_return_trace_index,
233 => try w.writeNoOp(s, inst),
234
235 .alloc,
236 .ret_ptr,
237 .err_return_trace,
238 .c_va_start,
239 => try w.writeTy(s, inst),
240
241 .arg => try w.writeArg(s, inst),
242
243 .not,
244 .bit_cast,
245 .bit_cast_safe,
246 .ptr_cast,
247 .ptr_from_int,
248 .int_from_ptr,
249 .error_cast,
250 .error_from_int,
251 .int_from_error,
252 .union_from_enum,
253 .load,
254 .fptrunc,
255 .fpext,
256 .int_cast,
257 .int_cast_safe,
258 .trunc,
259 .optional_payload,
260 .optional_payload_ptr,
261 .optional_payload_ptr_set,
262 .errunion_payload_ptr_set,
263 .wrap_optional,
264 .unwrap_errunion_payload,
265 .unwrap_errunion_err,
266 .unwrap_errunion_payload_ptr,
267 .unwrap_errunion_err_ptr,
268 .wrap_errunion_payload,
269 .wrap_errunion_err,
270 .slice_ptr,
271 .slice_len,
272 .ptr_slice_len_ptr,
273 .ptr_slice_ptr_ptr,
274 .struct_field_ptr_index_0,
275 .struct_field_ptr_index_1,
276 .struct_field_ptr_index_2,
277 .struct_field_ptr_index_3,
278 .array_to_slice,
279 .array_to_vector,
280 .float_from_int,
281 .splat,
282 .int_from_float,
283 .int_from_float_optimized,
284 .int_from_float_safe,
285 .int_from_float_optimized_safe,
286 .get_union_tag,
287 .clz,
288 .ctz,
289 .popcount,
290 .byte_swap,
291 .bit_reverse,
292 .abs,
293 .error_set_has_value,
294 .addrspace_cast,
295 .c_va_arg,
296 .c_va_copy,
297 => try w.writeTyOp(s, inst),
298
299 .block, .dbg_inline_block => try w.writeBlock(s, tag, inst),
300
301 .loop => try w.writeLoop(s, inst),
302
303 .slice,
304 .slice_elem_ptr,
305 .ptr_elem_ptr,
306 .ptr_add,
307 .ptr_sub,
308 .add_with_overflow,
309 .sub_with_overflow,
310 .mul_with_overflow,
311 .shl_with_overflow,
312 => try w.writeTyPlBin(s, inst),
313
314 .call,
315 .call_always_tail,
316 .call_never_tail,
317 .call_never_inline,
318 => try w.writeCall(s, inst),
319
320 .dbg_var_ptr,
321 .dbg_var_val,
322 .dbg_arg_inline,
323 => try w.writeDbgVar(s, inst),
324
325 .struct_field_ptr => try w.writeStructField(s, inst),
326 .agg_field_val => try w.writeStructField(s, inst),
327 .spirv_runtime_array_len => try w.writeStructField(s, inst),
328 .inferred_alloc => @panic("TODO"),
329 .inferred_alloc_comptime => @panic("TODO"),
330 .assembly => try w.writeAssembly(s, inst),
331 .dbg_stmt => try w.writeDbgStmt(s, inst),
332
333 .aggregate_init => try w.writeAggregateInit(s, inst),
334 .union_init => try w.writeUnionInit(s, inst),
335 .br => try w.writeBr(s, inst),
336 .switch_dispatch => try w.writeBr(s, inst),
337 .repeat => try w.writeRepeat(s, inst),
338 .cond_br => try w.writeCondBr(s, inst),
339 .@"try", .try_cold => try w.writeTry(s, inst),
340 .try_ptr, .try_ptr_cold => try w.writeTryPtr(s, inst),
341 .loop_switch_br, .switch_br => try w.writeSwitchBr(s, inst),
342 .cmpxchg_weak, .cmpxchg_strong => try w.writeCmpxchg(s, inst),
343 .atomic_load => try w.writeAtomicLoad(s, inst),
344 .prefetch => try w.writePrefetch(s, inst),
345 .atomic_store_unordered => try w.writeAtomicStore(s, inst, .unordered),
346 .atomic_store_monotonic => try w.writeAtomicStore(s, inst, .monotonic),
347 .atomic_store_release => try w.writeAtomicStore(s, inst, .release),
348 .atomic_store_seq_cst => try w.writeAtomicStore(s, inst, .seq_cst),
349 .atomic_rmw => try w.writeAtomicRmw(s, inst),
350 .field_parent_ptr => try w.writeFieldParentPtr(s, inst),
351 .wasm_memory_size => try w.writeWasmMemorySize(s, inst),
352 .wasm_memory_grow => try w.writeWasmMemoryGrow(s, inst),
353 .mul_add => try w.writeMulAdd(s, inst),
354 .select => try w.writeSelect(s, inst),
355 .shuffle_one => try w.writeShuffleOne(s, inst),
356 .shuffle_two => try w.writeShuffleTwo(s, inst),
357 .reduce, .reduce_optimized => try w.writeReduce(s, inst),
358 .cmp_vector, .cmp_vector_optimized => try w.writeCmpVector(s, inst),
359 .runtime_nav_ptr => try w.writeRuntimeNavPtr(s, inst),
360 .legalize_vec_store_elem => try w.writeLegalizeVecStoreElem(s, inst),
361 .legalize_compiler_rt_call => try w.writeLegalizeCompilerRtCall(s, inst),
362
363 .work_item_id,
364 .work_group_size,
365 .work_group_id,
366 => try w.writeWorkDimension(s, inst),
367 }
368 try s.writeByte(')');
369 }
370
371 fn writeBinOp(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
372 const bin_op = w.air.instructions.items(.data)[@backingInt(inst)].bin_op;
373 try w.writeOperand(s, inst, 0, bin_op.lhs);
374 try s.writeAll(", ");
375 try w.writeOperand(s, inst, 1, bin_op.rhs);
376 }
377
378 fn writeUnOp(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
379 const un_op = w.air.instructions.items(.data)[@backingInt(inst)].un_op;
380 try w.writeOperand(s, inst, 0, un_op);
381 }
382
383 fn writeNoOp(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
384 _ = w;
385 _ = s;
386 _ = inst;
387 // no-op, no argument to write
388 }
389
390 fn writeType(w: *Writer, s: *std.Io.Writer, ty: Type) !void {
391 return ty.print(s, w.zcu, null);
392 }
393
394 fn writeTy(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
395 const ty = w.air.instructions.items(.data)[@backingInt(inst)].ty;
396 try w.writeType(s, ty);
397 }
398
399 fn writeArg(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
400 const arg = w.air.instructions.items(.data)[@backingInt(inst)].arg;
401 try w.writeType(s, arg.ty);
402 try s.print(", {d}", .{arg.zir_param_index});
403 }
404
405 fn writeTyOp(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
406 const ty_op = w.air.instructions.items(.data)[@backingInt(inst)].ty_op;
407 try w.writeType(s, ty_op.ty);
408 try s.writeAll(", ");
409 try w.writeOperand(s, inst, 0, ty_op.operand);
410 }
411
412 fn writeBlock(w: *Writer, s: *std.Io.Writer, tag: Air.Inst.Tag, inst: Air.Inst.Index) Error!void {
413 const ty_pl = w.air.instructions.items(.data)[@backingInt(inst)].ty_pl;
414 try w.writeType(s, ty_pl.ty);
415
416 const body = switch (tag) {
417 .block => w.air.unwrapBlock(inst).body,
418 .dbg_inline_block => body: {
419 const dbg_block = w.air.unwrapDbgBlock(inst);
420 try s.writeAll(", ");
421 try w.writeInstRef(s, Air.internedToRef(dbg_block.func), false);
422 break :body dbg_block.body;
423 },
424 else => unreachable,
425 };
426 if (w.skip_body) return s.writeAll(", ...");
427 const liveness_block: Air.Liveness.BlockSlices = if (w.liveness) |liveness|
428 liveness.getBlock(inst)
429 else
430 .{ .deaths = &.{} };
431
432 try s.writeAll(", {\n");
433 const old_indent = w.indent;
434 w.indent += 2;
435 try w.writeBody(s, body);
436 w.indent = old_indent;
437 try s.splatByteAll(' ', w.indent);
438 try s.writeAll("}");
439
440 for (liveness_block.deaths) |operand| {
441 try s.print(" {f}!", .{operand});
442 }
443 }
444
445 fn writeLoop(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
446 const block = w.air.unwrapBlock(inst);
447
448 try w.writeType(s, block.ty);
449 if (w.skip_body) return s.writeAll(", ...");
450 try s.writeAll(", {\n");
451 const old_indent = w.indent;
452 w.indent += 2;
453 try w.writeBody(s, block.body);
454 w.indent = old_indent;
455 try s.splatByteAll(' ', w.indent);
456 try s.writeAll("}");
457 }
458
459 fn writeAggregateInit(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
460 const zcu = w.zcu;
461 const ty_pl = w.air.instructions.items(.data)[@backingInt(inst)].ty_pl;
462 const vector_ty = ty_pl.ty;
463 const len = @as(usize, @intCast(vector_ty.arrayLen(zcu)));
464 const elements = @as([]const Air.Inst.Ref, @ptrCast(w.air.extra.items[ty_pl.payload..][0..len]));
465
466 try w.writeType(s, vector_ty);
467 try s.writeAll(", [");
468 for (elements, 0..) |elem, i| {
469 if (i != 0) try s.writeAll(", ");
470 try w.writeOperand(s, inst, i, elem);
471 }
472 try s.writeAll("]");
473 }
474
475 fn writeUnionInit(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
476 const ty_pl = w.air.instructions.items(.data)[@backingInt(inst)].ty_pl;
477 const extra = w.air.extraData(Air.UnionInit, ty_pl.payload).data;
478
479 try s.print("{d}, ", .{extra.field_index});
480 try w.writeOperand(s, inst, 0, extra.init);
481 }
482
483 fn writeStructField(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
484 const ty_pl = w.air.instructions.items(.data)[@backingInt(inst)].ty_pl;
485 const extra = w.air.extraData(Air.StructField, ty_pl.payload).data;
486
487 try w.writeOperand(s, inst, 0, extra.struct_operand);
488 try s.print(", {d}", .{extra.field_index});
489 }
490
491 fn writeTyPlBin(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
492 const data = w.air.instructions.items(.data);
493 const ty_pl = data[@backingInt(inst)].ty_pl;
494 const extra = w.air.extraData(Air.Bin, ty_pl.payload).data;
495
496 const inst_ty = data[@backingInt(inst)].ty_pl.ty;
497 try w.writeType(s, inst_ty);
498 try s.writeAll(", ");
499 try w.writeOperand(s, inst, 0, extra.lhs);
500 try s.writeAll(", ");
501 try w.writeOperand(s, inst, 1, extra.rhs);
502 }
503
504 fn writeCmpxchg(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
505 const ty_pl = w.air.instructions.items(.data)[@backingInt(inst)].ty_pl;
506 const extra = w.air.extraData(Air.Cmpxchg, ty_pl.payload).data;
507
508 try w.writeOperand(s, inst, 0, extra.ptr);
509 try s.writeAll(", ");
510 try w.writeOperand(s, inst, 1, extra.expected_value);
511 try s.writeAll(", ");
512 try w.writeOperand(s, inst, 2, extra.new_value);
513 try s.print(", {s}, {s}", .{
514 @tagName(extra.successOrder()), @tagName(extra.failureOrder()),
515 });
516 }
517
518 fn writeMulAdd(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
519 const pl_op = w.air.instructions.items(.data)[@backingInt(inst)].pl_op;
520 const extra = w.air.extraData(Air.Bin, pl_op.payload).data;
521
522 try w.writeOperand(s, inst, 0, extra.lhs);
523 try s.writeAll(", ");
524 try w.writeOperand(s, inst, 1, extra.rhs);
525 try s.writeAll(", ");
526 try w.writeOperand(s, inst, 2, pl_op.operand);
527 }
528
529 fn writeLegalizeVecStoreElem(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
530 const pl_op = w.air.instructions.items(.data)[@backingInt(inst)].pl_op;
531 const bin = w.air.extraData(Air.Bin, pl_op.payload).data;
532
533 try w.writeOperand(s, inst, 0, pl_op.operand);
534 try s.writeAll(", ");
535 try w.writeOperand(s, inst, 1, bin.lhs);
536 try s.writeAll(", ");
537 try w.writeOperand(s, inst, 2, bin.rhs);
538 }
539
540 fn writeLegalizeCompilerRtCall(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
541 const rt_call = w.air.unwrapCompilerRtCall(inst);
542 const args = rt_call.args;
543
544 try s.print("{t}, [", .{rt_call.func});
545 for (args, 0..) |arg, i| {
546 if (i != 0) try s.writeAll(", ");
547 try w.writeOperand(s, inst, i, arg);
548 }
549 try s.writeByte(']');
550 }
551
552 fn writeShuffleOne(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
553 const unwrapped = w.air.unwrapShuffleOne(w.zcu, inst);
554 try w.writeType(s, unwrapped.result_ty);
555 try s.writeAll(", ");
556 try w.writeOperand(s, inst, 0, unwrapped.operand);
557 try s.writeAll(", [");
558 for (unwrapped.mask, 0..) |mask_elem, mask_idx| {
559 if (mask_idx > 0) try s.writeAll(", ");
560 switch (mask_elem.unwrap()) {
561 .elem => |idx| try s.print("elem {d}", .{idx}),
562 .value => |val| try s.print("val {f}", .{Value.fromInterned(val).fmtValue(w.zcu)}),
563 }
564 }
565 try s.writeByte(']');
566 }
567
568 fn writeShuffleTwo(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
569 const unwrapped = w.air.unwrapShuffleTwo(w.zcu, inst);
570 try w.writeType(s, unwrapped.result_ty);
571 try s.writeAll(", ");
572 try w.writeOperand(s, inst, 0, unwrapped.operand_a);
573 try s.writeAll(", ");
574 try w.writeOperand(s, inst, 1, unwrapped.operand_b);
575 try s.writeAll(", [");
576 for (unwrapped.mask, 0..) |mask_elem, mask_idx| {
577 if (mask_idx > 0) try s.writeAll(", ");
578 switch (mask_elem.unwrap()) {
579 .a_elem => |idx| try s.print("a_elem {d}", .{idx}),
580 .b_elem => |idx| try s.print("b_elem {d}", .{idx}),
581 .undef => try s.writeAll("undef"),
582 }
583 }
584 try s.writeByte(']');
585 }
586
587 fn writeSelect(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
588 const zcu = w.zcu;
589 const pl_op = w.air.instructions.items(.data)[@backingInt(inst)].pl_op;
590 const extra = w.air.extraData(Air.Bin, pl_op.payload).data;
591
592 const elem_ty = w.typeOfIndex(inst).childType(zcu);
593 try w.writeType(s, elem_ty);
594 try s.writeAll(", ");
595 try w.writeOperand(s, inst, 0, pl_op.operand);
596 try s.writeAll(", ");
597 try w.writeOperand(s, inst, 1, extra.lhs);
598 try s.writeAll(", ");
599 try w.writeOperand(s, inst, 2, extra.rhs);
600 }
601
602 fn writeReduce(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
603 const reduce = w.air.instructions.items(.data)[@backingInt(inst)].reduce;
604
605 try w.writeOperand(s, inst, 0, reduce.operand);
606 try s.print(", {s}", .{@tagName(reduce.operation)});
607 }
608
609 fn writeCmpVector(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
610 const ty_pl = w.air.instructions.items(.data)[@backingInt(inst)].ty_pl;
611 const extra = w.air.extraData(Air.VectorCmp, ty_pl.payload).data;
612
613 try s.print("{s}, ", .{@tagName(extra.compareOperator())});
614 try w.writeOperand(s, inst, 0, extra.lhs);
615 try s.writeAll(", ");
616 try w.writeOperand(s, inst, 1, extra.rhs);
617 }
618
619 fn writeRuntimeNavPtr(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
620 const ip = &w.zcu.intern_pool;
621 const ty_nav = w.air.instructions.items(.data)[@backingInt(inst)].ty_nav;
622 try w.writeType(s, ty_nav.ty);
623 try s.print(", '{f}'", .{ip.getNav(ty_nav.nav).fqn.fmt(ip)});
624 }
625
626 fn writeAtomicLoad(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
627 const atomic_load = w.air.instructions.items(.data)[@backingInt(inst)].atomic_load;
628
629 try w.writeOperand(s, inst, 0, atomic_load.ptr);
630 try s.print(", {s}", .{@tagName(atomic_load.order)});
631 }
632
633 fn writePrefetch(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
634 const prefetch = w.air.instructions.items(.data)[@backingInt(inst)].prefetch;
635
636 try w.writeOperand(s, inst, 0, prefetch.ptr);
637 try s.print(", {s}, {d}, {s}", .{
638 @tagName(prefetch.rw), prefetch.locality, @tagName(prefetch.cache),
639 });
640 }
641
642 fn writeAtomicStore(
643 w: *Writer,
644 s: *std.Io.Writer,
645 inst: Air.Inst.Index,
646 order: std.lang.AtomicOrder,
647 ) Error!void {
648 const bin_op = w.air.instructions.items(.data)[@backingInt(inst)].bin_op;
649 try w.writeOperand(s, inst, 0, bin_op.lhs);
650 try s.writeAll(", ");
651 try w.writeOperand(s, inst, 1, bin_op.rhs);
652 try s.print(", {s}", .{@tagName(order)});
653 }
654
655 fn writeAtomicRmw(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
656 const pl_op = w.air.instructions.items(.data)[@backingInt(inst)].pl_op;
657 const extra = w.air.extraData(Air.AtomicRmw, pl_op.payload).data;
658
659 try w.writeOperand(s, inst, 0, pl_op.operand);
660 try s.writeAll(", ");
661 try w.writeOperand(s, inst, 1, extra.operand);
662 try s.print(", {s}, {s}", .{ @tagName(extra.op()), @tagName(extra.ordering()) });
663 }
664
665 fn writeFieldParentPtr(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
666 const ty_pl = w.air.instructions.items(.data)[@backingInt(inst)].ty_pl;
667 const extra = w.air.extraData(Air.FieldParentPtr, ty_pl.payload).data;
668
669 try w.writeOperand(s, inst, 0, extra.field_ptr);
670 try s.print(", {d}", .{extra.field_index});
671 }
672
673 fn writeAssembly(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
674 const unwrapped_asm = w.air.unwrapAsm(inst);
675 const is_volatile = unwrapped_asm.is_volatile;
676 var op_index: usize = 0;
677
678 const ret_ty = w.typeOfIndex(inst);
679 try w.writeType(s, ret_ty);
680
681 if (is_volatile) {
682 try s.writeAll(", volatile");
683 }
684
685 var it = unwrapped_asm.iterateOutputs();
686 while (it.next()) |out| {
687 const name = out.name;
688 const constraint = out.constraint;
689 if (out.operand == .none) {
690 try s.print(", [{s}] -> {s}", .{ name, constraint });
691 } else {
692 try s.print(", [{s}] out {s} = (", .{ name, constraint });
693 try w.writeOperand(s, inst, op_index, out.operand);
694 op_index += 1;
695 try s.writeByte(')');
696 }
697 }
698
699 it = unwrapped_asm.iterateInputs();
700 while (it.next()) |in| {
701 const name = in.name;
702 const constraint = in.constraint;
703 try s.print(", [{s}] in {s} = (", .{ name, constraint });
704 try w.writeOperand(s, inst, op_index, in.operand);
705 op_index += 1;
706 try s.writeByte(')');
707 }
708
709 const zcu = w.zcu;
710 const ip = &zcu.intern_pool;
711 const clobbers_val: Value = .fromInterned(unwrapped_asm.clobbers);
712 const clobbers_ty = clobbers_val.typeOf(zcu);
713 var clobbers_bigint_buf: Value.BigIntSpace = undefined;
714 const clobbers_bigint = clobbers_val.toBigInt(&clobbers_bigint_buf, zcu);
715 for (0..clobbers_ty.structFieldCount(zcu)) |field_index| {
716 assert(clobbers_ty.fieldType(field_index, zcu).toIntern() == .bool_type);
717 const limb_bits = @bitSizeOf(std.math.big.Limb);
718 if (field_index / limb_bits >= clobbers_bigint.limbs.len) continue; // field is false
719 switch (@as(u1, @truncate(clobbers_bigint.limbs[field_index / limb_bits] >> @intCast(field_index % limb_bits)))) {
720 0 => continue, // field is false
721 1 => {}, // field is true
722 }
723 const clobber = clobbers_ty.structFieldName(field_index, zcu).toSlice(ip).?;
724 assert(clobber.len != 0);
725 try s.writeAll(", ~{");
726 try s.writeAll(clobber);
727 try s.writeAll("}");
728 }
729 const asm_source = unwrapped_asm.source;
730 try s.print(", \"{f}\"", .{std.zig.fmtString(asm_source)});
731 }
732
733 fn writeDbgStmt(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
734 const dbg_stmt = w.air.instructions.items(.data)[@backingInt(inst)].dbg_stmt;
735 try s.print("{d}:{d}", .{ dbg_stmt.line + 1, dbg_stmt.column + 1 });
736 }
737
738 fn writeDbgVar(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
739 const pl_op = w.air.instructions.items(.data)[@backingInt(inst)].pl_op;
740 try w.writeOperand(s, inst, 0, pl_op.operand);
741 const name: Air.NullTerminatedString = @fromBackingInt(@intCast(pl_op.payload));
742 try s.print(", \"{f}\"", .{std.zig.fmtString(name.toSlice(w.air))});
743 }
744
745 fn writeCall(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
746 const call = w.air.unwrapCall(inst);
747 const args = call.args;
748 try w.writeOperand(s, inst, 0, call.callee);
749 try s.writeAll(", [");
750 for (args, 0..) |arg, i| {
751 if (i != 0) try s.writeAll(", ");
752 try w.writeOperand(s, inst, 1 + i, arg);
753 }
754 try s.writeAll("]");
755 }
756
757 fn writeBr(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
758 const br = w.air.instructions.items(.data)[@backingInt(inst)].br;
759 try w.writeInstIndex(s, br.block_inst, false);
760 try s.writeAll(", ");
761 try w.writeOperand(s, inst, 0, br.operand);
762 }
763
764 fn writeRepeat(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
765 const repeat = w.air.instructions.items(.data)[@backingInt(inst)].repeat;
766 try w.writeInstIndex(s, repeat.loop_inst, false);
767 }
768
769 fn writeTry(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
770 const unwrapped_try = w.air.unwrapTry(inst);
771 const body = unwrapped_try.else_body;
772 const liveness_condbr: Air.Liveness.CondBrSlices = if (w.liveness) |liveness|
773 liveness.getCondBr(inst)
774 else
775 .{ .then_deaths = &.{}, .else_deaths = &.{} };
776
777 try w.writeOperand(s, inst, 0, unwrapped_try.error_union);
778 if (w.skip_body) return s.writeAll(", ...");
779 try s.writeAll(", {\n");
780 const old_indent = w.indent;
781 w.indent += 2;
782
783 if (liveness_condbr.else_deaths.len != 0) {
784 try s.splatByteAll(' ', w.indent);
785 for (liveness_condbr.else_deaths, 0..) |operand, i| {
786 if (i != 0) try s.writeAll(" ");
787 try s.print("{f}!", .{operand});
788 }
789 try s.writeAll("\n");
790 }
791 try w.writeBody(s, body);
792
793 w.indent = old_indent;
794 try s.splatByteAll(' ', w.indent);
795 try s.writeAll("}");
796
797 for (liveness_condbr.then_deaths) |operand| {
798 try s.print(" {f}!", .{operand});
799 }
800 }
801
802 fn writeTryPtr(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
803 const unwrapped_try = w.air.unwrapTryPtr(inst);
804 const body = unwrapped_try.else_body;
805 const liveness_condbr: Air.Liveness.CondBrSlices = if (w.liveness) |liveness|
806 liveness.getCondBr(inst)
807 else
808 .{ .then_deaths = &.{}, .else_deaths = &.{} };
809
810 try w.writeOperand(s, inst, 0, unwrapped_try.error_union_ptr);
811
812 try s.writeAll(", ");
813 try w.writeType(s, unwrapped_try.error_union_payload_ptr_ty);
814 if (w.skip_body) return s.writeAll(", ...");
815 try s.writeAll(", {\n");
816 const old_indent = w.indent;
817 w.indent += 2;
818
819 if (liveness_condbr.else_deaths.len != 0) {
820 try s.splatByteAll(' ', w.indent);
821 for (liveness_condbr.else_deaths, 0..) |operand, i| {
822 if (i != 0) try s.writeAll(" ");
823 try s.print("{f}!", .{operand});
824 }
825 try s.writeAll("\n");
826 }
827 try w.writeBody(s, body);
828
829 w.indent = old_indent;
830 try s.splatByteAll(' ', w.indent);
831 try s.writeAll("}");
832
833 for (liveness_condbr.then_deaths) |operand| {
834 try s.print(" {f}!", .{operand});
835 }
836 }
837
838 fn writeCondBr(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
839 const cond_br = w.air.unwrapCondBr(inst);
840 const then_body = cond_br.then_body;
841 const else_body = cond_br.else_body;
842 const liveness_condbr: Air.Liveness.CondBrSlices = if (w.liveness) |liveness|
843 liveness.getCondBr(inst)
844 else
845 .{ .then_deaths = &.{}, .else_deaths = &.{} };
846
847 try w.writeOperand(s, inst, 0, cond_br.condition);
848 if (w.skip_body) return s.writeAll(", ...");
849 try s.writeAll(",");
850 if (cond_br.branch_hints.true != .none) {
851 try s.print(" {s}", .{@tagName(cond_br.branch_hints.true)});
852 }
853 if (cond_br.branch_hints.then_cov != .none) {
854 try s.print(" {s}", .{@tagName(cond_br.branch_hints.then_cov)});
855 }
856 try s.writeAll(" {\n");
857 const old_indent = w.indent;
858 w.indent += 2;
859
860 if (liveness_condbr.then_deaths.len != 0) {
861 try s.splatByteAll(' ', w.indent);
862 for (liveness_condbr.then_deaths, 0..) |operand, i| {
863 if (i != 0) try s.writeAll(" ");
864 try s.print("{f}!", .{operand});
865 }
866 try s.writeAll("\n");
867 }
868
869 try w.writeBody(s, then_body);
870 try s.splatByteAll(' ', old_indent);
871 try s.writeAll("},");
872 if (cond_br.branch_hints.false != .none) {
873 try s.print(" {s}", .{@tagName(cond_br.branch_hints.false)});
874 }
875 if (cond_br.branch_hints.else_cov != .none) {
876 try s.print(" {s}", .{@tagName(cond_br.branch_hints.else_cov)});
877 }
878 try s.writeAll(" {\n");
879
880 if (liveness_condbr.else_deaths.len != 0) {
881 try s.splatByteAll(' ', w.indent);
882 for (liveness_condbr.else_deaths, 0..) |operand, i| {
883 if (i != 0) try s.writeAll(" ");
884 try s.print("{f}!", .{operand});
885 }
886 try s.writeAll("\n");
887 }
888
889 try w.writeBody(s, else_body);
890 w.indent = old_indent;
891
892 try s.splatByteAll(' ', old_indent);
893 try s.writeAll("}");
894 }
895
896 fn writeSwitchBr(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
897 const switch_br = w.air.unwrapSwitch(inst);
898
899 const liveness: Air.Liveness.SwitchBrTable = if (w.liveness) |liveness|
900 liveness.getSwitchBr(w.gpa, inst, switch_br.cases_len + 1) catch
901 @panic("out of memory")
902 else blk: {
903 const slice = w.gpa.alloc([]const Air.Inst.Index, switch_br.cases_len + 1) catch
904 @panic("out of memory");
905 @memset(slice, &.{});
906 break :blk .{ .deaths = slice };
907 };
908 defer w.gpa.free(liveness.deaths);
909
910 try w.writeOperand(s, inst, 0, switch_br.operand);
911 if (w.skip_body) return s.writeAll(", ...");
912 const old_indent = w.indent;
913 w.indent += 2;
914
915 var it = switch_br.iterateCases();
916 while (it.next()) |case| {
917 try s.writeAll(", [");
918 for (case.items, 0..) |item, item_i| {
919 if (item_i != 0) try s.writeAll(", ");
920 try w.writeInstRef(s, item, false);
921 }
922 for (case.ranges, 0..) |range, range_i| {
923 if (range_i != 0 or case.items.len != 0) try s.writeAll(", ");
924 try w.writeInstRef(s, range[0], false);
925 try s.writeAll("...");
926 try w.writeInstRef(s, range[1], false);
927 }
928 try s.writeAll("] ");
929 const hint = switch_br.getHint(case.idx);
930 if (hint != .none) {
931 try s.print(".{s} ", .{@tagName(hint)});
932 }
933 try s.writeAll("=> {\n");
934 w.indent += 2;
935
936 const deaths = liveness.deaths[case.idx];
937 if (deaths.len != 0) {
938 try s.splatByteAll(' ', w.indent);
939 for (deaths, 0..) |operand, i| {
940 if (i != 0) try s.writeAll(" ");
941 try s.print("{f}!", .{operand});
942 }
943 try s.writeAll("\n");
944 }
945
946 try w.writeBody(s, case.body);
947 w.indent -= 2;
948 try s.splatByteAll(' ', w.indent);
949 try s.writeAll("}");
950 }
951
952 const else_body = it.elseBody();
953 if (else_body.len != 0) {
954 try s.writeAll(", else ");
955 const hint = switch_br.getElseHint();
956 if (hint != .none) {
957 try s.print(".{s} ", .{@tagName(hint)});
958 }
959 try s.writeAll("=> {\n");
960 w.indent += 2;
961
962 const deaths = liveness.deaths[liveness.deaths.len - 1];
963 if (deaths.len != 0) {
964 try s.splatByteAll(' ', w.indent);
965 for (deaths, 0..) |operand, i| {
966 if (i != 0) try s.writeAll(" ");
967 try s.print("{f}!", .{operand});
968 }
969 try s.writeAll("\n");
970 }
971
972 try w.writeBody(s, else_body);
973 w.indent -= 2;
974 try s.splatByteAll(' ', w.indent);
975 try s.writeAll("}");
976 }
977
978 try s.writeAll("\n");
979 try s.splatByteAll(' ', old_indent);
980 }
981
982 fn writeWasmMemorySize(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
983 const pl_op = w.air.instructions.items(.data)[@backingInt(inst)].pl_op;
984 try s.print("{d}", .{pl_op.payload});
985 }
986
987 fn writeWasmMemoryGrow(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
988 const pl_op = w.air.instructions.items(.data)[@backingInt(inst)].pl_op;
989 try s.print("{d}, ", .{pl_op.payload});
990 try w.writeOperand(s, inst, 0, pl_op.operand);
991 }
992
993 fn writeWorkDimension(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
994 const pl_op = w.air.instructions.items(.data)[@backingInt(inst)].pl_op;
995 try s.print("{d}", .{pl_op.payload});
996 }
997
998 fn writeOperand(
999 w: *Writer,
1000 s: *std.Io.Writer,
1001 inst: Air.Inst.Index,
1002 op_index: usize,
1003 operand: Air.Inst.Ref,
1004 ) Error!void {
1005 const small_tomb_bits = Air.Liveness.bpi - 1;
1006 const dies = if (w.liveness) |liveness| blk: {
1007 if (op_index < small_tomb_bits)
1008 break :blk liveness.operandDies(inst, @intCast(op_index));
1009 var extra_index = liveness.special.get(inst).?;
1010 var tomb_op_index: usize = small_tomb_bits;
1011 while (true) {
1012 const bits = liveness.extra[extra_index];
1013 if (op_index < tomb_op_index + 31) {
1014 break :blk @as(u1, @truncate(bits >> @as(u5, @intCast(op_index - tomb_op_index)))) != 0;
1015 }
1016 if ((bits >> 31) != 0) break :blk false;
1017 extra_index += 1;
1018 tomb_op_index += 31;
1019 }
1020 } else false;
1021 return w.writeInstRef(s, operand, dies);
1022 }
1023
1024 fn writeInstRef(
1025 w: *Writer,
1026 s: *std.Io.Writer,
1027 operand: Air.Inst.Ref,
1028 dies: bool,
1029 ) Error!void {
1030 if (@backingInt(operand) < InternPool.static_len) {
1031 return s.print("@{}", .{operand});
1032 } else if (operand.toInterned()) |ip_index| {
1033 const zcu = w.zcu;
1034 const ty = Type.fromInterned(zcu.intern_pool.indexToKey(ip_index).typeOf());
1035 try s.print("<{f}, {f}>", .{
1036 ty.fmt(zcu),
1037 Value.fromInterned(ip_index).fmtValue(w.zcu),
1038 });
1039 } else {
1040 return w.writeInstIndex(s, operand.toIndex().?, dies);
1041 }
1042 }
1043
1044 fn writeInstIndex(
1045 w: *Writer,
1046 s: *std.Io.Writer,
1047 inst: Air.Inst.Index,
1048 dies: bool,
1049 ) Error!void {
1050 _ = w;
1051 try s.print("{f}", .{inst});
1052 if (dies) try s.writeByte('!');
1053 }
1054
1055 fn typeOfIndex(w: *Writer, inst: Air.Inst.Index) Type {
1056 const zcu = w.zcu;
1057 return w.air.typeOfIndex(inst, &zcu.intern_pool);
1058 }
1059};
src/Air/print.zig deleted-1048
...@@ -1,1048 +0,0 @@
1const std = @import("std");
2const Allocator = std.mem.Allocator;
3const assert = std.debug.assert;
4
5const build_options = @import("build_options");
6const Zcu = @import("../Zcu.zig");
7const Value = @import("../Value.zig");
8const Type = @import("../Type.zig");
9const Air = @import("../Air.zig");
10const InternPool = @import("../InternPool.zig");
11
12pub fn write(air: Air, stream: *std.Io.Writer, zcu: *Zcu, liveness: ?Air.Liveness) !void {
13 comptime assert(build_options.enable_debug_extensions);
14 const instruction_bytes = air.instructions.len *
15 // Here we don't use @sizeOf(Air.Inst.Data) because it would include
16 // the debug safety tag but we want to measure release size.
17 (@sizeOf(Air.Inst.Tag) + 8);
18 const extra_bytes = air.extra.items.len * @sizeOf(u32);
19 const tomb_bytes = if (liveness) |l| l.tomb_bits.len * @sizeOf(usize) else 0;
20 const liveness_extra_bytes = if (liveness) |l| l.extra.len * @sizeOf(u32) else 0;
21 const liveness_special_bytes = if (liveness) |l| l.special.count() * 8 else 0;
22 const total_bytes = @sizeOf(Air) + instruction_bytes + extra_bytes +
23 @sizeOf(Air.Liveness) + liveness_extra_bytes +
24 liveness_special_bytes + tomb_bytes;
25
26 // zig fmt: off
27 try stream.print(
28 \\# Total AIR+Liveness bytes: {Bi}
29 \\# AIR Instructions: {d} ({Bi})
30 \\# AIR Extra Data: {d} ({Bi})
31 \\# Liveness tomb_bits: {Bi}
32 \\# Liveness Extra Data: {d} ({Bi})
33 \\# Liveness special table: {d} ({Bi})
34 \\
35 , .{
36 total_bytes,
37 air.instructions.len, instruction_bytes,
38 air.extra.items.len, extra_bytes,
39 tomb_bytes,
40 if (liveness) |l| l.extra.len else 0, liveness_extra_bytes,
41 if (liveness) |l| l.special.count() else 0, liveness_special_bytes,
42 });
43 // zig fmt: on
44
45 var writer: Writer = .{
46 .zcu = zcu,
47 .gpa = zcu.comp.gpa,
48 .air = air,
49 .liveness = liveness,
50 .indent = 2,
51 .skip_body = false,
52 };
53 try writer.writeBody(stream, air.getMainBody());
54}
55
56pub fn writeInst(
57 air: Air,
58 stream: *std.Io.Writer,
59 inst: Air.Inst.Index,
60 zcu: *Zcu,
61 liveness: ?Air.Liveness,
62) void {
63 comptime assert(build_options.enable_debug_extensions);
64 var writer: Writer = .{
65 .zcu = zcu,
66 .gpa = zcu.comp.gpa,
67 .air = air,
68 .liveness = liveness,
69 .indent = 2,
70 .skip_body = true,
71 };
72 writer.writeInst(stream, inst) catch return;
73}
74
75pub fn dump(air: Air, pt: Zcu.PerThread, liveness: ?Air.Liveness) void {
76 var buffer: [4096]u8 = undefined;
77 const stderr = std.debug.lockStderr(&buffer);
78 defer std.debug.unlockStderr();
79 const w = &stderr.file_writer.interface;
80 air.write(w, pt, liveness) catch return;
81}
82
83pub fn dumpInst(air: Air, inst: Air.Inst.Index, pt: Zcu.PerThread, liveness: ?Air.Liveness) void {
84 var buffer: [4096]u8 = undefined;
85 const stderr = std.debug.lockStderr(&buffer);
86 defer std.debug.unlockStderr();
87 const w = &stderr.file_writer.interface;
88 air.writeInst(w, inst, pt, liveness) catch return;
89}
90
91const Writer = struct {
92 zcu: *Zcu,
93 gpa: Allocator,
94 air: Air,
95 liveness: ?Air.Liveness,
96 indent: usize,
97 skip_body: bool,
98
99 const Error = std.Io.Writer.Error;
100
101 fn writeBody(w: *Writer, s: *std.Io.Writer, body: []const Air.Inst.Index) Error!void {
102 for (body) |inst| {
103 try w.writeInst(s, inst);
104 try s.writeByte('\n');
105 }
106 }
107
108 fn writeInst(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
109 const tag = w.air.instructions.items(.tag)[@backingInt(inst)];
110 try s.splatByteAll(' ', w.indent);
111 try s.print("{f}{c}= {s}(", .{
112 inst,
113 @as(u8, if (if (w.liveness) |liveness| liveness.isUnused(inst) else false) '!' else ' '),
114 @tagName(tag),
115 });
116 switch (tag) {
117 .add,
118 .add_optimized,
119 .add_safe,
120 .add_wrap,
121 .add_sat,
122 .sub,
123 .sub_optimized,
124 .sub_safe,
125 .sub_wrap,
126 .sub_sat,
127 .mul,
128 .mul_optimized,
129 .mul_safe,
130 .mul_wrap,
131 .mul_sat,
132 .div_float,
133 .div_trunc,
134 .div_floor,
135 .div_ceil,
136 .div_exact,
137 .rem,
138 .mod,
139 .bit_and,
140 .bit_or,
141 .xor,
142 .cmp_lt,
143 .cmp_lte,
144 .cmp_eq,
145 .cmp_gte,
146 .cmp_gt,
147 .cmp_neq,
148 .store,
149 .store_safe,
150 .array_elem_val,
151 .slice_elem_val,
152 .ptr_elem_val,
153 .shl,
154 .shl_exact,
155 .shl_sat,
156 .shr,
157 .shr_exact,
158 .set_union_tag,
159 .min,
160 .max,
161 .div_float_optimized,
162 .div_trunc_optimized,
163 .div_floor_optimized,
164 .div_ceil_optimized,
165 .div_exact_optimized,
166 .rem_optimized,
167 .mod_optimized,
168 .cmp_lt_optimized,
169 .cmp_lte_optimized,
170 .cmp_eq_optimized,
171 .cmp_gte_optimized,
172 .cmp_gt_optimized,
173 .cmp_neq_optimized,
174 .memcpy,
175 .memmove,
176 .memset,
177 .memset_safe,
178 .legalize_vec_elem_val,
179 => try w.writeBinOp(s, inst),
180
181 .is_null,
182 .is_non_null,
183 .is_null_ptr,
184 .is_non_null_ptr,
185 .is_err,
186 .is_non_err,
187 .is_err_ptr,
188 .is_non_err_ptr,
189 .ret,
190 .ret_safe,
191 .ret_load,
192 .is_named_enum_value,
193 .tag_name,
194 .error_name,
195 .sqrt,
196 .sin,
197 .cos,
198 .tan,
199 .exp,
200 .exp2,
201 .log,
202 .log2,
203 .log10,
204 .floor,
205 .ceil,
206 .round,
207 .trunc_float,
208 .neg,
209 .neg_optimized,
210 .cmp_lte_errors_len,
211 .set_err_return_trace,
212 .c_va_end,
213 => try w.writeUnOp(s, inst),
214
215 .trap,
216 .breakpoint,
217 .dbg_empty_stmt,
218 .unreach,
219 .ret_addr,
220 .frame_addr,
221 .save_err_return_trace_index,
222 => try w.writeNoOp(s, inst),
223
224 .alloc,
225 .ret_ptr,
226 .err_return_trace,
227 .c_va_start,
228 => try w.writeTy(s, inst),
229
230 .arg => try w.writeArg(s, inst),
231
232 .not,
233 .bit_cast,
234 .bit_cast_safe,
235 .ptr_cast,
236 .ptr_from_int,
237 .int_from_ptr,
238 .error_cast,
239 .error_from_int,
240 .int_from_error,
241 .union_from_enum,
242 .load,
243 .fptrunc,
244 .fpext,
245 .int_cast,
246 .int_cast_safe,
247 .trunc,
248 .optional_payload,
249 .optional_payload_ptr,
250 .optional_payload_ptr_set,
251 .errunion_payload_ptr_set,
252 .wrap_optional,
253 .unwrap_errunion_payload,
254 .unwrap_errunion_err,
255 .unwrap_errunion_payload_ptr,
256 .unwrap_errunion_err_ptr,
257 .wrap_errunion_payload,
258 .wrap_errunion_err,
259 .slice_ptr,
260 .slice_len,
261 .ptr_slice_len_ptr,
262 .ptr_slice_ptr_ptr,
263 .struct_field_ptr_index_0,
264 .struct_field_ptr_index_1,
265 .struct_field_ptr_index_2,
266 .struct_field_ptr_index_3,
267 .array_to_slice,
268 .array_to_vector,
269 .float_from_int,
270 .splat,
271 .int_from_float,
272 .int_from_float_optimized,
273 .int_from_float_safe,
274 .int_from_float_optimized_safe,
275 .get_union_tag,
276 .clz,
277 .ctz,
278 .popcount,
279 .byte_swap,
280 .bit_reverse,
281 .abs,
282 .error_set_has_value,
283 .addrspace_cast,
284 .c_va_arg,
285 .c_va_copy,
286 => try w.writeTyOp(s, inst),
287
288 .block, .dbg_inline_block => try w.writeBlock(s, tag, inst),
289
290 .loop => try w.writeLoop(s, inst),
291
292 .slice,
293 .slice_elem_ptr,
294 .ptr_elem_ptr,
295 .ptr_add,
296 .ptr_sub,
297 .add_with_overflow,
298 .sub_with_overflow,
299 .mul_with_overflow,
300 .shl_with_overflow,
301 => try w.writeTyPlBin(s, inst),
302
303 .call,
304 .call_always_tail,
305 .call_never_tail,
306 .call_never_inline,
307 => try w.writeCall(s, inst),
308
309 .dbg_var_ptr,
310 .dbg_var_val,
311 .dbg_arg_inline,
312 => try w.writeDbgVar(s, inst),
313
314 .struct_field_ptr => try w.writeStructField(s, inst),
315 .agg_field_val => try w.writeStructField(s, inst),
316 .spirv_runtime_array_len => try w.writeStructField(s, inst),
317 .inferred_alloc => @panic("TODO"),
318 .inferred_alloc_comptime => @panic("TODO"),
319 .assembly => try w.writeAssembly(s, inst),
320 .dbg_stmt => try w.writeDbgStmt(s, inst),
321
322 .aggregate_init => try w.writeAggregateInit(s, inst),
323 .union_init => try w.writeUnionInit(s, inst),
324 .br => try w.writeBr(s, inst),
325 .switch_dispatch => try w.writeBr(s, inst),
326 .repeat => try w.writeRepeat(s, inst),
327 .cond_br => try w.writeCondBr(s, inst),
328 .@"try", .try_cold => try w.writeTry(s, inst),
329 .try_ptr, .try_ptr_cold => try w.writeTryPtr(s, inst),
330 .loop_switch_br, .switch_br => try w.writeSwitchBr(s, inst),
331 .cmpxchg_weak, .cmpxchg_strong => try w.writeCmpxchg(s, inst),
332 .atomic_load => try w.writeAtomicLoad(s, inst),
333 .prefetch => try w.writePrefetch(s, inst),
334 .atomic_store_unordered => try w.writeAtomicStore(s, inst, .unordered),
335 .atomic_store_monotonic => try w.writeAtomicStore(s, inst, .monotonic),
336 .atomic_store_release => try w.writeAtomicStore(s, inst, .release),
337 .atomic_store_seq_cst => try w.writeAtomicStore(s, inst, .seq_cst),
338 .atomic_rmw => try w.writeAtomicRmw(s, inst),
339 .field_parent_ptr => try w.writeFieldParentPtr(s, inst),
340 .wasm_memory_size => try w.writeWasmMemorySize(s, inst),
341 .wasm_memory_grow => try w.writeWasmMemoryGrow(s, inst),
342 .mul_add => try w.writeMulAdd(s, inst),
343 .select => try w.writeSelect(s, inst),
344 .shuffle_one => try w.writeShuffleOne(s, inst),
345 .shuffle_two => try w.writeShuffleTwo(s, inst),
346 .reduce, .reduce_optimized => try w.writeReduce(s, inst),
347 .cmp_vector, .cmp_vector_optimized => try w.writeCmpVector(s, inst),
348 .runtime_nav_ptr => try w.writeRuntimeNavPtr(s, inst),
349 .legalize_vec_store_elem => try w.writeLegalizeVecStoreElem(s, inst),
350 .legalize_compiler_rt_call => try w.writeLegalizeCompilerRtCall(s, inst),
351
352 .work_item_id,
353 .work_group_size,
354 .work_group_id,
355 => try w.writeWorkDimension(s, inst),
356 }
357 try s.writeByte(')');
358 }
359
360 fn writeBinOp(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
361 const bin_op = w.air.instructions.items(.data)[@backingInt(inst)].bin_op;
362 try w.writeOperand(s, inst, 0, bin_op.lhs);
363 try s.writeAll(", ");
364 try w.writeOperand(s, inst, 1, bin_op.rhs);
365 }
366
367 fn writeUnOp(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
368 const un_op = w.air.instructions.items(.data)[@backingInt(inst)].un_op;
369 try w.writeOperand(s, inst, 0, un_op);
370 }
371
372 fn writeNoOp(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
373 _ = w;
374 _ = s;
375 _ = inst;
376 // no-op, no argument to write
377 }
378
379 fn writeType(w: *Writer, s: *std.Io.Writer, ty: Type) !void {
380 return ty.print(s, w.zcu, null);
381 }
382
383 fn writeTy(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
384 const ty = w.air.instructions.items(.data)[@backingInt(inst)].ty;
385 try w.writeType(s, ty);
386 }
387
388 fn writeArg(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
389 const arg = w.air.instructions.items(.data)[@backingInt(inst)].arg;
390 try w.writeType(s, arg.ty);
391 try s.print(", {d}", .{arg.zir_param_index});
392 }
393
394 fn writeTyOp(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
395 const ty_op = w.air.instructions.items(.data)[@backingInt(inst)].ty_op;
396 try w.writeType(s, ty_op.ty);
397 try s.writeAll(", ");
398 try w.writeOperand(s, inst, 0, ty_op.operand);
399 }
400
401 fn writeBlock(w: *Writer, s: *std.Io.Writer, tag: Air.Inst.Tag, inst: Air.Inst.Index) Error!void {
402 const ty_pl = w.air.instructions.items(.data)[@backingInt(inst)].ty_pl;
403 try w.writeType(s, ty_pl.ty);
404
405 const body = switch (tag) {
406 .block => w.air.unwrapBlock(inst).body,
407 .dbg_inline_block => body: {
408 const dbg_block = w.air.unwrapDbgBlock(inst);
409 try s.writeAll(", ");
410 try w.writeInstRef(s, Air.internedToRef(dbg_block.func), false);
411 break :body dbg_block.body;
412 },
413 else => unreachable,
414 };
415 if (w.skip_body) return s.writeAll(", ...");
416 const liveness_block: Air.Liveness.BlockSlices = if (w.liveness) |liveness|
417 liveness.getBlock(inst)
418 else
419 .{ .deaths = &.{} };
420
421 try s.writeAll(", {\n");
422 const old_indent = w.indent;
423 w.indent += 2;
424 try w.writeBody(s, body);
425 w.indent = old_indent;
426 try s.splatByteAll(' ', w.indent);
427 try s.writeAll("}");
428
429 for (liveness_block.deaths) |operand| {
430 try s.print(" {f}!", .{operand});
431 }
432 }
433
434 fn writeLoop(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
435 const block = w.air.unwrapBlock(inst);
436
437 try w.writeType(s, block.ty);
438 if (w.skip_body) return s.writeAll(", ...");
439 try s.writeAll(", {\n");
440 const old_indent = w.indent;
441 w.indent += 2;
442 try w.writeBody(s, block.body);
443 w.indent = old_indent;
444 try s.splatByteAll(' ', w.indent);
445 try s.writeAll("}");
446 }
447
448 fn writeAggregateInit(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
449 const zcu = w.zcu;
450 const ty_pl = w.air.instructions.items(.data)[@backingInt(inst)].ty_pl;
451 const vector_ty = ty_pl.ty;
452 const len = @as(usize, @intCast(vector_ty.arrayLen(zcu)));
453 const elements = @as([]const Air.Inst.Ref, @ptrCast(w.air.extra.items[ty_pl.payload..][0..len]));
454
455 try w.writeType(s, vector_ty);
456 try s.writeAll(", [");
457 for (elements, 0..) |elem, i| {
458 if (i != 0) try s.writeAll(", ");
459 try w.writeOperand(s, inst, i, elem);
460 }
461 try s.writeAll("]");
462 }
463
464 fn writeUnionInit(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
465 const ty_pl = w.air.instructions.items(.data)[@backingInt(inst)].ty_pl;
466 const extra = w.air.extraData(Air.UnionInit, ty_pl.payload).data;
467
468 try s.print("{d}, ", .{extra.field_index});
469 try w.writeOperand(s, inst, 0, extra.init);
470 }
471
472 fn writeStructField(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
473 const ty_pl = w.air.instructions.items(.data)[@backingInt(inst)].ty_pl;
474 const extra = w.air.extraData(Air.StructField, ty_pl.payload).data;
475
476 try w.writeOperand(s, inst, 0, extra.struct_operand);
477 try s.print(", {d}", .{extra.field_index});
478 }
479
480 fn writeTyPlBin(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
481 const data = w.air.instructions.items(.data);
482 const ty_pl = data[@backingInt(inst)].ty_pl;
483 const extra = w.air.extraData(Air.Bin, ty_pl.payload).data;
484
485 const inst_ty = data[@backingInt(inst)].ty_pl.ty;
486 try w.writeType(s, inst_ty);
487 try s.writeAll(", ");
488 try w.writeOperand(s, inst, 0, extra.lhs);
489 try s.writeAll(", ");
490 try w.writeOperand(s, inst, 1, extra.rhs);
491 }
492
493 fn writeCmpxchg(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
494 const ty_pl = w.air.instructions.items(.data)[@backingInt(inst)].ty_pl;
495 const extra = w.air.extraData(Air.Cmpxchg, ty_pl.payload).data;
496
497 try w.writeOperand(s, inst, 0, extra.ptr);
498 try s.writeAll(", ");
499 try w.writeOperand(s, inst, 1, extra.expected_value);
500 try s.writeAll(", ");
501 try w.writeOperand(s, inst, 2, extra.new_value);
502 try s.print(", {s}, {s}", .{
503 @tagName(extra.successOrder()), @tagName(extra.failureOrder()),
504 });
505 }
506
507 fn writeMulAdd(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
508 const pl_op = w.air.instructions.items(.data)[@backingInt(inst)].pl_op;
509 const extra = w.air.extraData(Air.Bin, pl_op.payload).data;
510
511 try w.writeOperand(s, inst, 0, extra.lhs);
512 try s.writeAll(", ");
513 try w.writeOperand(s, inst, 1, extra.rhs);
514 try s.writeAll(", ");
515 try w.writeOperand(s, inst, 2, pl_op.operand);
516 }
517
518 fn writeLegalizeVecStoreElem(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
519 const pl_op = w.air.instructions.items(.data)[@backingInt(inst)].pl_op;
520 const bin = w.air.extraData(Air.Bin, pl_op.payload).data;
521
522 try w.writeOperand(s, inst, 0, pl_op.operand);
523 try s.writeAll(", ");
524 try w.writeOperand(s, inst, 1, bin.lhs);
525 try s.writeAll(", ");
526 try w.writeOperand(s, inst, 2, bin.rhs);
527 }
528
529 fn writeLegalizeCompilerRtCall(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
530 const rt_call = w.air.unwrapCompilerRtCall(inst);
531 const args = rt_call.args;
532
533 try s.print("{t}, [", .{rt_call.func});
534 for (args, 0..) |arg, i| {
535 if (i != 0) try s.writeAll(", ");
536 try w.writeOperand(s, inst, i, arg);
537 }
538 try s.writeByte(']');
539 }
540
541 fn writeShuffleOne(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
542 const unwrapped = w.air.unwrapShuffleOne(w.zcu, inst);
543 try w.writeType(s, unwrapped.result_ty);
544 try s.writeAll(", ");
545 try w.writeOperand(s, inst, 0, unwrapped.operand);
546 try s.writeAll(", [");
547 for (unwrapped.mask, 0..) |mask_elem, mask_idx| {
548 if (mask_idx > 0) try s.writeAll(", ");
549 switch (mask_elem.unwrap()) {
550 .elem => |idx| try s.print("elem {d}", .{idx}),
551 .value => |val| try s.print("val {f}", .{Value.fromInterned(val).fmtValue(w.zcu)}),
552 }
553 }
554 try s.writeByte(']');
555 }
556
557 fn writeShuffleTwo(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
558 const unwrapped = w.air.unwrapShuffleTwo(w.zcu, inst);
559 try w.writeType(s, unwrapped.result_ty);
560 try s.writeAll(", ");
561 try w.writeOperand(s, inst, 0, unwrapped.operand_a);
562 try s.writeAll(", ");
563 try w.writeOperand(s, inst, 1, unwrapped.operand_b);
564 try s.writeAll(", [");
565 for (unwrapped.mask, 0..) |mask_elem, mask_idx| {
566 if (mask_idx > 0) try s.writeAll(", ");
567 switch (mask_elem.unwrap()) {
568 .a_elem => |idx| try s.print("a_elem {d}", .{idx}),
569 .b_elem => |idx| try s.print("b_elem {d}", .{idx}),
570 .undef => try s.writeAll("undef"),
571 }
572 }
573 try s.writeByte(']');
574 }
575
576 fn writeSelect(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
577 const zcu = w.zcu;
578 const pl_op = w.air.instructions.items(.data)[@backingInt(inst)].pl_op;
579 const extra = w.air.extraData(Air.Bin, pl_op.payload).data;
580
581 const elem_ty = w.typeOfIndex(inst).childType(zcu);
582 try w.writeType(s, elem_ty);
583 try s.writeAll(", ");
584 try w.writeOperand(s, inst, 0, pl_op.operand);
585 try s.writeAll(", ");
586 try w.writeOperand(s, inst, 1, extra.lhs);
587 try s.writeAll(", ");
588 try w.writeOperand(s, inst, 2, extra.rhs);
589 }
590
591 fn writeReduce(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
592 const reduce = w.air.instructions.items(.data)[@backingInt(inst)].reduce;
593
594 try w.writeOperand(s, inst, 0, reduce.operand);
595 try s.print(", {s}", .{@tagName(reduce.operation)});
596 }
597
598 fn writeCmpVector(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
599 const ty_pl = w.air.instructions.items(.data)[@backingInt(inst)].ty_pl;
600 const extra = w.air.extraData(Air.VectorCmp, ty_pl.payload).data;
601
602 try s.print("{s}, ", .{@tagName(extra.compareOperator())});
603 try w.writeOperand(s, inst, 0, extra.lhs);
604 try s.writeAll(", ");
605 try w.writeOperand(s, inst, 1, extra.rhs);
606 }
607
608 fn writeRuntimeNavPtr(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
609 const ip = &w.zcu.intern_pool;
610 const ty_nav = w.air.instructions.items(.data)[@backingInt(inst)].ty_nav;
611 try w.writeType(s, ty_nav.ty);
612 try s.print(", '{f}'", .{ip.getNav(ty_nav.nav).fqn.fmt(ip)});
613 }
614
615 fn writeAtomicLoad(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
616 const atomic_load = w.air.instructions.items(.data)[@backingInt(inst)].atomic_load;
617
618 try w.writeOperand(s, inst, 0, atomic_load.ptr);
619 try s.print(", {s}", .{@tagName(atomic_load.order)});
620 }
621
622 fn writePrefetch(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
623 const prefetch = w.air.instructions.items(.data)[@backingInt(inst)].prefetch;
624
625 try w.writeOperand(s, inst, 0, prefetch.ptr);
626 try s.print(", {s}, {d}, {s}", .{
627 @tagName(prefetch.rw), prefetch.locality, @tagName(prefetch.cache),
628 });
629 }
630
631 fn writeAtomicStore(
632 w: *Writer,
633 s: *std.Io.Writer,
634 inst: Air.Inst.Index,
635 order: std.lang.AtomicOrder,
636 ) Error!void {
637 const bin_op = w.air.instructions.items(.data)[@backingInt(inst)].bin_op;
638 try w.writeOperand(s, inst, 0, bin_op.lhs);
639 try s.writeAll(", ");
640 try w.writeOperand(s, inst, 1, bin_op.rhs);
641 try s.print(", {s}", .{@tagName(order)});
642 }
643
644 fn writeAtomicRmw(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
645 const pl_op = w.air.instructions.items(.data)[@backingInt(inst)].pl_op;
646 const extra = w.air.extraData(Air.AtomicRmw, pl_op.payload).data;
647
648 try w.writeOperand(s, inst, 0, pl_op.operand);
649 try s.writeAll(", ");
650 try w.writeOperand(s, inst, 1, extra.operand);
651 try s.print(", {s}, {s}", .{ @tagName(extra.op()), @tagName(extra.ordering()) });
652 }
653
654 fn writeFieldParentPtr(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
655 const ty_pl = w.air.instructions.items(.data)[@backingInt(inst)].ty_pl;
656 const extra = w.air.extraData(Air.FieldParentPtr, ty_pl.payload).data;
657
658 try w.writeOperand(s, inst, 0, extra.field_ptr);
659 try s.print(", {d}", .{extra.field_index});
660 }
661
662 fn writeAssembly(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
663 const unwrapped_asm = w.air.unwrapAsm(inst);
664 const is_volatile = unwrapped_asm.is_volatile;
665 var op_index: usize = 0;
666
667 const ret_ty = w.typeOfIndex(inst);
668 try w.writeType(s, ret_ty);
669
670 if (is_volatile) {
671 try s.writeAll(", volatile");
672 }
673
674 var it = unwrapped_asm.iterateOutputs();
675 while (it.next()) |out| {
676 const name = out.name;
677 const constraint = out.constraint;
678 if (out.operand == .none) {
679 try s.print(", [{s}] -> {s}", .{ name, constraint });
680 } else {
681 try s.print(", [{s}] out {s} = (", .{ name, constraint });
682 try w.writeOperand(s, inst, op_index, out.operand);
683 op_index += 1;
684 try s.writeByte(')');
685 }
686 }
687
688 it = unwrapped_asm.iterateInputs();
689 while (it.next()) |in| {
690 const name = in.name;
691 const constraint = in.constraint;
692 try s.print(", [{s}] in {s} = (", .{ name, constraint });
693 try w.writeOperand(s, inst, op_index, in.operand);
694 op_index += 1;
695 try s.writeByte(')');
696 }
697
698 const zcu = w.zcu;
699 const ip = &zcu.intern_pool;
700 const clobbers_val: Value = .fromInterned(unwrapped_asm.clobbers);
701 const clobbers_ty = clobbers_val.typeOf(zcu);
702 var clobbers_bigint_buf: Value.BigIntSpace = undefined;
703 const clobbers_bigint = clobbers_val.toBigInt(&clobbers_bigint_buf, zcu);
704 for (0..clobbers_ty.structFieldCount(zcu)) |field_index| {
705 assert(clobbers_ty.fieldType(field_index, zcu).toIntern() == .bool_type);
706 const limb_bits = @bitSizeOf(std.math.big.Limb);
707 if (field_index / limb_bits >= clobbers_bigint.limbs.len) continue; // field is false
708 switch (@as(u1, @truncate(clobbers_bigint.limbs[field_index / limb_bits] >> @intCast(field_index % limb_bits)))) {
709 0 => continue, // field is false
710 1 => {}, // field is true
711 }
712 const clobber = clobbers_ty.structFieldName(field_index, zcu).toSlice(ip).?;
713 assert(clobber.len != 0);
714 try s.writeAll(", ~{");
715 try s.writeAll(clobber);
716 try s.writeAll("}");
717 }
718 const asm_source = unwrapped_asm.source;
719 try s.print(", \"{f}\"", .{std.zig.fmtString(asm_source)});
720 }
721
722 fn writeDbgStmt(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
723 const dbg_stmt = w.air.instructions.items(.data)[@backingInt(inst)].dbg_stmt;
724 try s.print("{d}:{d}", .{ dbg_stmt.line + 1, dbg_stmt.column + 1 });
725 }
726
727 fn writeDbgVar(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
728 const pl_op = w.air.instructions.items(.data)[@backingInt(inst)].pl_op;
729 try w.writeOperand(s, inst, 0, pl_op.operand);
730 const name: Air.NullTerminatedString = @fromBackingInt(@intCast(pl_op.payload));
731 try s.print(", \"{f}\"", .{std.zig.fmtString(name.toSlice(w.air))});
732 }
733
734 fn writeCall(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
735 const call = w.air.unwrapCall(inst);
736 const args = call.args;
737 try w.writeOperand(s, inst, 0, call.callee);
738 try s.writeAll(", [");
739 for (args, 0..) |arg, i| {
740 if (i != 0) try s.writeAll(", ");
741 try w.writeOperand(s, inst, 1 + i, arg);
742 }
743 try s.writeAll("]");
744 }
745
746 fn writeBr(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
747 const br = w.air.instructions.items(.data)[@backingInt(inst)].br;
748 try w.writeInstIndex(s, br.block_inst, false);
749 try s.writeAll(", ");
750 try w.writeOperand(s, inst, 0, br.operand);
751 }
752
753 fn writeRepeat(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
754 const repeat = w.air.instructions.items(.data)[@backingInt(inst)].repeat;
755 try w.writeInstIndex(s, repeat.loop_inst, false);
756 }
757
758 fn writeTry(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
759 const unwrapped_try = w.air.unwrapTry(inst);
760 const body = unwrapped_try.else_body;
761 const liveness_condbr: Air.Liveness.CondBrSlices = if (w.liveness) |liveness|
762 liveness.getCondBr(inst)
763 else
764 .{ .then_deaths = &.{}, .else_deaths = &.{} };
765
766 try w.writeOperand(s, inst, 0, unwrapped_try.error_union);
767 if (w.skip_body) return s.writeAll(", ...");
768 try s.writeAll(", {\n");
769 const old_indent = w.indent;
770 w.indent += 2;
771
772 if (liveness_condbr.else_deaths.len != 0) {
773 try s.splatByteAll(' ', w.indent);
774 for (liveness_condbr.else_deaths, 0..) |operand, i| {
775 if (i != 0) try s.writeAll(" ");
776 try s.print("{f}!", .{operand});
777 }
778 try s.writeAll("\n");
779 }
780 try w.writeBody(s, body);
781
782 w.indent = old_indent;
783 try s.splatByteAll(' ', w.indent);
784 try s.writeAll("}");
785
786 for (liveness_condbr.then_deaths) |operand| {
787 try s.print(" {f}!", .{operand});
788 }
789 }
790
791 fn writeTryPtr(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
792 const unwrapped_try = w.air.unwrapTryPtr(inst);
793 const body = unwrapped_try.else_body;
794 const liveness_condbr: Air.Liveness.CondBrSlices = if (w.liveness) |liveness|
795 liveness.getCondBr(inst)
796 else
797 .{ .then_deaths = &.{}, .else_deaths = &.{} };
798
799 try w.writeOperand(s, inst, 0, unwrapped_try.error_union_ptr);
800
801 try s.writeAll(", ");
802 try w.writeType(s, unwrapped_try.error_union_payload_ptr_ty);
803 if (w.skip_body) return s.writeAll(", ...");
804 try s.writeAll(", {\n");
805 const old_indent = w.indent;
806 w.indent += 2;
807
808 if (liveness_condbr.else_deaths.len != 0) {
809 try s.splatByteAll(' ', w.indent);
810 for (liveness_condbr.else_deaths, 0..) |operand, i| {
811 if (i != 0) try s.writeAll(" ");
812 try s.print("{f}!", .{operand});
813 }
814 try s.writeAll("\n");
815 }
816 try w.writeBody(s, body);
817
818 w.indent = old_indent;
819 try s.splatByteAll(' ', w.indent);
820 try s.writeAll("}");
821
822 for (liveness_condbr.then_deaths) |operand| {
823 try s.print(" {f}!", .{operand});
824 }
825 }
826
827 fn writeCondBr(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
828 const cond_br = w.air.unwrapCondBr(inst);
829 const then_body = cond_br.then_body;
830 const else_body = cond_br.else_body;
831 const liveness_condbr: Air.Liveness.CondBrSlices = if (w.liveness) |liveness|
832 liveness.getCondBr(inst)
833 else
834 .{ .then_deaths = &.{}, .else_deaths = &.{} };
835
836 try w.writeOperand(s, inst, 0, cond_br.condition);
837 if (w.skip_body) return s.writeAll(", ...");
838 try s.writeAll(",");
839 if (cond_br.branch_hints.true != .none) {
840 try s.print(" {s}", .{@tagName(cond_br.branch_hints.true)});
841 }
842 if (cond_br.branch_hints.then_cov != .none) {
843 try s.print(" {s}", .{@tagName(cond_br.branch_hints.then_cov)});
844 }
845 try s.writeAll(" {\n");
846 const old_indent = w.indent;
847 w.indent += 2;
848
849 if (liveness_condbr.then_deaths.len != 0) {
850 try s.splatByteAll(' ', w.indent);
851 for (liveness_condbr.then_deaths, 0..) |operand, i| {
852 if (i != 0) try s.writeAll(" ");
853 try s.print("{f}!", .{operand});
854 }
855 try s.writeAll("\n");
856 }
857
858 try w.writeBody(s, then_body);
859 try s.splatByteAll(' ', old_indent);
860 try s.writeAll("},");
861 if (cond_br.branch_hints.false != .none) {
862 try s.print(" {s}", .{@tagName(cond_br.branch_hints.false)});
863 }
864 if (cond_br.branch_hints.else_cov != .none) {
865 try s.print(" {s}", .{@tagName(cond_br.branch_hints.else_cov)});
866 }
867 try s.writeAll(" {\n");
868
869 if (liveness_condbr.else_deaths.len != 0) {
870 try s.splatByteAll(' ', w.indent);
871 for (liveness_condbr.else_deaths, 0..) |operand, i| {
872 if (i != 0) try s.writeAll(" ");
873 try s.print("{f}!", .{operand});
874 }
875 try s.writeAll("\n");
876 }
877
878 try w.writeBody(s, else_body);
879 w.indent = old_indent;
880
881 try s.splatByteAll(' ', old_indent);
882 try s.writeAll("}");
883 }
884
885 fn writeSwitchBr(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
886 const switch_br = w.air.unwrapSwitch(inst);
887
888 const liveness: Air.Liveness.SwitchBrTable = if (w.liveness) |liveness|
889 liveness.getSwitchBr(w.gpa, inst, switch_br.cases_len + 1) catch
890 @panic("out of memory")
891 else blk: {
892 const slice = w.gpa.alloc([]const Air.Inst.Index, switch_br.cases_len + 1) catch
893 @panic("out of memory");
894 @memset(slice, &.{});
895 break :blk .{ .deaths = slice };
896 };
897 defer w.gpa.free(liveness.deaths);
898
899 try w.writeOperand(s, inst, 0, switch_br.operand);
900 if (w.skip_body) return s.writeAll(", ...");
901 const old_indent = w.indent;
902 w.indent += 2;
903
904 var it = switch_br.iterateCases();
905 while (it.next()) |case| {
906 try s.writeAll(", [");
907 for (case.items, 0..) |item, item_i| {
908 if (item_i != 0) try s.writeAll(", ");
909 try w.writeInstRef(s, item, false);
910 }
911 for (case.ranges, 0..) |range, range_i| {
912 if (range_i != 0 or case.items.len != 0) try s.writeAll(", ");
913 try w.writeInstRef(s, range[0], false);
914 try s.writeAll("...");
915 try w.writeInstRef(s, range[1], false);
916 }
917 try s.writeAll("] ");
918 const hint = switch_br.getHint(case.idx);
919 if (hint != .none) {
920 try s.print(".{s} ", .{@tagName(hint)});
921 }
922 try s.writeAll("=> {\n");
923 w.indent += 2;
924
925 const deaths = liveness.deaths[case.idx];
926 if (deaths.len != 0) {
927 try s.splatByteAll(' ', w.indent);
928 for (deaths, 0..) |operand, i| {
929 if (i != 0) try s.writeAll(" ");
930 try s.print("{f}!", .{operand});
931 }
932 try s.writeAll("\n");
933 }
934
935 try w.writeBody(s, case.body);
936 w.indent -= 2;
937 try s.splatByteAll(' ', w.indent);
938 try s.writeAll("}");
939 }
940
941 const else_body = it.elseBody();
942 if (else_body.len != 0) {
943 try s.writeAll(", else ");
944 const hint = switch_br.getElseHint();
945 if (hint != .none) {
946 try s.print(".{s} ", .{@tagName(hint)});
947 }
948 try s.writeAll("=> {\n");
949 w.indent += 2;
950
951 const deaths = liveness.deaths[liveness.deaths.len - 1];
952 if (deaths.len != 0) {
953 try s.splatByteAll(' ', w.indent);
954 for (deaths, 0..) |operand, i| {
955 if (i != 0) try s.writeAll(" ");
956 try s.print("{f}!", .{operand});
957 }
958 try s.writeAll("\n");
959 }
960
961 try w.writeBody(s, else_body);
962 w.indent -= 2;
963 try s.splatByteAll(' ', w.indent);
964 try s.writeAll("}");
965 }
966
967 try s.writeAll("\n");
968 try s.splatByteAll(' ', old_indent);
969 }
970
971 fn writeWasmMemorySize(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
972 const pl_op = w.air.instructions.items(.data)[@backingInt(inst)].pl_op;
973 try s.print("{d}", .{pl_op.payload});
974 }
975
976 fn writeWasmMemoryGrow(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
977 const pl_op = w.air.instructions.items(.data)[@backingInt(inst)].pl_op;
978 try s.print("{d}, ", .{pl_op.payload});
979 try w.writeOperand(s, inst, 0, pl_op.operand);
980 }
981
982 fn writeWorkDimension(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
983 const pl_op = w.air.instructions.items(.data)[@backingInt(inst)].pl_op;
984 try s.print("{d}", .{pl_op.payload});
985 }
986
987 fn writeOperand(
988 w: *Writer,
989 s: *std.Io.Writer,
990 inst: Air.Inst.Index,
991 op_index: usize,
992 operand: Air.Inst.Ref,
993 ) Error!void {
994 const small_tomb_bits = Air.Liveness.bpi - 1;
995 const dies = if (w.liveness) |liveness| blk: {
996 if (op_index < small_tomb_bits)
997 break :blk liveness.operandDies(inst, @intCast(op_index));
998 var extra_index = liveness.special.get(inst).?;
999 var tomb_op_index: usize = small_tomb_bits;
1000 while (true) {
1001 const bits = liveness.extra[extra_index];
1002 if (op_index < tomb_op_index + 31) {
1003 break :blk @as(u1, @truncate(bits >> @as(u5, @intCast(op_index - tomb_op_index)))) != 0;
1004 }
1005 if ((bits >> 31) != 0) break :blk false;
1006 extra_index += 1;
1007 tomb_op_index += 31;
1008 }
1009 } else false;
1010 return w.writeInstRef(s, operand, dies);
1011 }
1012
1013 fn writeInstRef(
1014 w: *Writer,
1015 s: *std.Io.Writer,
1016 operand: Air.Inst.Ref,
1017 dies: bool,
1018 ) Error!void {
1019 if (@backingInt(operand) < InternPool.static_len) {
1020 return s.print("@{}", .{operand});
1021 } else if (operand.toInterned()) |ip_index| {
1022 const zcu = w.zcu;
1023 const ty = Type.fromInterned(zcu.intern_pool.indexToKey(ip_index).typeOf());
1024 try s.print("<{f}, {f}>", .{
1025 ty.fmt(zcu),
1026 Value.fromInterned(ip_index).fmtValue(w.zcu),
1027 });
1028 } else {
1029 return w.writeInstIndex(s, operand.toIndex().?, dies);
1030 }
1031 }
1032
1033 fn writeInstIndex(
1034 w: *Writer,
1035 s: *std.Io.Writer,
1036 inst: Air.Inst.Index,
1037 dies: bool,
1038 ) Error!void {
1039 _ = w;
1040 try s.print("{f}", .{inst});
1041 if (dies) try s.writeByte('!');
1042 }
1043
1044 fn typeOfIndex(w: *Writer, inst: Air.Inst.Index) Type {
1045 const zcu = w.zcu;
1046 return w.air.typeOfIndex(inst, &zcu.intern_pool);
1047 }
1048};
src/Compilation.zig+28-84
...@@ -20,6 +20,7 @@ const link = @import("link.zig");...@@ -20,6 +20,7 @@ const link = @import("link.zig");
20const tracy = @import("tracy.zig");20const tracy = @import("tracy.zig");
21const trace = tracy.trace;21const trace = tracy.trace;
22const build_options = @import("build_options");22const build_options = @import("build_options");
23const debugLogScopeEnabled = @import("main.zig").debugLogScopeEnabled;
23const LibCInstallation = std.zig.LibCInstallation;24const LibCInstallation = std.zig.LibCInstallation;
24const glibc = @import("libs/glibc.zig");25const glibc = @import("libs/glibc.zig");
25const musl = @import("libs/musl.zig");26const musl = @import("libs/musl.zig");
...@@ -161,12 +162,6 @@ clang_passthrough_mode: bool,...@@ -161,12 +162,6 @@ clang_passthrough_mode: bool,
161clang_preprocessor_mode: ClangPreprocessorMode,162clang_preprocessor_mode: ClangPreprocessorMode,
162/// Whether to print clang argvs to stdout.163/// Whether to print clang argvs to stdout.
163verbose_cc: bool,164verbose_cc: bool,
164verbose_air: bool,
165verbose_intern_pool: bool,
166verbose_generic_instances: bool,
167verbose_llvm_ir: ?[]const u8,
168verbose_llvm_bc: ?[]const u8,
169verbose_llvm_cpu_features: bool,
170verbose_link: bool,165verbose_link: bool,
171link_depfile: ?[]const u8,166link_depfile: ?[]const u8,
172disable_c_depfile: bool,167disable_c_depfile: bool,
...@@ -1544,13 +1539,7 @@ pub const CreateOptions = struct {...@@ -1544,13 +1539,7 @@ pub const CreateOptions = struct {
1544 clang_passthrough_mode: bool = false,1539 clang_passthrough_mode: bool = false,
1545 verbose_cc: bool = false,1540 verbose_cc: bool = false,
1546 verbose_link: bool = false,1541 verbose_link: bool = false,
1547 verbose_air: bool = false,
1548 verbose_intern_pool: bool = false,
1549 verbose_generic_instances: bool = false,
1550 verbose_llvm_ir: ?[]const u8 = null,
1551 verbose_llvm_bc: ?[]const u8 = null,
1552 link_depfile: ?[]const u8 = null,1542 link_depfile: ?[]const u8 = null,
1553 verbose_llvm_cpu_features: bool = false,
1554 debug_compiler_runtime_libs: ?std.lang.Optimize = null,1543 debug_compiler_runtime_libs: ?std.lang.Optimize = null,
1555 debug_compile_errors: bool = false,1544 debug_compile_errors: bool = false,
1556 debug_incremental: bool = false,1545 debug_incremental: bool = false,
...@@ -1932,21 +1921,6 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,...@@ -1932,21 +1921,6 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,
1932 try options.root_mod.deps.putNoClobber(arena, "zigc", zigc_mod);1921 try options.root_mod.deps.putNoClobber(arena, "zigc", zigc_mod);
1933 }1922 }
19341923
1935 if (options.verbose_llvm_cpu_features) {
1936 if (options.root_mod.resolved_target.llvm_cpu_features) |cf| {
1937 const stderr = try io.lockStderr(&.{}, null);
1938 defer io.unlockStderr();
1939 const w = &stderr.file_writer.interface;
1940 printVerboseLlvmCpuFeatures(w, arena, options.root_name, target, cf) catch |err| switch (err) {
1941 error.WriteFailed => switch (stderr.file_writer.err.?) {
1942 error.Canceled => |e| return e,
1943 else => {},
1944 },
1945 error.OutOfMemory => |e| return e,
1946 };
1947 }
1948 }
1949
1950 const error_limit = options.error_limit orelse (std.math.maxInt(u16) - 1);1924 const error_limit = options.error_limit orelse (std.math.maxInt(u16) - 1);
1951 const main_mod = options.main_mod orelse options.root_mod;1925 const main_mod = options.main_mod orelse options.root_mod;
19521926
...@@ -2111,14 +2085,8 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,...@@ -2111,14 +2085,8 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,
2111 .clang_passthrough_mode = options.clang_passthrough_mode,2085 .clang_passthrough_mode = options.clang_passthrough_mode,
2112 .clang_preprocessor_mode = options.clang_preprocessor_mode,2086 .clang_preprocessor_mode = options.clang_preprocessor_mode,
2113 .verbose_cc = options.verbose_cc,2087 .verbose_cc = options.verbose_cc,
2114 .verbose_air = options.verbose_air,
2115 .verbose_intern_pool = options.verbose_intern_pool,
2116 .verbose_generic_instances = options.verbose_generic_instances,
2117 .verbose_llvm_ir = options.verbose_llvm_ir,
2118 .verbose_llvm_bc = options.verbose_llvm_bc,
2119 .link_depfile = options.link_depfile,
2120 .verbose_llvm_cpu_features = options.verbose_llvm_cpu_features,
2121 .verbose_link = options.verbose_link,2088 .verbose_link = options.verbose_link,
2089 .link_depfile = options.link_depfile,
2122 .disable_c_depfile = options.disable_c_depfile,2090 .disable_c_depfile = options.disable_c_depfile,
2123 .reference_trace = options.reference_trace,2091 .reference_trace = options.reference_trace,
2124 .time_report = if (options.time_report) .init else null,2092 .time_report = if (options.time_report) .init else null,
...@@ -2353,8 +2321,9 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,...@@ -2353,8 +2321,9 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,
2353 comp.emit_asm != null or2321 comp.emit_asm != null or
2354 comp.emit_llvm_ir != null or2322 comp.emit_llvm_ir != null or
2355 comp.emit_llvm_bc != null or2323 comp.emit_llvm_bc != null or
2356 comp.verbose_llvm_ir != null or2324 log_llvm_ir: {
2357 comp.verbose_llvm_bc != null))2325 break :log_llvm_ir debugLogScopeEnabled("llvm-ir") or debugLogScopeEnabled("opt-llvm-ir");
2326 }))
2358 {2327 {
2359 if (opt_zcu) |zcu| {2328 if (opt_zcu) |zcu| {
2360 dev.check(.llvm_backend);2329 dev.check(.llvm_backend);
...@@ -2566,19 +2535,6 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,...@@ -2566,19 +2535,6 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,
2566 return comp;2535 return comp;
2567}2536}
25682537
2569fn printVerboseLlvmCpuFeatures(
2570 w: *Writer,
2571 arena: Allocator,
2572 root_name: []const u8,
2573 target: *const std.Target,
2574 cf: [*:0]const u8,
2575) (Writer.Error || Allocator.Error)!void {
2576 try w.print("compilation: {s}\n", .{root_name});
2577 try w.print(" target: {s}\n", .{try target.zigTriple(arena)});
2578 try w.print(" cpu: {s}\n", .{target.cpu.model.name});
2579 try w.print(" features: {s}\n", .{cf});
2580}
2581
2582pub fn destroy(comp: *Compilation) void {2538pub fn destroy(comp: *Compilation) void {
2583 const gpa = comp.gpa;2539 const gpa = comp.gpa;
2584 const io = comp.io;2540 const io = comp.io;
...@@ -2991,14 +2947,19 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE...@@ -2991,14 +2947,19 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE
2991 try pt.processExports();2947 try pt.processExports();
2992 }2948 }
29932949
2994 if (build_options.enable_debug_extensions and comp.verbose_intern_pool) {2950 {
2995 std.debug.print("intern pool stats for {q}:\n", .{comp.root_name});2951 var d: InternPool.Dump = .{
2996 zcu.intern_pool.dump();2952 .name = comp.root_name,
2997 }2953 .arena = arena,
29982954 .ip = &zcu.intern_pool,
2999 if (build_options.enable_debug_extensions and comp.verbose_generic_instances) {2955 .err = null,
3000 std.debug.print("generic instances for '{s}:0x{x}':\n", .{ comp.root_name, @intFromPtr(zcu) });2956 };
3001 zcu.intern_pool.dumpGenericInstances(gpa);2957 std.log.scoped(.@"ip-stats").debug("{f}", .{&d});
2958 if (d.err) |err| return err;
2959 std.log.scoped(.@"ip-values").debug("{f}", .{std.fmt.alt(&d, .formatAll)});
2960 if (d.err) |err| return err;
2961 std.log.scoped(.@"ip-generic-instances").debug("{f}", .{std.fmt.alt(&d, .formatGenericInstances)});
2962 if (d.err) |err| return err;
3002 }2963 }
3003 }2964 }
30042965
...@@ -3220,28 +3181,29 @@ fn flush(comp: *Compilation, arena: Allocator) (Io.Cancelable || Allocator.Error...@@ -3220,28 +3181,29 @@ fn flush(comp: *Compilation, arena: Allocator) (Io.Cancelable || Allocator.Error
3220 comp.time_report.?.stats.real_ns_llvm_emit = ns;3181 comp.time_report.?.stats.real_ns_llvm_emit = ns;
3221 };3182 };
32223183
3223 const zcu_obj_path: ?Cache.Path = if (comp.bin_file != null) p: {3184 const zcu_obj_path: ?Cache.Path = switch (comp.getTarget().ofmt) {
3224 break :p try comp.resolveEmitPathFlush(arena, .temp, llvm_object.out_bin_basename);3185 .llvmbc, .llvmir => null,
3225 } else null;3186 else => if (comp.bin_file != null)
3187 try comp.resolveEmitPathFlush(arena, .temp, llvm_object.out_bin_basename)
3188 else
3189 null,
3190 };
32263191
3227 const active = zcu.activate(tid);3192 const active = zcu.activate(tid);
3228 defer active.deactivate();3193 defer active.deactivate();
3229 llvm_object.emit(active.pt, .{3194 llvm_object.emit(active.pt, .{
3230 .pre_ir_path = comp.verbose_llvm_ir,
3231 .pre_bc_path = comp.verbose_llvm_bc,
3232
3233 .bin_path = if (zcu_obj_path) |p| try p.toStringZ(arena) else null,3195 .bin_path = if (zcu_obj_path) |p| try p.toStringZ(arena) else null,
3234 .asm_path = p: {3196 .asm_path = p: {
3235 const raw = comp.emit_asm orelse break :p null;3197 const raw = comp.emit_asm orelse break :p null;
3236 const p = try comp.resolveEmitPathFlush(arena, .artifact, raw);3198 const p = try comp.resolveEmitPathFlush(arena, .artifact, raw);
3237 break :p try p.toStringZ(arena);3199 break :p try p.toStringZ(arena);
3238 },3200 },
3239 .post_ir_path = p: {3201 .opt_ir_path = p: {
3240 const raw = comp.emit_llvm_ir orelse break :p null;3202 const raw = comp.emit_llvm_ir orelse break :p null;
3241 const p = try comp.resolveEmitPathFlush(arena, .artifact, raw);3203 const p = try comp.resolveEmitPathFlush(arena, .artifact, raw);
3242 break :p try p.toStringZ(arena);3204 break :p try p.toStringZ(arena);
3243 },3205 },
3244 .post_bc_path = p: {3206 .opt_bc_path = p: {
3245 const raw = comp.emit_llvm_bc orelse break :p null;3207 const raw = comp.emit_llvm_bc orelse break :p null;
3246 const p = try comp.resolveEmitPathFlush(arena, .artifact, raw);3208 const p = try comp.resolveEmitPathFlush(arena, .artifact, raw);
3247 break :p try p.toStringZ(arena);3209 break :p try p.toStringZ(arena);
...@@ -3267,7 +3229,7 @@ fn flush(comp: *Compilation, arena: Allocator) (Io.Cancelable || Allocator.Error...@@ -3267,7 +3229,7 @@ fn flush(comp: *Compilation, arena: Allocator) (Io.Cancelable || Allocator.Error
3267 error.Canceled, error.OutOfMemory => |e| return e,3229 error.Canceled, error.OutOfMemory => |e| return e,
3268 error.AlreadyReported => return,3230 error.AlreadyReported => return,
3269 };3231 };
3270 }3232 } else return;
3271 }3233 }
3272 }3234 }
3273 if (comp.bin_file) |lf| {3235 if (comp.bin_file) |lf| {
...@@ -4903,12 +4865,6 @@ fn workerDocsWasmFallible(comp: *Compilation, prog_node: std.Progress.Node) SubU...@@ -4903,12 +4865,6 @@ fn workerDocsWasmFallible(comp: *Compilation, prog_node: std.Progress.Node) SubU
4903 .emit_bin = .yes_cache,4865 .emit_bin = .yes_cache,
4904 .verbose_cc = comp.verbose_cc,4866 .verbose_cc = comp.verbose_cc,
4905 .verbose_link = comp.verbose_link,4867 .verbose_link = comp.verbose_link,
4906 .verbose_air = comp.verbose_air,
4907 .verbose_intern_pool = comp.verbose_intern_pool,
4908 .verbose_generic_instances = comp.verbose_intern_pool,
4909 .verbose_llvm_ir = comp.verbose_llvm_ir,
4910 .verbose_llvm_bc = comp.verbose_llvm_bc,
4911 .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features,
4912 .environ_map = comp.environ_map,4868 .environ_map = comp.environ_map,
4913 }) catch |err| switch (err) {4869 }) catch |err| switch (err) {
4914 error.CreateFail => {4870 error.CreateFail => {
...@@ -7415,12 +7371,6 @@ fn buildOutputFromZig(...@@ -7415,12 +7371,6 @@ fn buildOutputFromZig(
7415 .data_sections = true,7371 .data_sections = true,
7416 .verbose_cc = comp.verbose_cc,7372 .verbose_cc = comp.verbose_cc,
7417 .verbose_link = comp.verbose_link,7373 .verbose_link = comp.verbose_link,
7418 .verbose_air = comp.verbose_air,
7419 .verbose_intern_pool = comp.verbose_intern_pool,
7420 .verbose_generic_instances = comp.verbose_intern_pool,
7421 .verbose_llvm_ir = comp.verbose_llvm_ir,
7422 .verbose_llvm_bc = comp.verbose_llvm_bc,
7423 .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features,
7424 .clang_passthrough_mode = comp.clang_passthrough_mode,7374 .clang_passthrough_mode = comp.clang_passthrough_mode,
7425 .skip_linker_dependencies = true,7375 .skip_linker_dependencies = true,
7426 .environ_map = comp.environ_map,7376 .environ_map = comp.environ_map,
...@@ -7552,12 +7502,6 @@ pub fn build_crt_file(...@@ -7552,12 +7502,6 @@ pub fn build_crt_file(
7552 .c_source_files = c_source_files,7502 .c_source_files = c_source_files,
7553 .verbose_cc = comp.verbose_cc,7503 .verbose_cc = comp.verbose_cc,
7554 .verbose_link = comp.verbose_link,7504 .verbose_link = comp.verbose_link,
7555 .verbose_air = comp.verbose_air,
7556 .verbose_intern_pool = comp.verbose_intern_pool,
7557 .verbose_generic_instances = comp.verbose_generic_instances,
7558 .verbose_llvm_ir = comp.verbose_llvm_ir,
7559 .verbose_llvm_bc = comp.verbose_llvm_bc,
7560 .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features,
7561 .clang_passthrough_mode = comp.clang_passthrough_mode,7505 .clang_passthrough_mode = comp.clang_passthrough_mode,
7562 .skip_linker_dependencies = true,7506 .skip_linker_dependencies = true,
7563 .environ_map = comp.environ_map,7507 .environ_map = comp.environ_map,
src/Compilation/Config.zig+4-4
...@@ -190,7 +190,7 @@ pub fn resolve(options: Options) ResolveError!Config {...@@ -190,7 +190,7 @@ pub fn resolve(options: Options) ResolveError!Config {
190 // *If* the LLVM backend were to be selected, should Zig use the LLVM190 // *If* the LLVM backend were to be selected, should Zig use the LLVM
191 // library to build the LLVM module?191 // library to build the LLVM module?
192 const use_lib_llvm = b: {192 const use_lib_llvm = b: {
193 if (!build_options.have_llvm) {193 if (!build_options.have_llvm or target.ofmt == .llvmbc or target.ofmt == .llvmir) {
194 if (options.use_lib_llvm == true) return error.LlvmLibraryUnavailable;194 if (options.use_lib_llvm == true) return error.LlvmLibraryUnavailable;
195 break :b false;195 break :b false;
196 }196 }
...@@ -324,7 +324,7 @@ pub fn resolve(options: Options) ResolveError!Config {...@@ -324,7 +324,7 @@ pub fn resolve(options: Options) ResolveError!Config {
324 if (!options.have_zcu) break :b false;324 if (!options.have_zcu) break :b false;
325325
326 // If emitting to LLVM bitcode object format, must use LLVM backend.326 // If emitting to LLVM bitcode object format, must use LLVM backend.
327 if (options.emit_llvm_ir or options.emit_llvm_bc) {327 if (target.ofmt == .llvmbc or target.ofmt == .llvmir or options.emit_llvm_bc or options.emit_llvm_ir) {
328 if (options.use_llvm == false)328 if (options.use_llvm == false)
329 return error.EmittingLlvmModuleRequiresLlvmBackend;329 return error.EmittingLlvmModuleRequiresLlvmBackend;
330 if (!target_util.hasLlvmSupport(target, target.ofmt))330 if (!target_util.hasLlvmSupport(target, target.ofmt))
...@@ -379,7 +379,7 @@ pub fn resolve(options: Options) ResolveError!Config {...@@ -379,7 +379,7 @@ pub fn resolve(options: Options) ResolveError!Config {
379 const backend = target_util.zigBackend(target, use_llvm);379 const backend = target_util.zigBackend(target, use_llvm);
380380
381 if (options.emit_bin and options.have_zcu) {381 if (options.emit_bin and options.have_zcu) {
382 if (!use_lib_llvm and use_llvm) {382 if (target.ofmt != .llvmbc and target.ofmt != .llvmir and !use_lib_llvm and use_llvm) {
383 // Explicit request to use LLVM to produce an object file, but without383 // Explicit request to use LLVM to produce an object file, but without
384 // using LLVM libraries. Impossible.384 // using LLVM libraries. Impossible.
385 return error.EmittingBinaryRequiresLlvmLibrary;385 return error.EmittingBinaryRequiresLlvmLibrary;
...@@ -513,7 +513,7 @@ pub fn resolve(options: Options) ResolveError!Config {...@@ -513,7 +513,7 @@ pub fn resolve(options: Options) ResolveError!Config {
513 break :b switch (target.ofmt) {513 break :b switch (target.ofmt) {
514 .elf, .macho, .wasm => .{ .dwarf = .@"32" },514 .elf, .macho, .wasm => .{ .dwarf = .@"32" },
515 .coff => .code_view,515 .coff => .code_view,
516 .c => switch (target.os.tag) {516 .c, .llvmbc, .llvmir => switch (target.os.tag) {
517 .windows, .uefi => .code_view,517 .windows, .uefi => .code_view,
518 else => .{ .dwarf = .@"32" },518 else => .{ .dwarf = .@"32" },
519 },519 },
src/InternPool.zig+33-25
...@@ -10591,17 +10591,36 @@ pub fn errorUnionPayload(ip: *const InternPool, ty: Index) Index {...@@ -10591,17 +10591,36 @@ pub fn errorUnionPayload(ip: *const InternPool, ty: Index) Index {
10591 return ip.indexToKey(ty).error_union_type.payload_type;10591 return ip.indexToKey(ty).error_union_type.payload_type;
10592}10592}
1059310593
10594pub fn dump(ip: *const InternPool) void {10594pub const Dump = struct {
10595 var buffer: [4096]u8 = undefined;10595 name: []const u8,
10596 const stderr = std.debug.lockStderr(&buffer);10596 arena: std.mem.Allocator,
10597 defer std.debug.unlockStderr();10597 ip: *const InternPool,
10598 const w = &stderr.file_writer.interface;10598 err: ?Allocator.Error,
10599 dumpDependencyStatsFallible(ip, w) catch return;10599
10600 dumpStatsFallible(ip, w, std.heap.page_allocator) catch return;10600 pub fn format(d: *Dump, w: *Io.Writer) Io.Writer.Error!void {
10601 dumpAllFallible(ip, w) catch return;10601 try w.print("{q}:\n", .{d.name});
10602}10602 try d.ip.dumpDependencyStatsFallible(w);
10603 d.ip.dumpStatsFallible(d.arena, w) catch |err| switch (err) {
10604 error.WriteFailed => |e| return e,
10605 error.OutOfMemory => |e| {
10606 d.err = e;
10607 return error.WriteFailed;
10608 },
10609 };
10610 }
10611
10612 pub fn formatAll(d: *Dump, w: *Io.Writer) Io.Writer.Error!void {
10613 try w.print("{q}:\n", .{d.name});
10614 try d.ip.dumpAllFallible(w);
10615 }
1060310616
10604fn dumpDependencyStatsFallible(ip: *const InternPool, w: *Io.Writer) !void {10617 pub fn formatGenericInstances(d: *Dump, w: *Io.Writer) Io.Writer.Error!void {
10618 try w.print("{q}:\n", .{d.name});
10619 d.ip.dumpGenericInstancesFallible(d.arena, w) catch return;
10620 }
10621};
10622
10623fn dumpDependencyStatsFallible(ip: *const InternPool, w: *Io.Writer) Io.Writer.Error!void {
10605 const dep_entries_len = ip.dep_entries.items.len - ip.free_dep_entries.items.len;10624 const dep_entries_len = ip.dep_entries.items.len - ip.free_dep_entries.items.len;
10606 const src_hash_deps_len = ip.src_hash_deps.count();10625 const src_hash_deps_len = ip.src_hash_deps.count();
10607 const nav_val_deps_len = ip.nav_val_deps.count();10626 const nav_val_deps_len = ip.nav_val_deps.count();
...@@ -10668,7 +10687,7 @@ fn dumpDependencyStatsFallible(ip: *const InternPool, w: *Io.Writer) !void {...@@ -10668,7 +10687,7 @@ fn dumpDependencyStatsFallible(ip: *const InternPool, w: *Io.Writer) !void {
10668 });10687 });
10669}10688}
1067010689
10671fn dumpStatsFallible(ip: *const InternPool, w: *Io.Writer, arena: Allocator) !void {10690fn dumpStatsFallible(ip: *const InternPool, arena: Allocator, w: *Io.Writer) (Allocator.Error || Io.Writer.Error)!void {
10672 var items_len: usize = 0;10691 var items_len: usize = 0;
10673 var extra_len: usize = 0;10692 var extra_len: usize = 0;
10674 var limbs_len: usize = 0;10693 var limbs_len: usize = 0;
...@@ -10968,7 +10987,7 @@ fn dumpStatsFallible(ip: *const InternPool, w: *Io.Writer, arena: Allocator) !vo...@@ -10968,7 +10987,7 @@ fn dumpStatsFallible(ip: *const InternPool, w: *Io.Writer, arena: Allocator) !vo
10968 }10987 }
10969}10988}
1097010989
10971fn dumpAllFallible(ip: *const InternPool, w: *Io.Writer) anyerror!void {10990fn dumpAllFallible(ip: *const InternPool, w: *Io.Writer) Io.Writer.Error!void {
10972 for (ip.locals, 0..) |*local, tid| {10991 for (ip.locals, 0..) |*local, tid| {
10973 // Early check for length 0, because `view()` is invalid if capacity is 010992 // Early check for length 0, because `view()` is invalid if capacity is 0
10974 if (local.mutate.items.len == 0) continue;10993 if (local.mutate.items.len == 0) continue;
...@@ -11071,21 +11090,10 @@ fn dumpAllFallible(ip: *const InternPool, w: *Io.Writer) anyerror!void {...@@ -11071,21 +11090,10 @@ fn dumpAllFallible(ip: *const InternPool, w: *Io.Writer) anyerror!void {
11071 }11090 }
11072}11091}
1107311092
11074pub fn dumpGenericInstances(ip: *const InternPool, allocator: Allocator) void {11093pub fn dumpGenericInstancesFallible(ip: *const InternPool, arena: Allocator, w: *Io.Writer) !void {
11075 var buffer: [4096]u8 = undefined;
11076 const stderr = std.debug.lockStderr(&buffer);
11077 defer std.debug.unlockStderr();
11078 const w = &stderr.file_writer.interface;
11079 ip.dumpGenericInstancesFallible(allocator, w) catch return;
11080}
11081
11082pub fn dumpGenericInstancesFallible(ip: *const InternPool, allocator: Allocator, w: *Io.Writer) !void {
11083 var arena_allocator = std.heap.ArenaAllocator.init(allocator);
11084 defer arena_allocator.deinit();
11085 const arena = arena_allocator.allocator();
11086
11087 var instances: std.array_hash_map.Auto(Index, std.ArrayList(Index)) = .empty;11094 var instances: std.array_hash_map.Auto(Index, std.ArrayList(Index)) = .empty;
11088 for (ip.locals, 0..) |*local, tid| {11095 for (ip.locals, 0..) |*local, tid| {
11096 if (local.mutate.items.len == 0) continue;
11089 const items = local.shared.items.view().slice();11097 const items = local.shared.items.view().slice();
11090 const extra_list = local.shared.extra;11098 const extra_list = local.shared.extra;
11091 for (11099 for (
src/Module.zig+8-11
...@@ -26,6 +26,7 @@ fully_qualified_name: []const u8,...@@ -26,6 +26,7 @@ fully_qualified_name: []const u8,
26deps: Deps = .{},26deps: Deps = .{},
2727
28resolved_target: ResolvedTarget,28resolved_target: ResolvedTarget,
29llvm_cpu_features: ?[:0]const u8,
29optimize_mode: std.lang.Optimize,30optimize_mode: std.lang.Optimize,
30code_model: std.lang.CodeModel,31code_model: std.lang.CodeModel,
31single_threaded: bool,32single_threaded: bool,
...@@ -94,7 +95,6 @@ pub const ResolvedTarget = struct {...@@ -94,7 +95,6 @@ pub const ResolvedTarget = struct {
94 is_native_os: bool,95 is_native_os: bool,
95 is_native_abi: bool,96 is_native_abi: bool,
96 is_explicit_dynamic_linker: bool,97 is_explicit_dynamic_linker: bool,
97 llvm_cpu_features: ?[*:0]const u8 = null,
98};98};
9999
100pub const CreateError = error{100pub const CreateError = error{
...@@ -362,15 +362,13 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Module {...@@ -362,15 +362,13 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Module {
362 break :b 0;362 break :b 0;
363 };363 };
364364
365 const llvm_cpu_features: ?[*:0]const u8 = b: {365 const llvm_cpu_features: ?[:0]const u8 = b: {
366 if (resolved_target.llvm_cpu_features) |x| break :b x;
367 if (!options.global.use_llvm) break :b null;366 if (!options.global.use_llvm) break :b null;
367 if (options.inherited.resolved_target == null) break :b options.parent.?.llvm_cpu_features;
368368
369 // Append disabled features after enabled ones, so that their effects aren't overwritten.
369 var buf = std.array_list.Managed(u8).init(arena);370 var buf = std.array_list.Managed(u8).init(arena);
370 var disabled_features = std.array_list.Managed(u8).init(arena);371 var disabled_features = std.array_list.Managed(u8).init(arena);
371 defer disabled_features.deinit();
372
373 // Append disabled features after enabled ones, so that their effects aren't overwritten.
374 for (target.cpu.arch.allFeaturesList()) |feature| {372 for (target.cpu.arch.allFeaturesList()) |feature| {
375 if (feature.llvm_name) |llvm_name| {373 if (feature.llvm_name) |llvm_name| {
376 // Ignore these until we figure out how to handle the concept of omitting features.374 // Ignore these until we figure out how to handle the concept of omitting features.
...@@ -401,10 +399,9 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Module {...@@ -401,10 +399,9 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Module {
401399
402 try buf.appendSlice(disabled_features.items);400 try buf.appendSlice(disabled_features.items);
403 if (buf.items.len == 0) break :b "";401 if (buf.items.len == 0) break :b "";
404 assert(std.mem.endsWith(u8, buf.items, ","));402 assert(buf.items[buf.items.len - 1] == ',');
405 buf.items[buf.items.len - 1] = 0;403 buf.items[buf.items.len - 1] = 0;
406 buf.shrinkAndFree(buf.items.len);404 break :b buf.items[0 .. buf.items.len - 1 :0];
407 break :b buf.items[0 .. buf.items.len - 1 :0].ptr;
408 };405 };
409406
410 const mod = try arena.create(Module);407 const mod = try arena.create(Module);
...@@ -417,8 +414,8 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Module {...@@ -417,8 +414,8 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Module {
417 .is_native_os = resolved_target.is_native_os,414 .is_native_os = resolved_target.is_native_os,
418 .is_native_abi = resolved_target.is_native_abi,415 .is_native_abi = resolved_target.is_native_abi,
419 .is_explicit_dynamic_linker = resolved_target.is_explicit_dynamic_linker,416 .is_explicit_dynamic_linker = resolved_target.is_explicit_dynamic_linker,
420 .llvm_cpu_features = llvm_cpu_features,
421 },417 },
418 .llvm_cpu_features = llvm_cpu_features,
422 .optimize_mode = optimize_mode,419 .optimize_mode = optimize_mode,
423 .single_threaded = single_threaded,420 .single_threaded = single_threaded,
424 .error_tracing = error_tracing,421 .error_tracing = error_tracing,
...@@ -494,8 +491,8 @@ pub fn createBuiltin(arena: Allocator, opts: Builtin, dirs: std.zig.Directories)...@@ -494,8 +491,8 @@ pub fn createBuiltin(arena: Allocator, opts: Builtin, dirs: std.zig.Directories)
494 .is_native_os = false,491 .is_native_os = false,
495 .is_native_abi = false,492 .is_native_abi = false,
496 .is_explicit_dynamic_linker = false,493 .is_explicit_dynamic_linker = false,
497 .llvm_cpu_features = null,
498 },494 },
495 .llvm_cpu_features = null,
499 .optimize_mode = opts.optimize_mode,496 .optimize_mode = opts.optimize_mode,
500 .single_threaded = opts.single_threaded,497 .single_threaded = opts.single_threaded,
501 .error_tracing = opts.error_tracing,498 .error_tracing = opts.error_tracing,
src/Sema.zig+3-5
...@@ -1126,6 +1126,8 @@ fn analyzeBodyInner(...@@ -1126,6 +1126,8 @@ fn analyzeBodyInner(
1126 crash_info.push(sema, block, body);1126 crash_info.push(sema, block, body);
1127 defer crash_info.pop();1127 defer crash_info.pop();
11281128
1129 const path = zcu.namespacePtr(block.namespace).fileScope(zcu).path;
1130
1129 // We use a while (true) loop here to avoid a redundant way of breaking out of1131 // We use a while (true) loop here to avoid a redundant way of breaking out of
1130 // the loop. The only way to break out of the loop is with a `noreturn`1132 // the loop. The only way to break out of the loop is with a `noreturn`
1131 // instruction.1133 // instruction.
...@@ -1134,11 +1136,7 @@ fn analyzeBodyInner(...@@ -1134,11 +1136,7 @@ fn analyzeBodyInner(
1134 crash_info.setBodyIndex(i);1136 crash_info.setBodyIndex(i);
1135 const inst = body[i];1137 const inst = body[i];
11361138
1137 // This log is a bit expensive, and LLVM fails to optimize it away.1139 std.log.scoped(.sema_zir).debug("sema ZIR {f} %{d}", .{ path.fmt(comp), inst });
1138 if (build_options.enable_logging) {
1139 const path = zcu.namespacePtr(block.namespace).fileScope(zcu).path;
1140 std.log.scoped(.sema_zir).debug("sema ZIR {f} %{d}", .{ path.fmt(comp), inst });
1141 }
11421140
1143 const air_ref: Air.Inst.Ref = inst: switch (tags[@backingInt(inst)]) {1141 const air_ref: Air.Inst.Ref = inst: switch (tags[@backingInt(inst)]) {
1144 // zig fmt: off1142 // zig fmt: off
src/Zcu/PerThread.zig+20-38
...@@ -25,6 +25,7 @@ const InternPool = @import("../InternPool.zig");...@@ -25,6 +25,7 @@ const InternPool = @import("../InternPool.zig");
25const AnalUnit = InternPool.AnalUnit;25const AnalUnit = InternPool.AnalUnit;
26const Module = @import("../Module.zig");26const Module = @import("../Module.zig");
27const Sema = @import("../Sema.zig");27const Sema = @import("../Sema.zig");
28const debugLogScopeEnabled = @import("../main.zig").debugLogScopeEnabled;
28const target_util = @import("../target.zig");29const target_util = @import("../target.zig");
29const tracy = @import("../tracy.zig");30const tracy = @import("../tracy.zig");
30const trace = tracy.trace;31const trace = tracy.trace;
...@@ -2303,10 +2304,9 @@ fn analyzeFuncBody(...@@ -2303,10 +2304,9 @@ fn analyzeFuncBody(
23032304
2304 const comp = zcu.comp;2305 const comp = zcu.comp;
23052306
2306 const dump_air = build_options.enable_debug_extensions and comp.verbose_air;2307 if (comp.bin_file != null or zcu.llvm_object != null or log_air: {
2307 const dump_llvm_ir = build_options.enable_debug_extensions and (comp.verbose_llvm_ir != null or comp.verbose_llvm_bc != null);2308 break :log_air debugLogScopeEnabled("illegal-air") or debugLogScopeEnabled("legal-air") or debugLogScopeEnabled("air");
23082309 }) {
2309 if (comp.bin_file != null or zcu.llvm_object != null or dump_air or dump_llvm_ir) {
2310 zcu.codegen_prog_node.increaseEstimatedTotalItems(1);2310 zcu.codegen_prog_node.increaseEstimatedTotalItems(1);
2311 comp.link_prog_node.increaseEstimatedTotalItems(1);2311 comp.link_prog_node.increaseEstimatedTotalItems(1);
23122312
...@@ -4522,32 +4522,28 @@ fn runCodegenInner(pt: Zcu.PerThread, func_index: InternPool.Index, air: *Air) e...@@ -4522,32 +4522,28 @@ fn runCodegenInner(pt: Zcu.PerThread, func_index: InternPool.Index, air: *Air) e
4522 tracy_trace.addText(fqn.toSlice(ip));4522 tracy_trace.addText(fqn.toSlice(ip));
4523 tracy_trace.addTextFmt("func_ip_index={d}", .{func_index});4523 tracy_trace.addTextFmt("func_ip_index={d}", .{func_index});
45244524
4525 Air.Verify.run(pt, func_index, air);4525 var liveness: ?Air.Liveness = null;
4526 defer if (liveness) |*l| l.deinit(gpa);
4527
4528 const ap: Air.Print = .{
4529 .zcu = zcu,
4530 .fqn = fqn,
4531 .air = air,
4532 .liveness = &liveness,
4533 };
4534 std.log.scoped(.@"illegal-air").debug("{f}", .{&ap});
45264535
4527 if (codegen.legalizeFeatures(pt, nav)) |features| {4536 if (codegen.legalizeFeatures(pt, nav)) |features| {
4528 try air.legalize(pt, features);4537 // Verify the AIR again pre-legalization.
4529 // Verify the AIR again post-legalization.
4530 Air.Verify.run(pt, func_index, air);4538 Air.Verify.run(pt, func_index, air);
4539 try air.legalize(pt, features);
4531 }4540 }
45324541
4533 var liveness: ?Air.Liveness = if (codegen.wantsLiveness(pt, nav))4542 std.log.scoped(.@"legal-air").debug("{f}", .{&ap});
4534 try .analyze(zcu, air.*, ip)4543 Air.Verify.run(pt, func_index, air);
4535 else
4536 null;
4537 defer if (liveness) |*l| l.deinit(gpa);
4538
4539 if (build_options.enable_debug_extensions and comp.verbose_air) p: {
4540 const io = comp.io;
4541 const stderr = try io.lockStderr(&.{}, null);
4542 defer io.unlockStderr();
4543 printVerboseAir(pt, liveness, fqn, air, &stderr.file_writer.interface) catch |err| switch (err) {
4544 error.WriteFailed => switch (stderr.file_writer.err.?) {
4545 error.Canceled => |e| return e,
4546 else => break :p,
4547 },
4548 };
4549 }
45504544
4545 if (codegen.wantsLiveness(pt, nav)) liveness = try .analyze(zcu, air.*, ip);
4546 std.log.scoped(.air).debug("{f}", .{&ap});
4551 if (std.debug.runtime_safety) verify_liveness: {4547 if (std.debug.runtime_safety) verify_liveness: {
4552 var verify: Air.Liveness.Verify = .{4548 var verify: Air.Liveness.Verify = .{
4553 .gpa = gpa,4549 .gpa = gpa,
...@@ -4577,17 +4573,3 @@ fn runCodegenInner(pt: Zcu.PerThread, func_index: InternPool.Index, air: *Air) e...@@ -4577,17 +4573,3 @@ fn runCodegenInner(pt: Zcu.PerThread, func_index: InternPool.Index, air: *Air) e
45774573
4578 return codegen.generateFunction(lf, pt, func_index, air, &liveness);4574 return codegen.generateFunction(lf, pt, func_index, air, &liveness);
4579}4575}
4580
4581fn printVerboseAir(
4582 pt: Zcu.PerThread,
4583 liveness: ?Air.Liveness,
4584 fqn: InternPool.NullTerminatedString,
4585 air: *const Air,
4586 w: *Io.Writer,
4587) Io.Writer.Error!void {
4588 const zcu = pt.zcu;
4589 const ip = &zcu.intern_pool;
4590 try w.print("# Begin Function AIR: {f}:\n", .{fqn.fmt(ip)});
4591 try air.write(w, zcu, liveness);
4592 try w.print("# End Function AIR: {f}\n\n", .{fqn.fmt(ip)});
4593}
src/codegen/llvm.zig+66-59
...@@ -10,6 +10,7 @@ const build_options = @import("build_options");...@@ -10,6 +10,7 @@ const build_options = @import("build_options");
10const Air = @import("../Air.zig");10const Air = @import("../Air.zig");
11const codegen = @import("../codegen.zig");11const codegen = @import("../codegen.zig");
12const Compilation = @import("../Compilation.zig");12const Compilation = @import("../Compilation.zig");
13const debugLogScopeEnabled = @import("../main.zig").debugLogScopeEnabled;
13const InternPool = @import("../InternPool.zig");14const InternPool = @import("../InternPool.zig");
14const link = @import("../link.zig");15const link = @import("../link.zig");
15const Module = @import("../Module.zig");16const Module = @import("../Module.zig");
...@@ -331,12 +332,10 @@ pub const Object = struct {...@@ -331,12 +332,10 @@ pub const Object = struct {
331 }332 }
332333
333 pub const EmitOptions = struct {334 pub const EmitOptions = struct {
334 pre_ir_path: ?[]const u8,
335 pre_bc_path: ?[]const u8,
336 bin_path: ?[:0]const u8,335 bin_path: ?[:0]const u8,
337 asm_path: ?[:0]const u8,336 asm_path: ?[:0]const u8,
338 post_ir_path: ?[:0]const u8,337 opt_ir_path: ?[:0]const u8,
339 post_bc_path: ?[:0]const u8,338 opt_bc_path: ?[:0]const u8,
340339
341 is_debug: bool,340 is_debug: bool,
342 is_small: bool,341 is_small: bool,
...@@ -351,6 +350,7 @@ pub const Object = struct {...@@ -351,6 +350,7 @@ pub const Object = struct {
351 const comp = zcu.comp;350 const comp = zcu.comp;
352 const io = comp.io;351 const io = comp.io;
353 const diags = &comp.link_diags;352 const diags = &comp.link_diags;
353 const target = &comp.root_mod.resolved_target.result;
354354
355 {355 {
356 if (o.errors_len_variable != .none) {356 if (o.errors_len_variable != .none) {
...@@ -403,7 +403,7 @@ pub const Object = struct {...@@ -403,7 +403,7 @@ pub const Object = struct {
403 const behavior_max = try o.builder.metadataConstant(try o.builder.intConst(.i32, 7));403 const behavior_max = try o.builder.metadataConstant(try o.builder.intConst(.i32, 7));
404 const behavior_min = try o.builder.metadataConstant(try o.builder.intConst(.i32, 8));404 const behavior_min = try o.builder.metadataConstant(try o.builder.intConst(.i32, 8));
405405
406 if (target_util.llvmMachineAbi(&comp.root_mod.resolved_target.result)) |abi| {406 if (target_util.llvmMachineAbi(target)) |abi| {
407 module_flags.appendAssumeCapacity(try o.builder.metadataTuple(&.{407 module_flags.appendAssumeCapacity(try o.builder.metadataTuple(&.{
408 behavior_error,408 behavior_error,
409 (try o.builder.metadataString("target-abi")).toMetadata(),409 (try o.builder.metadataString("target-abi")).toMetadata(),
...@@ -411,7 +411,7 @@ pub const Object = struct {...@@ -411,7 +411,7 @@ pub const Object = struct {
411 }));411 }));
412 }412 }
413413
414 const pic_level = target_util.picLevel(&comp.root_mod.resolved_target.result);414 const pic_level = target_util.picLevel(target);
415 if (comp.root_mod.pic) {415 if (comp.root_mod.pic) {
416 module_flags.appendAssumeCapacity(try o.builder.metadataTuple(&.{416 module_flags.appendAssumeCapacity(try o.builder.metadataTuple(&.{
417 behavior_min,417 behavior_min,
...@@ -434,7 +434,7 @@ pub const Object = struct {...@@ -434,7 +434,7 @@ pub const Object = struct {
434 (try o.builder.metadataString("Code Model")).toMetadata(),434 (try o.builder.metadataString("Code Model")).toMetadata(),
435 try o.builder.metadataConstant(try o.builder.intConst(.i32, @as(435 try o.builder.metadataConstant(try o.builder.intConst(.i32, @as(
436 i32,436 i32,
437 switch (codeModel(comp.root_mod.code_model, &comp.root_mod.resolved_target.result)) {437 switch (codeModel(comp.root_mod.code_model, target)) {
438 .default => unreachable,438 .default => unreachable,
439 .tiny => 0,439 .tiny => 0,
440 .small => 1,440 .small => 1,
...@@ -480,7 +480,6 @@ pub const Object = struct {...@@ -480,7 +480,6 @@ pub const Object = struct {
480 }480 }
481 }481 }
482482
483 const target = &comp.root_mod.resolved_target.result;
484 if (target.os.tag == .windows and (target.cpu.arch == .x86_64 or target.cpu.arch == .x86)) {483 if (target.os.tag == .windows and (target.cpu.arch == .x86_64 or target.cpu.arch == .x86)) {
485 // Add the "RegCallv4" flag so that any functions using `x86_regcallcc` use regcall484 // Add the "RegCallv4" flag so that any functions using `x86_regcallcc` use regcall
486 // v4, which is essentially a requirement on Windows. See corresponding logic in485 // v4, which is essentially a requirement on Windows. See corresponding logic in
...@@ -515,21 +514,26 @@ pub const Object = struct {...@@ -515,21 +514,26 @@ pub const Object = struct {
515514
516 const emit_asm_msg = options.asm_path orelse "(none)";515 const emit_asm_msg = options.asm_path orelse "(none)";
517 const emit_bin_msg = options.bin_path orelse "(none)";516 const emit_bin_msg = options.bin_path orelse "(none)";
518 const post_llvm_ir_msg = options.post_ir_path orelse "(none)";517 const opt_llvm_ir_msg = options.opt_ir_path orelse "(none)";
519 const post_llvm_bc_msg = options.post_bc_path orelse "(none)";518 const opt_llvm_bc_msg = options.opt_bc_path orelse "(none)";
520 log.debug("emit LLVM object asm={s} bin={s} ir={s} bc={s}", .{519 log.debug("emit LLVM object asm={s} bin={s} ir={s} bc={s}", .{
521 emit_asm_msg, emit_bin_msg, post_llvm_ir_msg, post_llvm_bc_msg,520 emit_asm_msg, emit_bin_msg, opt_llvm_ir_msg, opt_llvm_bc_msg,
522 });521 });
522 const log_opt_llvm_ir = debugLogScopeEnabled("opt-llvm-ir");
523523
524 const context, const module = emit: {524 const context, const module = emit: {
525 if (options.pre_ir_path) |path| {525 {
526 if (std.mem.eql(u8, path, "-")) {526 var p: Builder.Print = .{ .name = comp.root_name, .builder = &o.builder, .err = null };
527 o.builder.dump(io);527 std.log.scoped(.@"llvm-ir").debug("{f}", .{&p});
528 } else {528 if (p.err) |err| return err;
529 o.builder.printToFilePath(io, Io.Dir.cwd(), path) catch |err| {529 }
530 log.err("failed printing LLVM module to \"{s}\": {t}", .{ path, err });530
531 };531 if (target.ofmt == .llvmir) {
532 }532 const path = comp.bin_file.?.emit;
533 o.builder.printToFilePath(io, path.root_dir.handle, path.sub_path) catch |err| {
534 return diags.fail("failed emitting LLVM module to {qf}: {t}", .{ path, err });
535 };
536 return;
533 }537 }
534538
535 const bitcode = try o.builder.toBitcode(o.gpa, .{539 const bitcode = try o.builder.toBitcode(o.gpa, .{
...@@ -538,23 +542,26 @@ pub const Object = struct {...@@ -538,23 +542,26 @@ pub const Object = struct {
538 });542 });
539 defer o.gpa.free(bitcode);543 defer o.gpa.free(bitcode);
540544
541 if (options.pre_bc_path) |path| {545 if (target.ofmt == .llvmbc) {
542 var file = Io.Dir.cwd().createFile(io, path, .{}) catch |err|546 const path = comp.bin_file.?.emit;
543 return diags.fail("failed to create '{s}': {t}", .{ path, err });547 var file = path.root_dir.handle.createFile(io, path.sub_path, .{}) catch |err|
548 return diags.fail("failed to create {qf}: {t}", .{ path, err });
544 defer file.close(io);549 defer file.close(io);
545550
546 file.writeStreamingAll(io, @ptrCast(bitcode)) catch |err|551 file.writeStreamingAll(io, @ptrCast(bitcode)) catch |err|
547 return diags.fail("failed to write to '{s}': {t}", .{ path, err });552 return diags.fail("failed to write to {qf}: {t}", .{ path, err });
553 return;
548 }554 }
549555
550 if (options.asm_path == null and options.bin_path == null and556 if (options.asm_path == null and options.bin_path == null and
551 options.post_ir_path == null and options.post_bc_path == null) return;557 options.opt_ir_path == null and options.opt_bc_path == null and
558 !log_opt_llvm_ir) return;
552559
553 if (!build_options.have_llvm or !comp.config.use_lib_llvm) {560 if (!build_options.have_llvm or !comp.config.use_lib_llvm) {
554 return diags.fail("emitting without libllvm not implemented", .{});561 return diags.fail("emitting without libllvm not implemented", .{});
555 }562 }
556563
557 initializeLLVMTarget(io, comp.root_mod.resolved_target.result.cpu.arch);564 initializeLLVMTarget(io, target.cpu.arch);
558565
559 const context: *bindings.Context = .create();566 const context: *bindings.Context = .create();
560 errdefer context.dispose();567 errdefer context.dispose();
...@@ -577,9 +584,9 @@ pub const Object = struct {...@@ -577,9 +584,9 @@ pub const Object = struct {
577 };584 };
578 defer context.dispose();585 defer context.dispose();
579586
580 var target: *bindings.Target = undefined;587 var llvm_target: *bindings.Target = undefined;
581 var error_message: [*:0]const u8 = undefined;588 var error_message: [*:0]const u8 = undefined;
582 if (bindings.Target.getFromTriple(target_triple_sentinel, &target, &error_message).toBool()) {589 if (bindings.Target.getFromTriple(target_triple_sentinel, &llvm_target, &error_message).toBool()) {
583 defer bindings.disposeMessage(error_message);590 defer bindings.disposeMessage(error_message);
584 return diags.fail("LLVM failed to parse '{s}': {s}", .{ target_triple_sentinel, error_message });591 return diags.fail("LLVM failed to parse '{s}': {s}", .{ target_triple_sentinel, error_message });
585 }592 }
...@@ -598,7 +605,7 @@ pub const Object = struct {...@@ -598,7 +605,7 @@ pub const Object = struct {
598 else605 else
599 .Static;606 .Static;
600607
601 const code_model: bindings.CodeModel = switch (codeModel(comp.root_mod.code_model, &comp.root_mod.resolved_target.result)) {608 const code_model: bindings.CodeModel = switch (codeModel(comp.root_mod.code_model, target)) {
602 .default => .Default,609 .default => .Default,
603 .tiny => .Tiny,610 .tiny => .Tiny,
604 .small => .Small,611 .small => .Small,
...@@ -607,24 +614,22 @@ pub const Object = struct {...@@ -607,24 +614,22 @@ pub const Object = struct {
607 .large => .Large,614 .large => .Large,
608 };615 };
609616
610 const float_abi: bindings.TargetMachine.FloatABI = if (comp.root_mod.resolved_target.result.abi.float() == .hard)
611 .Hard
612 else
613 .Soft;
614
615 var target_machine = bindings.TargetMachine.create(617 var target_machine = bindings.TargetMachine.create(
616 target,618 llvm_target,
617 target_triple_sentinel,619 target_triple_sentinel,
618 if (comp.root_mod.resolved_target.result.cpu.model.llvm_name) |s| s.ptr else null,620 if (target.cpu.model.llvm_name) |s| s.ptr else null,
619 comp.root_mod.resolved_target.llvm_cpu_features.?,621 comp.root_mod.llvm_cpu_features.?,
620 opt_level,622 opt_level,
621 reloc_mode,623 reloc_mode,
622 code_model,624 code_model,
623 comp.function_sections,625 comp.function_sections,
624 comp.data_sections,626 comp.data_sections,
625 float_abi,627 switch (target.abi.float()) {
626 if (target_util.llvmMachineAbi(&comp.root_mod.resolved_target.result)) |s| s.ptr else null,628 .hard => .Hard,
627 target_util.useEmulatedTls(&comp.root_mod.resolved_target.result),629 .soft => .Soft,
630 },
631 if (target_util.llvmMachineAbi(target)) |s| s.ptr else null,
632 target_util.useEmulatedTls(target),
628 );633 );
629 errdefer target_machine.dispose();634 errdefer target_machine.dispose();
630635
...@@ -634,7 +639,10 @@ pub const Object = struct {...@@ -634,7 +639,10 @@ pub const Object = struct {
634639
635 // Unfortunately, LLVM shits the bed when we ask for both binary and assembly.640 // Unfortunately, LLVM shits the bed when we ask for both binary and assembly.
636 // So we call the entire pipeline multiple times if this is requested.641 // So we call the entire pipeline multiple times if this is requested.
637 // var error_message: [*:0]const u8 = undefined;642 var time_report_c_str: ?[*:0]u8 = null;
643 defer if (time_report_c_str) |time_report| bindings.disposeMessage(time_report);
644 var llvm_ir_c_str: ?[*:0]u8 = null;
645 defer if (llvm_ir_c_str) |llvm_ir| bindings.disposeMessage(llvm_ir);
638 var lowered_options: bindings.TargetMachine.EmitOptions = .{646 var lowered_options: bindings.TargetMachine.EmitOptions = .{
639 .is_debug = options.is_debug,647 .is_debug = options.is_debug,
640 .is_small = options.is_small,648 .is_small = options.is_small,
...@@ -648,11 +656,12 @@ pub const Object = struct {...@@ -648,11 +656,12 @@ pub const Object = struct {
648 .allow_fast_isel = true,656 .allow_fast_isel = true,
649 // LLVM's RISC-V backend for some reason enables the machine outliner by default even657 // LLVM's RISC-V backend for some reason enables the machine outliner by default even
650 // though it's clearly not ready and produces multiple miscompilations in our std tests.658 // though it's clearly not ready and produces multiple miscompilations in our std tests.
651 .allow_machine_outliner = !comp.root_mod.resolved_target.result.cpu.arch.isRISCV(),659 .allow_machine_outliner = !target.cpu.arch.isRISCV(),
652 .asm_filename = null,660 .asm_filename = null,
653 .bin_filename = if (options.bin_path) |x| x.ptr else null,661 .bin_filename = if (options.bin_path) |x| x.ptr else null,
654 .llvm_ir_filename = if (options.post_ir_path) |x| x.ptr else null,662 .llvm_ir_filename = if (options.opt_ir_path) |x| x.ptr else null,
655 .bitcode_filename = if (options.post_bc_path) |x| x.ptr else null,663 .bitcode_filename = if (options.opt_bc_path) |x| x.ptr else null,
664 .llvm_ir_out = if (log_opt_llvm_ir) &llvm_ir_c_str else null,
656665
657 // `.coverage` value is only used when `.sancov` is enabled.666 // `.coverage` value is only used when `.sancov` is enabled.
658 .sancov = options.fuzz or comp.config.san_cov_trace_pc_guard,667 .sancov = options.fuzz or comp.config.san_cov_trace_pc_guard,
...@@ -684,33 +693,31 @@ pub const Object = struct {...@@ -684,33 +693,31 @@ pub const Object = struct {
684 };693 };
685 if (options.asm_path != null and options.bin_path != null) {694 if (options.asm_path != null and options.bin_path != null) {
686 if (target_machine.emitToFile(module, &error_message, &lowered_options)) {695 if (target_machine.emitToFile(module, &error_message, &lowered_options)) {
687 defer bindings.disposeMessage(error_message);
688 return diags.fail("LLVM failed to emit bin={s} ir={s}: {s}", .{696 return diags.fail("LLVM failed to emit bin={s} ir={s}: {s}", .{
689 emit_bin_msg, post_llvm_ir_msg, error_message,697 emit_bin_msg, opt_llvm_ir_msg, error_message,
690 });698 });
691 }699 }
692 lowered_options.bin_filename = null;700 lowered_options.bin_filename = null;
693 lowered_options.llvm_ir_filename = null;701 lowered_options.llvm_ir_filename = null;
694 lowered_options.bitcode_filename = null;702 lowered_options.bitcode_filename = null;
703 lowered_options.llvm_ir_out = null;
695 }704 }
696705 if (options.time_report) |_| lowered_options.time_report_out = &time_report_c_str;
697 var time_report_c_str: [*:0]u8 = undefined;
698 if (options.time_report != null) {
699 lowered_options.time_report_out = &time_report_c_str;
700 }
701
702 lowered_options.asm_filename = if (options.asm_path) |x| x.ptr else null;706 lowered_options.asm_filename = if (options.asm_path) |x| x.ptr else null;
703 if (target_machine.emitToFile(module, &error_message, &lowered_options)) {707 if (target_machine.emitToFile(module, &error_message, &lowered_options)) {
704 defer bindings.disposeMessage(error_message);708 defer bindings.disposeMessage(error_message);
705 return diags.fail("LLVM failed to emit asm={s} bin={s} ir={s} bc={s}: {s}", .{709 return diags.fail("LLVM failed to emit asm={s} bin={s} ir={s} bc={s}: {s}", .{
706 emit_asm_msg, emit_bin_msg, post_llvm_ir_msg, post_llvm_bc_msg, error_message,710 emit_asm_msg, emit_bin_msg, opt_llvm_ir_msg, opt_llvm_bc_msg, error_message,
707 });711 });
708 }712 }
709 if (options.time_report) |tr| {713 if (log_opt_llvm_ir) std.log.scoped(.@"opt-llvm-ir").debug("{s}", .{
710 defer std.c.free(time_report_c_str);714 llvm_ir_c_str orelse return error.OutOfMemory,
711 const time_report_data = std.mem.span(time_report_c_str);715 });
712 assert(tr.llvm_pass_timings.len == 0);716 if (options.time_report) |time_report| {
713 tr.llvm_pass_timings = try comp.gpa.dupe(u8, time_report_data);717 assert(time_report.llvm_pass_timings.len == 0);
718 time_report.llvm_pass_timings = try comp.gpa.dupe(u8, std.mem.span(
719 time_report_c_str orelse return error.OutOfMemory,
720 ));
714 }721 }
715 }722 }
716723
...@@ -2184,10 +2191,10 @@ pub const Object = struct {...@@ -2184,10 +2191,10 @@ pub const Object = struct {
2184 .value = try o.builder.string(s),2191 .value = try o.builder.string(s),
2185 } }, &o.builder);2192 } }, &o.builder);
2186 }2193 }
2187 if (owner_mod.resolved_target.llvm_cpu_features) |s| {2194 if (owner_mod.llvm_cpu_features) |s| {
2188 try attributes.addFnAttr(.{ .string = .{2195 try attributes.addFnAttr(.{ .string = .{
2189 .kind = try o.builder.string("target-features"),2196 .kind = try o.builder.string("target-features"),
2190 .value = try o.builder.string(std.mem.span(s)),2197 .value = try o.builder.string(s),
2191 } }, &o.builder);2198 } }, &o.builder);
2192 }2199 }
21932200
src/codegen/llvm/bindings.zig+3-2
...@@ -51,7 +51,7 @@ pub const Module = opaque {...@@ -51,7 +51,7 @@ pub const Module = opaque {
51};51};
5252
53pub const disposeMessage = LLVMDisposeMessage;53pub const disposeMessage = LLVMDisposeMessage;
54extern fn LLVMDisposeMessage(Message: [*:0]const u8) void;54extern fn LLVMDisposeMessage(Message: ?[*:0]const u8) void;
5555
56pub const TargetMachine = opaque {56pub const TargetMachine = opaque {
57 pub const FloatABI = enum(c_int) {57 pub const FloatABI = enum(c_int) {
...@@ -85,7 +85,7 @@ pub const TargetMachine = opaque {...@@ -85,7 +85,7 @@ pub const TargetMachine = opaque {
85 pub const EmitOptions = extern struct {85 pub const EmitOptions = extern struct {
86 is_debug: bool,86 is_debug: bool,
87 is_small: bool,87 is_small: bool,
88 time_report_out: ?*[*:0]u8,88 time_report_out: ?*?[*:0]u8,
89 tsan: bool,89 tsan: bool,
90 sancov: bool,90 sancov: bool,
91 lto: LtoPhase,91 lto: LtoPhase,
...@@ -95,6 +95,7 @@ pub const TargetMachine = opaque {...@@ -95,6 +95,7 @@ pub const TargetMachine = opaque {
95 bin_filename: ?[*:0]const u8,95 bin_filename: ?[*:0]const u8,
96 llvm_ir_filename: ?[*:0]const u8,96 llvm_ir_filename: ?[*:0]const u8,
97 bitcode_filename: ?[*:0]const u8,97 bitcode_filename: ?[*:0]const u8,
98 llvm_ir_out: ?*?[*:0]u8,
98 coverage: Coverage,99 coverage: Coverage,
99100
100 pub const LtoPhase = enum(c_int) {101 pub const LtoPhase = enum(c_int) {
src/codegen/riscv64/CodeGen.zig+1-1
...@@ -27,7 +27,7 @@ const Target = std.Target;...@@ -27,7 +27,7 @@ const Target = std.Target;
27const log = std.log.scoped(.riscv_codegen);27const log = std.log.scoped(.riscv_codegen);
28const tracking_log = std.log.scoped(.tracking);28const tracking_log = std.log.scoped(.tracking);
29const verbose_tracking_log = std.log.scoped(.verbose_tracking);29const verbose_tracking_log = std.log.scoped(.verbose_tracking);
30const wip_mir_log = std.log.scoped(.wip_mir);30const wip_mir_log = std.log.scoped(.@"wip-mir");
31const Alignment = InternPool.Alignment;31const Alignment = InternPool.Alignment;
3232
33const bits = @import("bits.zig");33const bits = @import("bits.zig");
src/codegen/x86_64/CodeGen.zig+1-1
...@@ -5,7 +5,7 @@ const link = @import("../../link.zig");...@@ -5,7 +5,7 @@ const link = @import("../../link.zig");
5const log = std.log.scoped(.codegen);5const log = std.log.scoped(.codegen);
6const tracking_log = std.log.scoped(.tracking);6const tracking_log = std.log.scoped(.tracking);
7const verbose_tracking_log = std.log.scoped(.verbose_tracking);7const verbose_tracking_log = std.log.scoped(.verbose_tracking);
8const wip_mir_log = std.log.scoped(.wip_mir);8const wip_mir_log = std.log.scoped(.@"wip-mir");
9const Writer = std.Io.Writer;9const Writer = std.Io.Writer;
1010
11const Air = @import("../../Air.zig");11const Air = @import("../../Air.zig");
src/dev.zig+2
...@@ -112,6 +112,7 @@ pub const Env = enum {...@@ -112,6 +112,7 @@ pub const Env = enum {
112 .loongarch_backend,112 .loongarch_backend,
113 .spork8_backend,113 .spork8_backend,
114 .lld_linker,114 .lld_linker,
115 .llvm_linker,
115 .coff_linker,116 .coff_linker,
116 .elf_linker,117 .elf_linker,
117 .elf2_linker,118 .elf2_linker,
...@@ -333,6 +334,7 @@ pub const Feature = enum {...@@ -333,6 +334,7 @@ pub const Feature = enum {
333 spork8_backend,334 spork8_backend,
334335
335 lld_linker,336 lld_linker,
337 llvm_linker,
336 coff_linker,338 coff_linker,
337 elf_linker,339 elf_linker,
338 elf2_linker,340 elf2_linker,
src/libs/freebsd.zig-4
...@@ -1120,10 +1120,6 @@ fn buildSharedLib(...@@ -1120,10 +1120,6 @@ fn buildSharedLib(
1120 .emit_bin = .{ .yes_path = try bin_directory.join(arena, &.{basename}) },1120 .emit_bin = .{ .yes_path = try bin_directory.join(arena, &.{basename}) },
1121 .verbose_cc = comp.verbose_cc,1121 .verbose_cc = comp.verbose_cc,
1122 .verbose_link = comp.verbose_link,1122 .verbose_link = comp.verbose_link,
1123 .verbose_air = comp.verbose_air,
1124 .verbose_llvm_ir = comp.verbose_llvm_ir,
1125 .verbose_llvm_bc = comp.verbose_llvm_bc,
1126 .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features,
1127 .clang_passthrough_mode = comp.clang_passthrough_mode,1123 .clang_passthrough_mode = comp.clang_passthrough_mode,
1128 .version = version,1124 .version = version,
1129 .version_script = .{1125 .version_script = .{
src/libs/glibc.zig-4
...@@ -1268,10 +1268,6 @@ fn buildSharedLib(...@@ -1268,10 +1268,6 @@ fn buildSharedLib(
1268 .emit_bin = .{ .yes_path = try bin_directory.join(arena, &.{basename}) },1268 .emit_bin = .{ .yes_path = try bin_directory.join(arena, &.{basename}) },
1269 .verbose_cc = comp.verbose_cc,1269 .verbose_cc = comp.verbose_cc,
1270 .verbose_link = comp.verbose_link,1270 .verbose_link = comp.verbose_link,
1271 .verbose_air = comp.verbose_air,
1272 .verbose_llvm_ir = comp.verbose_llvm_ir,
1273 .verbose_llvm_bc = comp.verbose_llvm_bc,
1274 .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features,
1275 .clang_passthrough_mode = comp.clang_passthrough_mode,1271 .clang_passthrough_mode = comp.clang_passthrough_mode,
1276 .version = version,1272 .version = version,
1277 .version_script = .{1273 .version_script = .{
src/libs/libcxx.zig-8
...@@ -260,10 +260,6 @@ pub fn buildLibCxx(comp: *Compilation, prog_node: std.Progress.Node) BuildError!...@@ -260,10 +260,6 @@ pub fn buildLibCxx(comp: *Compilation, prog_node: std.Progress.Node) BuildError!
260 .c_source_files = c_source_files.items,260 .c_source_files = c_source_files.items,
261 .verbose_cc = comp.verbose_cc,261 .verbose_cc = comp.verbose_cc,
262 .verbose_link = comp.verbose_link,262 .verbose_link = comp.verbose_link,
263 .verbose_air = comp.verbose_air,
264 .verbose_llvm_ir = comp.verbose_llvm_ir,
265 .verbose_llvm_bc = comp.verbose_llvm_bc,
266 .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features,
267 .clang_passthrough_mode = comp.clang_passthrough_mode,263 .clang_passthrough_mode = comp.clang_passthrough_mode,
268 .skip_linker_dependencies = true,264 .skip_linker_dependencies = true,
269 .environ_map = comp.environ_map,265 .environ_map = comp.environ_map,
...@@ -445,10 +441,6 @@ pub fn buildLibCxxAbi(comp: *Compilation, prog_node: std.Progress.Node) BuildErr...@@ -445,10 +441,6 @@ pub fn buildLibCxxAbi(comp: *Compilation, prog_node: std.Progress.Node) BuildErr
445 .c_source_files = c_source_files.items,441 .c_source_files = c_source_files.items,
446 .verbose_cc = comp.verbose_cc,442 .verbose_cc = comp.verbose_cc,
447 .verbose_link = comp.verbose_link,443 .verbose_link = comp.verbose_link,
448 .verbose_air = comp.verbose_air,
449 .verbose_llvm_ir = comp.verbose_llvm_ir,
450 .verbose_llvm_bc = comp.verbose_llvm_bc,
451 .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features,
452 .clang_passthrough_mode = comp.clang_passthrough_mode,444 .clang_passthrough_mode = comp.clang_passthrough_mode,
453 .skip_linker_dependencies = true,445 .skip_linker_dependencies = true,
454 .environ_map = comp.environ_map,446 .environ_map = comp.environ_map,
src/libs/libtsan.zig-4
...@@ -295,10 +295,6 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo...@@ -295,10 +295,6 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo
295 .c_source_files = c_source_files.items,295 .c_source_files = c_source_files.items,
296 .verbose_cc = comp.verbose_cc,296 .verbose_cc = comp.verbose_cc,
297 .verbose_link = comp.verbose_link,297 .verbose_link = comp.verbose_link,
298 .verbose_air = comp.verbose_air,
299 .verbose_llvm_ir = comp.verbose_llvm_ir,
300 .verbose_llvm_bc = comp.verbose_llvm_bc,
301 .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features,
302 .clang_passthrough_mode = comp.clang_passthrough_mode,298 .clang_passthrough_mode = comp.clang_passthrough_mode,
303 .skip_linker_dependencies = skip_linker_dependencies,299 .skip_linker_dependencies = skip_linker_dependencies,
304 .linker_allow_shlib_undefined = linker_allow_shlib_undefined,300 .linker_allow_shlib_undefined = linker_allow_shlib_undefined,
src/libs/libunwind.zig-4
...@@ -157,10 +157,6 @@ pub fn buildStaticLib(comp: *Compilation, prog_node: std.Progress.Node) BuildErr...@@ -157,10 +157,6 @@ pub fn buildStaticLib(comp: *Compilation, prog_node: std.Progress.Node) BuildErr
157 .c_source_files = &c_source_files,157 .c_source_files = &c_source_files,
158 .verbose_cc = comp.verbose_cc,158 .verbose_cc = comp.verbose_cc,
159 .verbose_link = comp.verbose_link,159 .verbose_link = comp.verbose_link,
160 .verbose_air = comp.verbose_air,
161 .verbose_llvm_ir = comp.verbose_llvm_ir,
162 .verbose_llvm_bc = comp.verbose_llvm_bc,
163 .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features,
164 .clang_passthrough_mode = comp.clang_passthrough_mode,160 .clang_passthrough_mode = comp.clang_passthrough_mode,
165 .skip_linker_dependencies = true,161 .skip_linker_dependencies = true,
166 .environ_map = comp.environ_map,162 .environ_map = comp.environ_map,
src/libs/musl.zig-3
...@@ -246,9 +246,6 @@ pub fn buildCrtFile(comp: *Compilation, in_crt_file: CrtFile, prog_node: std.Pro...@@ -246,9 +246,6 @@ pub fn buildCrtFile(comp: *Compilation, in_crt_file: CrtFile, prog_node: std.Pro
246 .emit_bin = .yes_cache,246 .emit_bin = .yes_cache,
247 .verbose_cc = comp.verbose_cc,247 .verbose_cc = comp.verbose_cc,
248 .verbose_link = comp.verbose_link,248 .verbose_link = comp.verbose_link,
249 .verbose_air = comp.verbose_air,
250 .verbose_llvm_ir = comp.verbose_llvm_ir,
251 .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features,
252 .clang_passthrough_mode = comp.clang_passthrough_mode,249 .clang_passthrough_mode = comp.clang_passthrough_mode,
253 .c_source_files = &.{250 .c_source_files = &.{
254 .{251 .{
src/libs/netbsd.zig-4
...@@ -771,10 +771,6 @@ fn buildSharedLib(...@@ -771,10 +771,6 @@ fn buildSharedLib(
771 .emit_bin = .{ .yes_path = try bin_directory.join(arena, &.{basename}) },771 .emit_bin = .{ .yes_path = try bin_directory.join(arena, &.{basename}) },
772 .verbose_cc = comp.verbose_cc,772 .verbose_cc = comp.verbose_cc,
773 .verbose_link = comp.verbose_link,773 .verbose_link = comp.verbose_link,
774 .verbose_air = comp.verbose_air,
775 .verbose_llvm_ir = comp.verbose_llvm_ir,
776 .verbose_llvm_bc = comp.verbose_llvm_bc,
777 .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features,
778 .clang_passthrough_mode = comp.clang_passthrough_mode,774 .clang_passthrough_mode = comp.clang_passthrough_mode,
779 .version = version,775 .version = version,
780 .soname = soname,776 .soname = soname,
src/libs/openbsd.zig-4
...@@ -691,10 +691,6 @@ fn buildSharedLib(...@@ -691,10 +691,6 @@ fn buildSharedLib(
691 .emit_bin = .{ .yes_path = try bin_directory.join(arena, &.{basename}) },691 .emit_bin = .{ .yes_path = try bin_directory.join(arena, &.{basename}) },
692 .verbose_cc = comp.verbose_cc,692 .verbose_cc = comp.verbose_cc,
693 .verbose_link = comp.verbose_link,693 .verbose_link = comp.verbose_link,
694 .verbose_air = comp.verbose_air,
695 .verbose_llvm_ir = comp.verbose_llvm_ir,
696 .verbose_llvm_bc = comp.verbose_llvm_bc,
697 .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features,
698 .clang_passthrough_mode = comp.clang_passthrough_mode,694 .clang_passthrough_mode = comp.clang_passthrough_mode,
699 .soname = soname,695 .soname = soname,
700 .c_source_files = &c_source_files,696 .c_source_files = &c_source_files,
src/link.zig+35-4
...@@ -550,6 +550,7 @@ pub const File = struct {...@@ -550,6 +550,7 @@ pub const File = struct {
550 return &ptr.base;550 return &ptr.base;
551 },551 },
552 .lld => unreachable, // not known from ofmt552 .lld => unreachable, // not known from ofmt
553 .llvm => |tag| return createDummy(arena, tag, comp, emit),
553 }554 }
554 }555 }
555556
...@@ -573,9 +574,26 @@ pub const File = struct {...@@ -573,9 +574,26 @@ pub const File = struct {
573 return &ptr.base;574 return &ptr.base;
574 },575 },
575 .lld => unreachable, // not known from ofmt576 .lld => unreachable, // not known from ofmt
577 .llvm => |tag| return createDummy(arena, tag, comp, emit),
576 }578 }
577 }579 }
578580
581 fn createDummy(arena: Allocator, tag: Tag, comp: *Compilation, path: Path) Allocator.Error!*File {
582 const base = try arena.create(File);
583 base.* = .{
584 .tag = tag,
585 .comp = comp,
586 .emit = path,
587 .file = null,
588 .gc_sections = false,
589 .print_gc_sections = false,
590 .build_id = .none,
591 .allow_shlib_undefined = false,
592 .stack_size = 0,
593 };
594 return base;
595 }
596
579 pub fn cast(base: *File, comptime tag: Tag) if (dev.env.supports(tag.devFeature())) ?*tag.Type() else ?noreturn {597 pub fn cast(base: *File, comptime tag: Tag) if (dev.env.supports(tag.devFeature())) ?*tag.Type() else ?noreturn {
580 return if (dev.env.supports(tag.devFeature()) and base.tag == tag) @fieldParentPtr("base", base) else null;598 return if (dev.env.supports(tag.devFeature()) and base.tag == tag) @fieldParentPtr("base", base) else null;
581 }599 }
...@@ -606,7 +624,7 @@ pub const File = struct {...@@ -606,7 +624,7 @@ pub const File = struct {
606 const gpa = comp.gpa;624 const gpa = comp.gpa;
607 const io = comp.io;625 const io = comp.io;
608 switch (base.tag) {626 switch (base.tag) {
609 .lld => assert(base.file == null),627 .lld, .llvm => assert(base.file == null),
610 .elf, .macho, .wasm => {628 .elf, .macho, .wasm => {
611 dev.checkAny(&.{ .coff_linker, .elf_linker, .macho_linker, .plan9_linker, .wasm_linker });629 dev.checkAny(&.{ .coff_linker, .elf_linker, .macho_linker, .plan9_linker, .wasm_linker });
612 if (base.file != null) return;630 if (base.file != null) return;
...@@ -706,7 +724,7 @@ pub const File = struct {...@@ -706,7 +724,7 @@ pub const File = struct {
706 if (!base.canMakeExecutable())724 if (!base.canMakeExecutable())
707 return;725 return;
708 switch (base.tag) {726 switch (base.tag) {
709 .lld => assert(base.file == null),727 .lld, .llvm => assert(base.file == null),
710 .elf => if (base.file) |f| {728 .elf => if (base.file) |f| {
711 dev.check(.elf_linker);729 dev.check(.elf_linker);
712 f.close(io);730 f.close(io);
...@@ -827,6 +845,7 @@ pub const File = struct {...@@ -827,6 +845,7 @@ pub const File = struct {
827845
828 switch (base.tag) {846 switch (base.tag) {
829 .lld => unreachable,847 .lld => unreachable,
848 .llvm => unreachable,
830 .plan9 => unreachable,849 .plan9 => unreachable,
831 inline else => |tag| {850 inline else => |tag| {
832 dev.check(tag.devFeature());851 dev.check(tag.devFeature());
...@@ -862,6 +881,7 @@ pub const File = struct {...@@ -862,6 +881,7 @@ pub const File = struct {
862 assert(pt.zcu.llvm_object == null);881 assert(pt.zcu.llvm_object == null);
863 switch (base.tag) {882 switch (base.tag) {
864 .lld => unreachable,883 .lld => unreachable,
884 .llvm => unreachable,
865 .plan9 => unreachable,885 .plan9 => unreachable,
866 inline else => |tag| {886 inline else => |tag| {
867 dev.check(tag.devFeature());887 dev.check(tag.devFeature());
...@@ -897,6 +917,7 @@ pub const File = struct {...@@ -897,6 +917,7 @@ pub const File = struct {
897 }917 }
898 switch (base.tag) {918 switch (base.tag) {
899 .lld => unreachable,919 .lld => unreachable,
920 .llvm => unreachable,
900 .plan9 => unreachable,921 .plan9 => unreachable,
901 .spirv => {},922 .spirv => {},
902 .coff => {},923 .coff => {},
...@@ -941,6 +962,7 @@ pub const File = struct {...@@ -941,6 +962,7 @@ pub const File = struct {
941 base.releaseLock();962 base.releaseLock();
942 if (base.file) |f| f.close(io);963 if (base.file) |f| f.close(io);
943 switch (base.tag) {964 switch (base.tag) {
965 .llvm => {},
944 .plan9 => unreachable,966 .plan9 => unreachable,
945 inline else => |tag| {967 inline else => |tag| {
946 dev.check(tag.devFeature());968 dev.check(tag.devFeature());
...@@ -1003,6 +1025,7 @@ pub const File = struct {...@@ -1003,6 +1025,7 @@ pub const File = struct {
1003 }1025 }
1004 assert(base.post_prelink);1026 assert(base.post_prelink);
1005 switch (base.tag) {1027 switch (base.tag) {
1028 .llvm => {},
1006 .plan9 => unreachable,1029 .plan9 => unreachable,
1007 inline else => |tag| {1030 inline else => |tag| {
1008 dev.check(tag.devFeature());1031 dev.check(tag.devFeature());
...@@ -1030,6 +1053,7 @@ pub const File = struct {...@@ -1030,6 +1053,7 @@ pub const File = struct {
10301053
1031 switch (base.tag) {1054 switch (base.tag) {
1032 .lld => unreachable,1055 .lld => unreachable,
1056 .llvm => unreachable,
1033 .plan9 => unreachable,1057 .plan9 => unreachable,
1034 inline else => |tag| {1058 inline else => |tag| {
1035 dev.check(tag.devFeature());1059 dev.check(tag.devFeature());
...@@ -1056,6 +1080,7 @@ pub const File = struct {...@@ -1056,6 +1080,7 @@ pub const File = struct {
1056 assert(base.comp.zcu.?.llvm_object == null);1080 assert(base.comp.zcu.?.llvm_object == null);
1057 switch (base.tag) {1081 switch (base.tag) {
1058 .lld => unreachable,1082 .lld => unreachable,
1083 .llvm => unreachable,
1059 .c => unreachable,1084 .c => unreachable,
1060 .spirv => unreachable,1085 .spirv => unreachable,
1061 .wasm => unreachable,1086 .wasm => unreachable,
...@@ -1078,6 +1103,7 @@ pub const File = struct {...@@ -1078,6 +1103,7 @@ pub const File = struct {
1078 assert(pt.zcu.llvm_object == null);1103 assert(pt.zcu.llvm_object == null);
1079 switch (base.tag) {1104 switch (base.tag) {
1080 .lld => unreachable,1105 .lld => unreachable,
1106 .llvm => unreachable,
1081 .c => unreachable,1107 .c => unreachable,
1082 .spirv => unreachable,1108 .spirv => unreachable,
1083 .wasm => unreachable,1109 .wasm => unreachable,
...@@ -1095,6 +1121,7 @@ pub const File = struct {...@@ -1095,6 +1121,7 @@ pub const File = struct {
1095 assert(base.comp.zcu.?.llvm_object == null);1121 assert(base.comp.zcu.?.llvm_object == null);
1096 switch (base.tag) {1122 switch (base.tag) {
1097 .lld => unreachable,1123 .lld => unreachable,
1124 .llvm => unreachable,
1098 .c => unreachable,1125 .c => unreachable,
1099 .spirv => unreachable,1126 .spirv => unreachable,
1100 .wasm => unreachable,1127 .wasm => unreachable,
...@@ -1124,6 +1151,7 @@ pub const File = struct {...@@ -1124,6 +1151,7 @@ pub const File = struct {
1124 .spirv,1151 .spirv,
1125 .plan9,1152 .plan9,
1126 .lld,1153 .lld,
1154 .llvm,
1127 .spork8,1155 .spork8,
1128 => return .unimplemented,1156 => return .unimplemented,
1129 inline else => |tag| {1157 inline else => |tag| {
...@@ -1240,7 +1268,7 @@ pub const File = struct {...@@ -1240,7 +1268,7 @@ pub const File = struct {
1240 dev.check(tag.devFeature());1268 dev.check(tag.devFeature());
1241 return @as(*tag.Type(), @fieldParentPtr("base", base)).loadInput(input);1269 return @as(*tag.Type(), @fieldParentPtr("base", base)).loadInput(input);
1242 },1270 },
1243 .c, .spork8, .plan9, .lld => {},1271 .c, .spork8, .plan9, .lld, .llvm => {},
1244 }1272 }
1245 }1273 }
12461274
...@@ -1352,6 +1380,7 @@ pub const File = struct {...@@ -1352,6 +1380,7 @@ pub const File = struct {
1352 coff,1380 coff,
1353 elf,1381 elf,
1354 elf2,1382 elf2,
1383 llvm,
1355 macho,1384 macho,
1356 macho2,1385 macho2,
1357 c,1386 c,
...@@ -1366,13 +1395,14 @@ pub const File = struct {...@@ -1366,13 +1395,14 @@ pub const File = struct {
1366 .coff => Coff,1395 .coff => Coff,
1367 .elf => Elf,1396 .elf => Elf,
1368 .elf2 => Elf2,1397 .elf2 => Elf2,
1398 .llvm => File,
1369 .macho => MachO,1399 .macho => MachO,
1370 .macho2 => MachO2,1400 .macho2 => MachO2,
1371 .c => C,1401 .c => C,
1372 .wasm => Wasm,1402 .wasm => Wasm,
1373 .spirv => Spirv,1403 .spirv => Spirv,
1374 .lld => Lld,1404 .lld => Lld,
1375 .plan9 => comptime unreachable,1405 .plan9 => unreachable,
1376 .spork8 => Spork8,1406 .spork8 => Spork8,
1377 };1407 };
1378 }1408 }
...@@ -1381,6 +1411,7 @@ pub const File = struct {...@@ -1381,6 +1411,7 @@ pub const File = struct {
1381 return switch (ofmt) {1411 return switch (ofmt) {
1382 .coff => .coff,1412 .coff => .coff,
1383 .elf => if (use_new_linker) .elf2 else .elf,1413 .elf => if (use_new_linker) .elf2 else .elf,
1414 .llvmbc, .llvmir => .llvm,
1384 .macho => if (use_new_linker) .macho2 else .macho,1415 .macho => if (use_new_linker) .macho2 else .macho,
1385 .wasm => .wasm,1416 .wasm => .wasm,
1386 .plan9 => .plan9,1417 .plan9 => .plan9,
src/link/Elf.zig+1-3
...@@ -860,9 +860,7 @@ fn flushInner(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id) !void {...@@ -860,9 +860,7 @@ fn flushInner(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id) !void {
860860
861 // Dump the state for easy debugging.861 // Dump the state for easy debugging.
862 // State can be dumped via `--debug-log link_state`.862 // State can be dumped via `--debug-log link_state`.
863 if (build_options.enable_logging) {863 state_log.debug("{f}", .{self.dumpState()});
864 state_log.debug("{f}", .{self.dumpState()});
865 }
866864
867 // Beyond this point, everything has been allocated a virtual address and we can resolve865 // Beyond this point, everything has been allocated a virtual address and we can resolve
868 // the relocations, and commit objects to file.866 // the relocations, and commit objects to file.
src/link/Elf/ZigObject.zig+1-1
...@@ -291,7 +291,7 @@ pub fn flush(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !void {...@@ -291,7 +291,7 @@ pub fn flush(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !void {
291 if (metadata.rodata_state != .unused) metadata.rodata_state = .flushed;291 if (metadata.rodata_state != .unused) metadata.rodata_state = .flushed;
292 }292 }
293293
294 if (build_options.enable_logging) {294 if (build_options.enable_debug_extensions) {
295 const active = elf_file.base.comp.zcu.?.activate(tid);295 const active = elf_file.base.comp.zcu.?.activate(tid);
296 defer active.deactivate();296 defer active.deactivate();
297 for (self.navs.keys(), self.navs.values()) |nav_index, meta| {297 for (self.navs.keys(), self.navs.values()) |nav_index, meta| {
src/link/Elf/gc.zig+1-1
...@@ -98,7 +98,7 @@ fn markAtom(atom: *Atom) bool {...@@ -98,7 +98,7 @@ fn markAtom(atom: *Atom) bool {
98}98}
9999
100fn markLive(atom: *Atom, elf_file: *Elf) void {100fn markLive(atom: *Atom, elf_file: *Elf) void {
101 if (@import("build_options").enable_logging) track_live_level.incr();101 if (@import("build_options").enable_debug_extensions) track_live_level.incr();
102102
103 assert(atom.visited);103 assert(atom.visited);
104 const file = atom.file(elf_file).?;104 const file = atom.file(elf_file).?;
src/link/Elf/relocatable.zig+4-10
...@@ -51,9 +51,7 @@ pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation) !void {...@@ -51,9 +51,7 @@ pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation) !void {
51 try allocateAllocSections(elf_file);51 try allocateAllocSections(elf_file);
52 try elf_file.allocateNonAllocSections();52 try elf_file.allocateNonAllocSections();
5353
54 if (build_options.enable_logging) {54 state_log.debug("{f}", .{elf_file.dumpState()});
55 state_log.debug("{f}", .{elf_file.dumpState()});
56 }
5755
58 try elf_file.writeMergeSections();56 try elf_file.writeMergeSections();
59 try writeSyntheticSections(elf_file);57 try writeSyntheticSections(elf_file);
...@@ -117,10 +115,8 @@ pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation) !void {...@@ -117,10 +115,8 @@ pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation) !void {
117 break :blk pos;115 break :blk pos;
118 };116 };
119117
120 if (build_options.enable_logging) {118 state_log.debug("ar_symtab\n{f}\n", .{ar_symtab.fmt(elf_file)});
121 state_log.debug("ar_symtab\n{f}\n", .{ar_symtab.fmt(elf_file)});119 state_log.debug("ar_strtab\n{f}\n", .{ar_strtab});
122 state_log.debug("ar_strtab\n{f}\n", .{ar_strtab});
123 }
124120
125 const buffer = try gpa.alloc(u8, total_size);121 const buffer = try gpa.alloc(u8, total_size);
126 defer gpa.free(buffer);122 defer gpa.free(buffer);
...@@ -193,9 +189,7 @@ pub fn flushObject(elf_file: *Elf, comp: *Compilation) !void {...@@ -193,9 +189,7 @@ pub fn flushObject(elf_file: *Elf, comp: *Compilation) !void {
193 try allocateAllocSections(elf_file);189 try allocateAllocSections(elf_file);
194 try elf_file.allocateNonAllocSections();190 try elf_file.allocateNonAllocSections();
195191
196 if (build_options.enable_logging) {192 state_log.debug("{f}", .{elf_file.dumpState()});
197 state_log.debug("{f}", .{elf_file.dumpState()});
198 }
199193
200 try writeAtoms(elf_file);194 try writeAtoms(elf_file);
201 try elf_file.writeMergeSections();195 try elf_file.writeMergeSections();
src/link/MachO.zig+1-3
...@@ -456,9 +456,7 @@ pub fn flush(...@@ -456,9 +456,7 @@ pub fn flush(
456 self.allocateSegments();456 self.allocateSegments();
457 self.allocateSyntheticSymbols();457 self.allocateSyntheticSymbols();
458458
459 if (build_options.enable_logging) {459 state_log.debug("{f}", .{self.dumpState()});
460 state_log.debug("{f}", .{self.dumpState()});
461 }
462460
463 // Beyond this point, everything has been allocated a virtual address and we can resolve461 // Beyond this point, everything has been allocated a virtual address and we can resolve
464 // the relocations, and commit objects to file.462 // the relocations, and commit objects to file.
src/link/MachO/dead_strip.zig+2-1
...@@ -123,8 +123,9 @@ fn markLive(atom: *Atom, macho_file: *MachO) void {...@@ -123,8 +123,9 @@ fn markLive(atom: *Atom, macho_file: *MachO) void {
123 atom.getName(macho_file),123 atom.getName(macho_file),
124 });124 });
125125
126 if (build_options.enable_logging)126 if (build_options.enable_debug_extensions) {
127 track_live_level.incr();127 track_live_level.incr();
128 }
128129
129 for (atom.getRelocs(macho_file)) |rel| {130 for (atom.getRelocs(macho_file)) |rel| {
130 const target_atom = switch (rel.tag) {131 const target_atom = switch (rel.tag) {
src/link/MachO/relocatable.zig+3-9
...@@ -61,9 +61,7 @@ pub fn flushObject(macho_file: *MachO, comp: *Compilation) link.Error!void {...@@ -61,9 +61,7 @@ pub fn flushObject(macho_file: *MachO, comp: *Compilation) link.Error!void {
61 };61 };
62 allocateSegment(macho_file);62 allocateSegment(macho_file);
6363
64 if (build_options.enable_logging) {64 state_log.debug("{f}", .{macho_file.dumpState()});
65 state_log.debug("{f}", .{macho_file.dumpState()});
66 }
6765
68 try writeSections(macho_file);66 try writeSections(macho_file);
69 sortRelocs(macho_file);67 sortRelocs(macho_file);
...@@ -107,9 +105,7 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation) link.Error!void {...@@ -107,9 +105,7 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation) link.Error!void {
107 return diags.fail("failed to allocate sections: {s}", .{@errorName(err)});105 return diags.fail("failed to allocate sections: {s}", .{@errorName(err)});
108 allocateSegment(macho_file);106 allocateSegment(macho_file);
109107
110 if (build_options.enable_logging) {108 state_log.debug("{f}", .{macho_file.dumpState()});
111 state_log.debug("{f}", .{macho_file.dumpState()});
112 }
113109
114 try writeSections(macho_file);110 try writeSections(macho_file);
115 sortRelocs(macho_file);111 sortRelocs(macho_file);
...@@ -185,9 +181,7 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation) link.Error!void {...@@ -185,9 +181,7 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation) link.Error!void {
185 break :blk pos;181 break :blk pos;
186 };182 };
187183
188 if (build_options.enable_logging) {184 state_log.debug("ar_symtab\n{f}\n", .{ar_symtab.fmt(macho_file)});
189 state_log.debug("ar_symtab\n{f}\n", .{ar_symtab.fmt(macho_file)});
190 }
191185
192 const buffer = try gpa.alloc(u8, total_size);186 const buffer = try gpa.alloc(u8, total_size);
193 defer gpa.free(buffer);187 defer gpa.free(buffer);
src/main.zig+40-74
...@@ -42,11 +42,8 @@ const thread_stack_size = 60 << 20;...@@ -42,11 +42,8 @@ const thread_stack_size = 60 << 20;
4242
43pub const std_options: std.Options = .{43pub const std_options: std.Options = .{
44 .logFn = log,44 .logFn = log,
4545 .log_level = switch (build_options.log_level) {
46 .log_level = switch (builtin.mode) {46 inline else => |log_level| @field(std.log.Level, @tagName(log_level)),
47 .debug => .debug,
48 .safe, .fast => .info,
49 .small => .err,
50 },47 },
51};48};
52pub const std_options_cwd = if (native_os == .wasi) wasi_cwd else null;49pub const std_options_cwd = if (native_os == .wasi) wasi_cwd else null;
...@@ -104,7 +101,7 @@ const normal_usage =...@@ -104,7 +101,7 @@ const normal_usage =
104 \\ help Print this help and exit101 \\ help Print this help and exit
105 \\ cache-cat Print a zig-cache manifest file as zon102 \\ cache-cat Print a zig-cache manifest file as zon
106 \\ std View standard library documentation in a browser103 \\ std View standard library documentation in a browser
107 \\ libc Display native libc paths file or validate one104 \\ libc Print native libc paths file or validate one
108 \\ targets List available compilation targets105 \\ targets List available compilation targets
109 \\ version Print version number and exit106 \\ version Print version number and exit
110 \\ zen Print Zen of Zig and exit107 \\ zen Print Zen of Zig and exit
...@@ -126,7 +123,15 @@ const debug_usage = normal_usage ++...@@ -126,7 +123,15 @@ const debug_usage = normal_usage ++
126123
127const usage = if (build_options.enable_debug_extensions) debug_usage else normal_usage;124const usage = if (build_options.enable_debug_extensions) debug_usage else normal_usage;
128125
129var log_scopes: std.ArrayList([]const u8) = .empty;126var log_scopes: std.array_hash_map.String(void) = .empty;
127
128pub fn debugLogScopeEnabled(scope: []const u8) bool {
129 switch (build_options.log_level) {
130 else => {},
131 .debug => if (log_scopes.contains(scope)) return true,
132 }
133 return false;
134}
130135
131pub fn log(136pub fn log(
132 comptime level: std.log.Level,137 comptime level: std.log.Level,
...@@ -135,18 +140,11 @@ pub fn log(...@@ -135,18 +140,11 @@ pub fn log(
135 args: anytype,140 args: anytype,
136) void {141) void {
137 // Hide debug messages unless:142 // Hide debug messages unless:
138 // * logging enabled with `-Dlog`.143 // * logging enabled with `-Ddebug-extensions` or `-Dlog=debug`.
139 // * the --debug-log arg for the scope has been provided144 // * the --debug-log arg for the scope has been provided
140 if (@backingInt(level) > @backingInt(std.options.log_level) or145 switch (level) {
141 @backingInt(level) > @backingInt(std.log.Level.info))146 else => {},
142 {147 .debug => if (!debugLogScopeEnabled(@tagName(scope))) return,
143 if (!build_options.enable_logging) return;
144
145 const scope_name = @tagName(scope);
146 for (log_scopes.items) |log_scope| {
147 if (mem.eql(u8, log_scope, scope_name))
148 break;
149 } else return;
150 }148 }
151149
152 // Otherwise, use the default implementation.150 // Otherwise, use the default implementation.
...@@ -557,11 +555,14 @@ const compile_usage =...@@ -557,11 +555,14 @@ const compile_usage =
557 \\ -fno-emit-docs (default) Do not produce docs/ dir with html documentation555 \\ -fno-emit-docs (default) Do not produce docs/ dir with html documentation
558 \\ -femit-implib[=path] (default) Produce an import .lib when building a Windows DLL556 \\ -femit-implib[=path] (default) Produce an import .lib when building a Windows DLL
559 \\ -fno-emit-implib Do not produce an import .lib when building a Windows DLL557 \\ -fno-emit-implib Do not produce an import .lib when building a Windows DLL
560 \\ --show-builtin Output the source of @import("builtin") then exit
561 \\ --cache-dir [path] Override the local cache directory558 \\ --cache-dir [path] Override the local cache directory
562 \\ --global-cache-dir [path] Override the global cache directory559 \\ --global-cache-dir [path] Override the global cache directory
563 \\ --zig-lib-dir [path] Override path to Zig installation lib directory560 \\ --zig-lib-dir [path] Override path to Zig installation lib directory
564 \\ --build-root [path] Override path to project source files561 \\ --build-root [path] Override path to project source files
562 \\ --show-builtin Output the source of @import("builtin") then exit
563 \\ --time-report Send timing diagnostics to '--listen' clients
564 \\ --verbose-cc Print C compiler commands before executing them
565 \\ --verbose-link Print linker commands before executing them
565 \\566 \\
566 \\Global Compile Options:567 \\Global Compile Options:
567 \\ --name [name] Compilation unit name (not a file path)568 \\ --name [name] Compilation unit name (not a file path)
...@@ -593,7 +594,6 @@ const compile_usage =...@@ -593,7 +594,6 @@ const compile_usage =
593 \\ -fpatchable-function-entry=[num] Add num NOPs of padding in function prologues594 \\ -fpatchable-function-entry=[num] Add num NOPs of padding in function prologues
594 \\ -mexec-model=[value] (WASI) Execution model595 \\ -mexec-model=[value] (WASI) Execution model
595 \\ -municode (Windows) Use wmain/wWinMain as entry point596 \\ -municode (Windows) Use wmain/wWinMain as entry point
596 \\ --time-report Send timing diagnostics to '--listen' clients
597 \\597 \\
598 \\Per-Module Compile Options:598 \\Per-Module Compile Options:
599 \\ --dep [[import=]name] Add an entry to the next module's import table599 \\ --dep [[import=]name] Add an entry to the next module's import table
...@@ -604,13 +604,15 @@ const compile_usage =...@@ -604,13 +604,15 @@ const compile_usage =
604 \\ safe Enable both safety checks and machine code optimizations604 \\ safe Enable both safety checks and machine code optimizations
605 \\ small Prioritize small binary size. Safety checks off.605 \\ small Prioritize small binary size. Safety checks off.
606 \\ -ofmt=[fmt] Override target object format606 \\ -ofmt=[fmt] Override target object format
607 \\ elf Executable and Linking Format
608 \\ c C source code607 \\ c C source code
609 \\ wasm WebAssembly
610 \\ coff Common Object File Format (Windows)608 \\ coff Common Object File Format (Windows)
609 \\ elf Executable and Linking Format
610 \\ llvmir LLVM text intermediate representation
611 \\ llvmbc LLVM binary intermediate representation
611 \\ macho macOS relocatables612 \\ macho macOS relocatables
612 \\ spirv Standard, Portable Intermediate Representation V (SPIR-V)
613 \\ plan9 Plan 9 from Bell Labs object format613 \\ plan9 Plan 9 from Bell Labs object format
614 \\ spirv Standard, Portable Intermediate Representation V (SPIR-V)
615 \\ wasm WebAssembly
614 \\ hex (planned feature) Intel IHEX616 \\ hex (planned feature) Intel IHEX
615 \\ raw (planned feature) Dump machine code directly617 \\ raw (planned feature) Dump machine code directly
616 \\ -mcpu [cpu] Specify target CPU and feature set618 \\ -mcpu [cpu] Specify target CPU and feature set
...@@ -791,15 +793,6 @@ const compile_usage =...@@ -791,15 +793,6 @@ const compile_usage =
791 \\Debug Options (Zig Compiler Development):793 \\Debug Options (Zig Compiler Development):
792 \\ -fopt-bisect-limit=[limit] Only run [limit] first LLVM optimization passes794 \\ -fopt-bisect-limit=[limit] Only run [limit] first LLVM optimization passes
793 \\ -fstack-report Print stack size diagnostics795 \\ -fstack-report Print stack size diagnostics
794 \\ --verbose-link Display linker invocations
795 \\ --verbose-cc Display C compiler invocations
796 \\ --verbose-air Enable compiler debug output for Zig AIR
797 \\ --verbose-intern-pool Enable compiler debug output for InternPool
798 \\ --verbose-generic-instances Enable compiler debug output for generic instance generation
799 \\ --verbose-llvm-ir[=path] Enable compiler debug output for unoptimized LLVM IR
800 \\ --verbose-llvm-bc=[path] Enable compiler debug output for unoptimized LLVM BC
801 \\ --verbose-cimport Enable compiler debug output for C imports
802 \\ --verbose-llvm-cpu-features Enable compiler debug output for LLVM CPU features
803 \\ --debug-log [scope] Enable printing debug/info log messages for scope796 \\ --debug-log [scope] Enable printing debug/info log messages for scope
804 \\ --debug-compile-errors Crash with helpful diagnostics at the first compile error797 \\ --debug-compile-errors Crash with helpful diagnostics at the first compile error
805 \\ --debug-link-snapshot Dump linker state and output file information for troubleshooting798 \\ --debug-link-snapshot Dump linker state and output file information for troubleshooting
...@@ -933,17 +926,11 @@ fn buildOutputType(...@@ -933,17 +926,11 @@ fn buildOutputType(
933 var listen: Listen = .none;926 var listen: Listen = .none;
934 var debug_compile_errors = false;927 var debug_compile_errors = false;
935 var debug_incremental = false;928 var debug_incremental = false;
936 var verbose_link = (native_os != .wasi or builtin.link_libc) and
937 EnvVar.ZIG_VERBOSE_LINK.isSet(environ_map);
938 var verbose_cc = (native_os != .wasi or builtin.link_libc) and929 var verbose_cc = (native_os != .wasi or builtin.link_libc) and
939 EnvVar.ZIG_VERBOSE_CC.isSet(environ_map);930 EnvVar.ZIG_VERBOSE_CC.isSet(environ_map);
940 var verbose_air = false;931 var verbose_link = (native_os != .wasi or builtin.link_libc) and
941 var verbose_intern_pool = false;932 EnvVar.ZIG_VERBOSE_LINK.isSet(environ_map);
942 var verbose_generic_instances = false;
943 var verbose_llvm_ir: ?[]const u8 = null;
944 var verbose_llvm_bc: ?[]const u8 = null;
945 var link_depfile: ?[]const u8 = null;933 var link_depfile: ?[]const u8 = null;
946 var verbose_llvm_cpu_features = false;
947 var time_report = false;934 var time_report = false;
948 var stack_report = false;935 var stack_report = false;
949 var show_builtin = false;936 var show_builtin = false;
...@@ -1809,24 +1796,10 @@ fn buildOutputType(...@@ -1809,24 +1796,10 @@ fn buildOutputType(
1809 } else {1796 } else {
1810 warn("Zig was compiled without debug extensions. --debug-compile-errors has no effect.", .{});1797 warn("Zig was compiled without debug extensions. --debug-compile-errors has no effect.", .{});
1811 }1798 }
1812 } else if (mem.eql(u8, arg, "--verbose-link")) {
1813 verbose_link = true;
1814 } else if (mem.eql(u8, arg, "--verbose-cc")) {1799 } else if (mem.eql(u8, arg, "--verbose-cc")) {
1815 verbose_cc = true;1800 verbose_cc = true;
1816 } else if (mem.eql(u8, arg, "--verbose-air")) {1801 } else if (mem.eql(u8, arg, "--verbose-link")) {
1817 verbose_air = true;1802 verbose_link = true;
1818 } else if (mem.eql(u8, arg, "--verbose-intern-pool")) {
1819 verbose_intern_pool = true;
1820 } else if (mem.eql(u8, arg, "--verbose-generic-instances")) {
1821 verbose_generic_instances = true;
1822 } else if (mem.eql(u8, arg, "--verbose-llvm-ir")) {
1823 verbose_llvm_ir = "-";
1824 } else if (mem.cutPrefix(u8, arg, "--verbose-llvm-ir=")) |rest| {
1825 verbose_llvm_ir = rest;
1826 } else if (mem.cutPrefix(u8, arg, "--verbose-llvm-bc=")) |rest| {
1827 verbose_llvm_bc = rest;
1828 } else if (mem.eql(u8, arg, "--verbose-llvm-cpu-features")) {
1829 verbose_llvm_cpu_features = true;
1830 } else if (mem.cutPrefix(u8, arg, "-T")) |rest| {1803 } else if (mem.cutPrefix(u8, arg, "-T")) |rest| {
1831 linker_script = rest;1804 linker_script = rest;
1832 } else if (mem.cutPrefix(u8, arg, "-L")) |rest| {1805 } else if (mem.cutPrefix(u8, arg, "-L")) |rest| {
...@@ -3729,13 +3702,7 @@ fn buildOutputType(...@@ -3729,13 +3702,7 @@ fn buildOutputType(
3729 .libc_installation = if (create_module.libc_installation) |*lci| lci else null,3702 .libc_installation = if (create_module.libc_installation) |*lci| lci else null,
3730 .verbose_cc = verbose_cc,3703 .verbose_cc = verbose_cc,
3731 .verbose_link = verbose_link,3704 .verbose_link = verbose_link,
3732 .verbose_air = verbose_air,
3733 .verbose_intern_pool = verbose_intern_pool,
3734 .verbose_generic_instances = verbose_generic_instances,
3735 .verbose_llvm_ir = verbose_llvm_ir,
3736 .verbose_llvm_bc = verbose_llvm_bc,
3737 .link_depfile = link_depfile,3705 .link_depfile = link_depfile,
3738 .verbose_llvm_cpu_features = verbose_llvm_cpu_features,
3739 .time_report = time_report,3706 .time_report = time_report,
3740 .stack_report = stack_report,3707 .stack_report = stack_report,
3741 .build_id = build_id,3708 .build_id = build_id,
...@@ -3956,10 +3923,10 @@ fn buildOutputType(...@@ -3956,10 +3923,10 @@ fn buildOutputType(
3956 });3923 });
3957 }3924 }
39583925
3959 try test_exec_args.ensureUnusedCapacity(arena, 2 * log_scopes.items.len + @intFromBool(verbose_link) + @intFromBool(verbose_cc));3926 try test_exec_args.ensureUnusedCapacity(arena, 2 * log_scopes.count() + @intFromBool(verbose_link) + @intFromBool(verbose_cc));
3960 for (log_scopes.items) |log_scope| test_exec_args.appendSliceAssumeCapacity(&.{ "--debug-log", log_scope });3927 for (log_scopes.keys()) |log_scope| test_exec_args.appendSliceAssumeCapacity(&.{ "--debug-log", log_scope });
3961 if (verbose_link) test_exec_args.appendAssumeCapacity("--verbose-link");
3962 if (verbose_cc) test_exec_args.appendAssumeCapacity("--verbose-cc");3928 if (verbose_cc) test_exec_args.appendAssumeCapacity("--verbose-cc");
3929 if (verbose_link) test_exec_args.appendAssumeCapacity("--verbose-link");
3963 }3930 }
39643931
3965 try runOrTest(3932 try runOrTest(
...@@ -5627,17 +5594,17 @@ fn cmdAstCheck(arena: Allocator, io: Io, args: []const []const u8, environ_map:...@@ -5627,17 +5594,17 @@ fn cmdAstCheck(arena: Allocator, io: Io, args: []const []const u8, environ_map:
5627 }5594 }
5628 }5595 }
56295596
5630 const display_path = zig_source_path orelse "<stdin>";5597 const print_path = zig_source_path orelse "<stdin>";
5631 const source: [:0]const u8 = s: {5598 const source: [:0]const u8 = s: {
5632 var f = if (zig_source_path) |p| file: {5599 var f = if (zig_source_path) |p| file: {
5633 break :file Io.Dir.cwd().openFile(io, p, .{}) catch |err| {5600 break :file Io.Dir.cwd().openFile(io, p, .{}) catch |err| {
5634 fatal("unable to open file {q} for ast-check: {t}", .{ display_path, err });5601 fatal("unable to open file {q} for ast-check: {t}", .{ print_path, err });
5635 };5602 };
5636 } else Io.File.stdin();5603 } else Io.File.stdin();
5637 defer if (zig_source_path != null) f.close(io);5604 defer if (zig_source_path != null) f.close(io);
5638 var file_reader: Io.File.Reader = f.reader(io, &stdin_buffer);5605 var file_reader: Io.File.Reader = f.reader(io, &stdin_buffer);
5639 break :s std.zig.readSourceFileToEndAlloc(arena, &file_reader) catch |err| {5606 break :s std.zig.readSourceFileToEndAlloc(arena, &file_reader) catch |err| {
5640 fatal("unable to load file {q} for ast-check: {t}", .{ display_path, err });5607 fatal("unable to load file {q} for ast-check: {t}", .{ print_path, err });
5641 };5608 };
5642 };5609 };
56435610
...@@ -5661,7 +5628,7 @@ fn cmdAstCheck(arena: Allocator, io: Io, args: []const []const u8, environ_map:...@@ -5661,7 +5628,7 @@ fn cmdAstCheck(arena: Allocator, io: Io, args: []const []const u8, environ_map:
56615628
5662 if (zir.hasCompileErrors()) {5629 if (zir.hasCompileErrors()) {
5663 var wip_errors: std.zig.ErrorBundle.Wip = try .init(arena);5630 var wip_errors: std.zig.ErrorBundle.Wip = try .init(arena);
5664 try wip_errors.addZirErrorMessages(zir, tree, source, display_path);5631 try wip_errors.addZirErrorMessages(zir, tree, source, print_path);
5665 var error_bundle = try wip_errors.toOwnedBundle("");5632 var error_bundle = try wip_errors.toOwnedBundle("");
5666 try error_bundle.renderToStderr(io, .{}, color);5633 try error_bundle.renderToStderr(io, .{}, color);
5667 if (zir.loweringFailed()) {5634 if (zir.loweringFailed()) {
...@@ -5731,7 +5698,7 @@ fn cmdAstCheck(arena: Allocator, io: Io, args: []const []const u8, environ_map:...@@ -5731,7 +5698,7 @@ fn cmdAstCheck(arena: Allocator, io: Io, args: []const []const u8, environ_map:
5731 const zoir = try ZonGen.generate(arena, tree, .{});5698 const zoir = try ZonGen.generate(arena, tree, .{});
5732 if (zoir.hasCompileErrors()) {5699 if (zoir.hasCompileErrors()) {
5733 var wip_errors: std.zig.ErrorBundle.Wip = try .init(arena);5700 var wip_errors: std.zig.ErrorBundle.Wip = try .init(arena);
5734 try wip_errors.addZoirErrorMessages(zoir, tree, source, display_path);5701 try wip_errors.addZoirErrorMessages(zoir, tree, source, print_path);
5735 var error_bundle = try wip_errors.toOwnedBundle("");5702 var error_bundle = try wip_errors.toOwnedBundle("");
5736 error_bundle.renderToStderr(io, .{}, color) catch {};5703 error_bundle.renderToStderr(io, .{}, color) catch {};
5737 process.exit(1);5704 process.exit(1);
...@@ -6254,9 +6221,8 @@ fn randInt(io: Io, comptime T: type) T {...@@ -6254,9 +6221,8 @@ fn randInt(io: Io, comptime T: type) T {
6254}6221}
62556222
6256fn addDebugLog(arena: Allocator, scope_name: []const u8) error{OutOfMemory}!void {6223fn addDebugLog(arena: Allocator, scope_name: []const u8) error{OutOfMemory}!void {
6257 if (!build_options.enable_logging) {6224 switch (build_options.log_level) {
6258 warn("Zig was compiled without logging enabled (-Dlog). --debug-log has no effect.", .{});6225 else => warn("Zig was compiled without logging enabled (-Dlog). --debug-log has no effect.", .{}),
6259 } else {6226 .debug => try log_scopes.put(arena, try arena.dupe(u8, scope_name), {}),
6260 try log_scopes.append(arena, scope_name);
6261 }6227 }
6262}6228}
src/target.zig+2
...@@ -193,6 +193,8 @@ pub fn hasLlvmSupport(target: *const std.Target, ofmt: std.Target.ObjectFormat)...@@ -193,6 +193,8 @@ pub fn hasLlvmSupport(target: *const std.Target, ofmt: std.Target.ObjectFormat)
193 .coff,193 .coff,
194 .elf,194 .elf,
195 .hex,195 .hex,
196 .llvmbc,
197 .llvmir,
196 .macho,198 .macho,
197 .spirv,199 .spirv,
198 .raw,200 .raw,
src/zig_llvm.cpp+5-3
...@@ -410,6 +410,10 @@ ZIG_EXTERN_C bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machi...@@ -410,6 +410,10 @@ ZIG_EXTERN_C bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machi
410 // Code generation phase410 // Code generation phase
411 codegen_pm.run(llvm_module);411 codegen_pm.run(llvm_module);
412412
413 if (options->llvm_ir_out != nullptr) {
414 *options->llvm_ir_out = LLVMPrintModuleToString(module_ref);
415 }
416
413 if (options->llvm_ir_filename) {417 if (options->llvm_ir_filename) {
414 if (LLVMPrintModuleToFile(module_ref, options->llvm_ir_filename, error_message)) {418 if (LLVMPrintModuleToFile(module_ref, options->llvm_ir_filename, error_message)) {
415 return true;419 return true;
...@@ -430,9 +434,7 @@ ZIG_EXTERN_C bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machi...@@ -430,9 +434,7 @@ ZIG_EXTERN_C bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machi
430 auto os = raw_string_ostream(out_str);434 auto os = raw_string_ostream(out_str);
431 TimerGroup::printAll(os);435 TimerGroup::printAll(os);
432 TimerGroup::clearAll();436 TimerGroup::clearAll();
433 auto c_str = (char *)malloc(out_str.length() + 1);437 *options->time_report_out = LLVMCreateMessage(out_str.c_str());
434 strcpy(c_str, out_str.c_str());
435 *options->time_report_out = c_str;
436 }438 }
437 return false;439 return false;
438}440}
src/zig_llvm.h+6-2
...@@ -67,8 +67,8 @@ struct ZigLLVMEmitOptions {...@@ -67,8 +67,8 @@ struct ZigLLVMEmitOptions {
67 bool is_debug;67 bool is_debug;
68 bool is_small;68 bool is_small;
69 // If not null, and `ZigLLVMTargetMachineEmitToFile` returns `false` indicating success, this69 // If not null, and `ZigLLVMTargetMachineEmitToFile` returns `false` indicating success, this
70 // `char *` will be populated with a `malloc`-allocated string containing the serialized (as70 // `char *` will be populated with the serialized (as JSON) time report data. The caller is
71 // JSON) time report data. The caller is responsible for freeing that memory.71 // responsible for freeing that memory with `disposeMessage`.
72 char **time_report_out;72 char **time_report_out;
73 bool tsan;73 bool tsan;
74 bool sancov;74 bool sancov;
...@@ -79,6 +79,10 @@ struct ZigLLVMEmitOptions {...@@ -79,6 +79,10 @@ struct ZigLLVMEmitOptions {
79 const char *bin_filename;79 const char *bin_filename;
80 const char *llvm_ir_filename;80 const char *llvm_ir_filename;
81 const char *bitcode_filename;81 const char *bitcode_filename;
82 // If not null and `ZigLLVMTargetMachineEmitToFile` returns `false` indicating success, this
83 // `char *` will be populated with the optimized LLVM IR. The caller is responsible for freeing
84 // this memory with `disposeMessage`.
85 char **llvm_ir_out;
82 ZigLLVMCoverageOptions coverage;86 ZigLLVMCoverageOptions coverage;
83};87};
8488
stage1/config.zig.in+1-1
...@@ -6,7 +6,7 @@ pub const llvm_has_xtensa = false;...@@ -6,7 +6,7 @@ pub const llvm_has_xtensa = false;
6pub const version: [:0]const u8 = "@RESOLVED_ZIG_VERSION@";6pub const version: [:0]const u8 = "@RESOLVED_ZIG_VERSION@";
7pub const semver = @import("std").SemanticVersion.parse(version) catch unreachable;7pub const semver = @import("std").SemanticVersion.parse(version) catch unreachable;
8pub const enable_debug_extensions = false;8pub const enable_debug_extensions = false;
9pub const enable_logging = false;9pub const log_level: @import("std").log.Level = .err;
10pub const enable_link_snapshots = false;10pub const enable_link_snapshots = false;
11pub const enable_tracy = false;11pub const enable_tracy = false;
12pub const value_tracing = false;12pub const value_tracing = false;