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
330330 src/Air/Legalize.zig
331331 src/Air/Liveness.zig
332332 src/Air/Liveness/Verify.zig
333 src/Air/print.zig
333 src/Air/Print.zig
334334 src/Builtin.zig
335335 src/Compilation.zig
336336 src/Compilation/Config.zig
bootstrap.c+1-1
......@@ -179,7 +179,7 @@ int main(int argc, char **argv) {
179179 "pub const version: [:0]const u8 = \"%s\";\n"
180180 "pub const semver = @import(\"std\").SemanticVersion.parse(version) catch unreachable;\n"
181181 "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"
183183 "pub const enable_link_snapshots = false;\n"
184184 "pub const enable_tracy = false;\n"
185185 "pub const value_tracing = false;\n"
build.zig+17-7
......@@ -25,6 +25,10 @@ pub fn build(b: *std.Build) !void {
2525 },
2626 });
2727 const optimize = b.standardOptimizeOption(.{});
28 const is_debug = switch (optimize) {
29 .debug => true,
30 .safe, .fast, .small => false,
31 };
2832
2933 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;
3034 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 {
205209 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
207211 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);
209 if (optimize != .debug) break :blk 0;
210 break :blk 4;
212 if (strip == true) break :blk 0;
213 if (is_debug) break :blk 4;
214 break :blk 0;
211215 };
212216
213217 const exe = addCompilerStep(b, .{
......@@ -255,9 +259,15 @@ pub fn build(b: *std.Build) !void {
255259 exe.root_module.link_libc = true;
256260 }
257261
258 const is_debug = optimize == .debug;
259262 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
262272 const opt_version_string = b.option([]const u8, "version-string", "Override Zig version string. Default is to find out with git.");
263273 const version_slice = if (opt_version_string) |version| version else v: {
......@@ -398,7 +408,7 @@ pub fn build(b: *std.Build) !void {
398408 exe_options.addOption(std.SemanticVersion, "semver", semver);
399409
400410 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);
402412 exe_options.addOption(bool, "enable_tracy", tracy != null);
403413 exe_options.addOption(bool, "enable_tracy_callstack", tracy_callstack);
404414 exe_options.addOption(bool, "enable_tracy_allocation", tracy_allocation);
......@@ -837,7 +847,7 @@ fn addWasiUpdateStep(b: *std.Build, version: [:0]const u8) !void {
837847 exe_options.addOption([:0]const u8, "version", version);
838848 exe_options.addOption(std.SemanticVersion, "semver", semver);
839849 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);
841851 exe_options.addOption(bool, "enable_tracy", false);
842852 exe_options.addOption(bool, "enable_tracy_callstack", false);
843853 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 {
509509 } else if (mem.eql(u8, arg, "--libc-runtimes") or mem.eql(u8, arg, "--glibc-runtimes")) {
510510 // --glibc-runtimes was the old name of the flag; kept for compatibility for now.
511511 graph.libc_runtimes_dir = nextArgOrFatal(args, &arg_i);
512 } else if (mem.eql(u8, arg, "--verbose-air")) {
513 graph.verbose_air = true;
514512 } else if (mem.eql(u8, arg, "--verbose-cc")) {
515513 graph.verbose_cc = true;
516514 } else if (mem.eql(u8, arg, "--verbose-link")) {
517515 graph.verbose_link = true;
518 } else if (mem.eql(u8, arg, "--verbose-llvm-ir")) {
519 graph.verbose_llvm_ir = true;
520516 } else if (mem.eql(u8, arg, "--watch")) {
521517 watch_flag = true;
522518 } else if (mem.eql(u8, arg, "--time-report")) {
lib/compiler/Maker/Graph.zig-3
......@@ -32,11 +32,8 @@ debug_compile_errors: bool = false,
3232debug_incremental: bool = false,
3333fuzzing: bool = false,
3434verbose: bool = false,
35verbose_air: bool = false,
3635verbose_cc: bool = false,
3736verbose_link: bool = false,
38verbose_llvm_cpu_features: bool = false,
39verbose_llvm_ir: bool = false,
4037libc_file: ?[]const u8 = null,
4138/// What does this do? Nobody bothered to document it, and I think it's a
4239/// smelly option. So unless somebody deletes these passive aggressive comments
lib/compiler/Maker/ScannedConfig.zig+2-6
......@@ -351,6 +351,8 @@ const general_usage =
351351 \\ preferred optimization mode: fast, safe, small
352352 \\
353353 \\ --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
354356 \\ --color [auto|off|on] Enable or disable colored error messages
355357 \\ --error-style [style] Control how build errors are printed
356358 \\ verbose (Default) Report errors with full context
......@@ -417,11 +419,5 @@ const general_usage =
417419 \\ none (default) No build ID
418420 \\ --debug-log [scope] Enable debugging the compiler
419421 \\ --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
426422 \\
427423;
lib/compiler/Maker/Step/Compile.zig+1-4
......@@ -608,11 +608,8 @@ fn lowerZigArgs(
608608
609609 try addBool(gpa, zig_args, "--debug-compile-errors", graph.debug_compile_errors);
610610 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);
614611 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);
616613 try addBool(gpa, zig_args, "--time-report", graph.time_report);
617614
618615 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(
927927 break :debug switch (d.comp.target.ofmt) {
928928 .elf, .macho, .wasm => .{ .dwarf = .@"32" },
929929 .coff => .code_view,
930 .c => switch (d.comp.target.os.tag) {
930 .c, .llvmbc, .llvmir => switch (d.comp.target.os.tag) {
931931 .windows, .uefi => .code_view,
932932 else => .{ .dwarf = .@"32" },
933933 },
lib/std/Build/Configuration.zig+2
......@@ -2519,6 +2519,8 @@ pub const TargetQuery = struct {
25192519 coff,
25202520 elf,
25212521 hex,
2522 llvmbc,
2523 llvmir,
25222524 macho,
25232525 plan9,
25242526 raw,
lib/std/Target.zig+6
......@@ -1043,6 +1043,10 @@ pub const ObjectFormat = enum {
10431043 elf,
10441044 /// The Intel HEX format for storing binary code in ASCII text.
10451045 hex,
1046 /// LLVM binary intermediate representation.
1047 llvmbc,
1048 /// LLVM text intermediate representation.
1049 llvmir,
10461050 /// The Mach object format used by macOS and other Apple platforms.
10471051 macho,
10481052 /// The a.out format used by Plan 9 from Bell Labs.
......@@ -1060,6 +1064,8 @@ pub const ObjectFormat = enum {
10601064 .coff => ".obj",
10611065 .elf, .macho, .wasm => ".o",
10621066 .hex => ".ihex",
1067 .llvmbc => ".bc",
1068 .llvmir => ".ll",
10631069 .plan9 => arch.plan9Ext(),
10641070 .raw => ".bin",
10651071 .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 {
7676 },
7777 .macho => @import("debug/SelfInfo/MachO.zig"),
7878 .plan9, .spirv, .wasm, .raw, .hex => void,
79 .c => unreachable,
79 .c, .llvmbc, .llvmir => unreachable,
8080 };
8181}
8282
lib/std/fmt.zig+7-1
......@@ -285,7 +285,13 @@ pub fn Alt(
285285pub fn alt(
286286 context: anytype,
287287 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))) {
289295 return .{ .data = context };
290296}
291297
lib/std/zig.zig+2
......@@ -218,6 +218,8 @@ pub fn binNameAlloc(allocator: Allocator, options: BinNameOptions) error{OutOfMe
218218 },
219219 .Obj => return std.fmt.allocPrint(allocator, "{s}.o", .{root_name}),
220220 },
221 .llvmbc => return std.fmt.allocPrint(allocator, "{s}.bc", .{root_name}),
222 .llvmir => return std.fmt.allocPrint(allocator, "{s}.ll", .{root_name}),
221223 .macho => switch (options.output_mode) {
222224 .Exe => return allocator.dupe(u8, root_name),
223225 .Lib => {
lib/std/zig/llvm/Builder.zig+16-5
......@@ -10855,11 +10855,22 @@ pub fn resolveAlignmentForwardReference(b: *Builder, fwd_ref: Alignment.Lazy, va
1085510855 b.alignment_forward_references.items[index] = value;
1085610856}
1085710857
10858pub fn dump(b: *Builder, io: Io) void {
10859 var buffer: [4000]u8 = undefined;
10860 const stderr: Io.File = .stderr();
10861 b.printToFile(io, stderr, &buffer) catch {};
10862}
10858pub const Print = struct {
10859 name: []const u8,
10860 builder: *Builder,
10861 err: ?Allocator.Error,
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
1086410875pub fn printToFilePath(b: *Builder, io: Io, dir: Io.Dir, path: []const u8) !void {
1086510876 var buffer: [4000]u8 = undefined;
src/Air.zig+5-5
......@@ -13,10 +13,10 @@ const InternPool = @import("InternPool.zig");
1313const Type = @import("Type.zig");
1414const Value = @import("Value.zig");
1515const Zcu = @import("Zcu.zig");
16const print = @import("Air/print.zig");
1716
1817pub const Legalize = @import("Air/Legalize.zig");
1918pub const Liveness = @import("Air/Liveness.zig");
19pub const Print = @import("Air/Print.zig");
2020pub const Verify = @import("Air/Verify.zig");
2121
2222instructions: std.MultiArrayList(Inst).Slice,
......@@ -2517,10 +2517,10 @@ pub fn unwrapShuffleTwo(air: *const Air, zcu: *const Zcu, inst_index: Inst.Index
25172517}
25182518
25192519pub const legalize = Legalize.legalize;
2520pub const write = print.write;
2521pub const writeInst = print.writeInst;
2522pub const dump = print.dump;
2523pub const dumpInst = print.dumpInst;
2520pub const write = Print.write;
2521pub const writeInst = Print.writeInst;
2522pub const dump = Print.dump;
2523pub const dumpInst = Print.dumpInst;
25242524
25252525pub const CoveragePoint = enum(u1) {
25262526 /// 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");
2020const tracy = @import("tracy.zig");
2121const trace = tracy.trace;
2222const build_options = @import("build_options");
23const debugLogScopeEnabled = @import("main.zig").debugLogScopeEnabled;
2324const LibCInstallation = std.zig.LibCInstallation;
2425const glibc = @import("libs/glibc.zig");
2526const musl = @import("libs/musl.zig");
......@@ -161,12 +162,6 @@ clang_passthrough_mode: bool,
161162clang_preprocessor_mode: ClangPreprocessorMode,
162163/// Whether to print clang argvs to stdout.
163164verbose_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,
170165verbose_link: bool,
171166link_depfile: ?[]const u8,
172167disable_c_depfile: bool,
......@@ -1544,13 +1539,7 @@ pub const CreateOptions = struct {
15441539 clang_passthrough_mode: bool = false,
15451540 verbose_cc: bool = false,
15461541 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,
15521542 link_depfile: ?[]const u8 = null,
1553 verbose_llvm_cpu_features: bool = false,
15541543 debug_compiler_runtime_libs: ?std.lang.Optimize = null,
15551544 debug_compile_errors: bool = false,
15561545 debug_incremental: bool = false,
......@@ -1932,21 +1921,6 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,
19321921 try options.root_mod.deps.putNoClobber(arena, "zigc", zigc_mod);
19331922 }
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
19501924 const error_limit = options.error_limit orelse (std.math.maxInt(u16) - 1);
19511925 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,
21112085 .clang_passthrough_mode = options.clang_passthrough_mode,
21122086 .clang_preprocessor_mode = options.clang_preprocessor_mode,
21132087 .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,
21212088 .verbose_link = options.verbose_link,
2089 .link_depfile = options.link_depfile,
21222090 .disable_c_depfile = options.disable_c_depfile,
21232091 .reference_trace = options.reference_trace,
21242092 .time_report = if (options.time_report) .init else null,
......@@ -2353,8 +2321,9 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,
23532321 comp.emit_asm != null or
23542322 comp.emit_llvm_ir != null or
23552323 comp.emit_llvm_bc != null or
2356 comp.verbose_llvm_ir != null or
2357 comp.verbose_llvm_bc != null))
2324 log_llvm_ir: {
2325 break :log_llvm_ir debugLogScopeEnabled("llvm-ir") or debugLogScopeEnabled("opt-llvm-ir");
2326 }))
23582327 {
23592328 if (opt_zcu) |zcu| {
23602329 dev.check(.llvm_backend);
......@@ -2566,19 +2535,6 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,
25662535 return comp;
25672536}
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
25822538pub fn destroy(comp: *Compilation) void {
25832539 const gpa = comp.gpa;
25842540 const io = comp.io;
......@@ -2991,14 +2947,19 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE
29912947 try pt.processExports();
29922948 }
29932949
2994 if (build_options.enable_debug_extensions and comp.verbose_intern_pool) {
2995 std.debug.print("intern pool stats for {q}:\n", .{comp.root_name});
2996 zcu.intern_pool.dump();
2997 }
2998
2999 if (build_options.enable_debug_extensions and comp.verbose_generic_instances) {
3000 std.debug.print("generic instances for '{s}:0x{x}':\n", .{ comp.root_name, @intFromPtr(zcu) });
3001 zcu.intern_pool.dumpGenericInstances(gpa);
2950 {
2951 var d: InternPool.Dump = .{
2952 .name = comp.root_name,
2953 .arena = arena,
2954 .ip = &zcu.intern_pool,
2955 .err = null,
2956 };
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;
30022963 }
30032964 }
30042965
......@@ -3220,28 +3181,29 @@ fn flush(comp: *Compilation, arena: Allocator) (Io.Cancelable || Allocator.Error
32203181 comp.time_report.?.stats.real_ns_llvm_emit = ns;
32213182 };
32223183
3223 const zcu_obj_path: ?Cache.Path = if (comp.bin_file != null) p: {
3224 break :p try comp.resolveEmitPathFlush(arena, .temp, llvm_object.out_bin_basename);
3225 } else null;
3184 const zcu_obj_path: ?Cache.Path = switch (comp.getTarget().ofmt) {
3185 .llvmbc, .llvmir => 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
32273192 const active = zcu.activate(tid);
32283193 defer active.deactivate();
32293194 llvm_object.emit(active.pt, .{
3230 .pre_ir_path = comp.verbose_llvm_ir,
3231 .pre_bc_path = comp.verbose_llvm_bc,
3232
32333195 .bin_path = if (zcu_obj_path) |p| try p.toStringZ(arena) else null,
32343196 .asm_path = p: {
32353197 const raw = comp.emit_asm orelse break :p null;
32363198 const p = try comp.resolveEmitPathFlush(arena, .artifact, raw);
32373199 break :p try p.toStringZ(arena);
32383200 },
3239 .post_ir_path = p: {
3201 .opt_ir_path = p: {
32403202 const raw = comp.emit_llvm_ir orelse break :p null;
32413203 const p = try comp.resolveEmitPathFlush(arena, .artifact, raw);
32423204 break :p try p.toStringZ(arena);
32433205 },
3244 .post_bc_path = p: {
3206 .opt_bc_path = p: {
32453207 const raw = comp.emit_llvm_bc orelse break :p null;
32463208 const p = try comp.resolveEmitPathFlush(arena, .artifact, raw);
32473209 break :p try p.toStringZ(arena);
......@@ -3267,7 +3229,7 @@ fn flush(comp: *Compilation, arena: Allocator) (Io.Cancelable || Allocator.Error
32673229 error.Canceled, error.OutOfMemory => |e| return e,
32683230 error.AlreadyReported => return,
32693231 };
3270 }
3232 } else return;
32713233 }
32723234 }
32733235 if (comp.bin_file) |lf| {
......@@ -4903,12 +4865,6 @@ fn workerDocsWasmFallible(comp: *Compilation, prog_node: std.Progress.Node) SubU
49034865 .emit_bin = .yes_cache,
49044866 .verbose_cc = comp.verbose_cc,
49054867 .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,
49124868 .environ_map = comp.environ_map,
49134869 }) catch |err| switch (err) {
49144870 error.CreateFail => {
......@@ -7415,12 +7371,6 @@ fn buildOutputFromZig(
74157371 .data_sections = true,
74167372 .verbose_cc = comp.verbose_cc,
74177373 .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,
74247374 .clang_passthrough_mode = comp.clang_passthrough_mode,
74257375 .skip_linker_dependencies = true,
74267376 .environ_map = comp.environ_map,
......@@ -7552,12 +7502,6 @@ pub fn build_crt_file(
75527502 .c_source_files = c_source_files,
75537503 .verbose_cc = comp.verbose_cc,
75547504 .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,
75617505 .clang_passthrough_mode = comp.clang_passthrough_mode,
75627506 .skip_linker_dependencies = true,
75637507 .environ_map = comp.environ_map,
src/Compilation/Config.zig+4-4
......@@ -190,7 +190,7 @@ pub fn resolve(options: Options) ResolveError!Config {
190190 // *If* the LLVM backend were to be selected, should Zig use the LLVM
191191 // library to build the LLVM module?
192192 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) {
194194 if (options.use_lib_llvm == true) return error.LlvmLibraryUnavailable;
195195 break :b false;
196196 }
......@@ -324,7 +324,7 @@ pub fn resolve(options: Options) ResolveError!Config {
324324 if (!options.have_zcu) break :b false;
325325
326326 // 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) {
328328 if (options.use_llvm == false)
329329 return error.EmittingLlvmModuleRequiresLlvmBackend;
330330 if (!target_util.hasLlvmSupport(target, target.ofmt))
......@@ -379,7 +379,7 @@ pub fn resolve(options: Options) ResolveError!Config {
379379 const backend = target_util.zigBackend(target, use_llvm);
380380
381381 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) {
383383 // Explicit request to use LLVM to produce an object file, but without
384384 // using LLVM libraries. Impossible.
385385 return error.EmittingBinaryRequiresLlvmLibrary;
......@@ -513,7 +513,7 @@ pub fn resolve(options: Options) ResolveError!Config {
513513 break :b switch (target.ofmt) {
514514 .elf, .macho, .wasm => .{ .dwarf = .@"32" },
515515 .coff => .code_view,
516 .c => switch (target.os.tag) {
516 .c, .llvmbc, .llvmir => switch (target.os.tag) {
517517 .windows, .uefi => .code_view,
518518 else => .{ .dwarf = .@"32" },
519519 },
src/InternPool.zig+33-25
......@@ -10591,17 +10591,36 @@ pub fn errorUnionPayload(ip: *const InternPool, ty: Index) Index {
1059110591 return ip.indexToKey(ty).error_union_type.payload_type;
1059210592}
1059310593
10594pub fn dump(ip: *const InternPool) void {
10595 var buffer: [4096]u8 = undefined;
10596 const stderr = std.debug.lockStderr(&buffer);
10597 defer std.debug.unlockStderr();
10598 const w = &stderr.file_writer.interface;
10599 dumpDependencyStatsFallible(ip, w) catch return;
10600 dumpStatsFallible(ip, w, std.heap.page_allocator) catch return;
10601 dumpAllFallible(ip, w) catch return;
10602}
10594pub const Dump = struct {
10595 name: []const u8,
10596 arena: std.mem.Allocator,
10597 ip: *const InternPool,
10598 err: ?Allocator.Error,
10599
10600 pub fn format(d: *Dump, w: *Io.Writer) Io.Writer.Error!void {
10601 try w.print("{q}:\n", .{d.name});
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 {
1060510624 const dep_entries_len = ip.dep_entries.items.len - ip.free_dep_entries.items.len;
1060610625 const src_hash_deps_len = ip.src_hash_deps.count();
1060710626 const nav_val_deps_len = ip.nav_val_deps.count();
......@@ -10668,7 +10687,7 @@ fn dumpDependencyStatsFallible(ip: *const InternPool, w: *Io.Writer) !void {
1066810687 });
1066910688}
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 {
1067210691 var items_len: usize = 0;
1067310692 var extra_len: usize = 0;
1067410693 var limbs_len: usize = 0;
......@@ -10968,7 +10987,7 @@ fn dumpStatsFallible(ip: *const InternPool, w: *Io.Writer, arena: Allocator) !vo
1096810987 }
1096910988}
1097010989
10971fn dumpAllFallible(ip: *const InternPool, w: *Io.Writer) anyerror!void {
10990fn dumpAllFallible(ip: *const InternPool, w: *Io.Writer) Io.Writer.Error!void {
1097210991 for (ip.locals, 0..) |*local, tid| {
1097310992 // Early check for length 0, because `view()` is invalid if capacity is 0
1097410993 if (local.mutate.items.len == 0) continue;
......@@ -11071,21 +11090,10 @@ fn dumpAllFallible(ip: *const InternPool, w: *Io.Writer) anyerror!void {
1107111090 }
1107211091}
1107311092
11074pub fn dumpGenericInstances(ip: *const InternPool, allocator: Allocator) 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
11093pub fn dumpGenericInstancesFallible(ip: *const InternPool, arena: Allocator, w: *Io.Writer) !void {
1108711094 var instances: std.array_hash_map.Auto(Index, std.ArrayList(Index)) = .empty;
1108811095 for (ip.locals, 0..) |*local, tid| {
11096 if (local.mutate.items.len == 0) continue;
1108911097 const items = local.shared.items.view().slice();
1109011098 const extra_list = local.shared.extra;
1109111099 for (
src/Module.zig+8-11
......@@ -26,6 +26,7 @@ fully_qualified_name: []const u8,
2626deps: Deps = .{},
2727
2828resolved_target: ResolvedTarget,
29llvm_cpu_features: ?[:0]const u8,
2930optimize_mode: std.lang.Optimize,
3031code_model: std.lang.CodeModel,
3132single_threaded: bool,
......@@ -94,7 +95,6 @@ pub const ResolvedTarget = struct {
9495 is_native_os: bool,
9596 is_native_abi: bool,
9697 is_explicit_dynamic_linker: bool,
97 llvm_cpu_features: ?[*:0]const u8 = null,
9898};
9999
100100pub const CreateError = error{
......@@ -362,15 +362,13 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Module {
362362 break :b 0;
363363 };
364364
365 const llvm_cpu_features: ?[*:0]const u8 = b: {
366 if (resolved_target.llvm_cpu_features) |x| break :b x;
365 const llvm_cpu_features: ?[:0]const u8 = b: {
367366 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.
369370 var buf = std.array_list.Managed(u8).init(arena);
370371 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.
374372 for (target.cpu.arch.allFeaturesList()) |feature| {
375373 if (feature.llvm_name) |llvm_name| {
376374 // 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 {
401399
402400 try buf.appendSlice(disabled_features.items);
403401 if (buf.items.len == 0) break :b "";
404 assert(std.mem.endsWith(u8, buf.items, ","));
402 assert(buf.items[buf.items.len - 1] == ',');
405403 buf.items[buf.items.len - 1] = 0;
406 buf.shrinkAndFree(buf.items.len);
407 break :b buf.items[0 .. buf.items.len - 1 :0].ptr;
404 break :b buf.items[0 .. buf.items.len - 1 :0];
408405 };
409406
410407 const mod = try arena.create(Module);
......@@ -417,8 +414,8 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Module {
417414 .is_native_os = resolved_target.is_native_os,
418415 .is_native_abi = resolved_target.is_native_abi,
419416 .is_explicit_dynamic_linker = resolved_target.is_explicit_dynamic_linker,
420 .llvm_cpu_features = llvm_cpu_features,
421417 },
418 .llvm_cpu_features = llvm_cpu_features,
422419 .optimize_mode = optimize_mode,
423420 .single_threaded = single_threaded,
424421 .error_tracing = error_tracing,
......@@ -494,8 +491,8 @@ pub fn createBuiltin(arena: Allocator, opts: Builtin, dirs: std.zig.Directories)
494491 .is_native_os = false,
495492 .is_native_abi = false,
496493 .is_explicit_dynamic_linker = false,
497 .llvm_cpu_features = null,
498494 },
495 .llvm_cpu_features = null,
499496 .optimize_mode = opts.optimize_mode,
500497 .single_threaded = opts.single_threaded,
501498 .error_tracing = opts.error_tracing,
src/Sema.zig+3-5
......@@ -1126,6 +1126,8 @@ fn analyzeBodyInner(
11261126 crash_info.push(sema, block, body);
11271127 defer crash_info.pop();
11281128
1129 const path = zcu.namespacePtr(block.namespace).fileScope(zcu).path;
1130
11291131 // We use a while (true) loop here to avoid a redundant way of breaking out of
11301132 // the loop. The only way to break out of the loop is with a `noreturn`
11311133 // instruction.
......@@ -1134,11 +1136,7 @@ fn analyzeBodyInner(
11341136 crash_info.setBodyIndex(i);
11351137 const inst = body[i];
11361138
1137 // This log is a bit expensive, and LLVM fails to optimize it away.
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 }
1139 std.log.scoped(.sema_zir).debug("sema ZIR {f} %{d}", .{ path.fmt(comp), inst });
11421140
11431141 const air_ref: Air.Inst.Ref = inst: switch (tags[@backingInt(inst)]) {
11441142 // zig fmt: off
src/Zcu/PerThread.zig+20-38
......@@ -25,6 +25,7 @@ const InternPool = @import("../InternPool.zig");
2525const AnalUnit = InternPool.AnalUnit;
2626const Module = @import("../Module.zig");
2727const Sema = @import("../Sema.zig");
28const debugLogScopeEnabled = @import("../main.zig").debugLogScopeEnabled;
2829const target_util = @import("../target.zig");
2930const tracy = @import("../tracy.zig");
3031const trace = tracy.trace;
......@@ -2303,10 +2304,9 @@ fn analyzeFuncBody(
23032304
23042305 const comp = zcu.comp;
23052306
2306 const dump_air = build_options.enable_debug_extensions and comp.verbose_air;
2307 const dump_llvm_ir = build_options.enable_debug_extensions and (comp.verbose_llvm_ir != null or comp.verbose_llvm_bc != null);
2308
2309 if (comp.bin_file != null or zcu.llvm_object != null or dump_air or dump_llvm_ir) {
2307 if (comp.bin_file != null or zcu.llvm_object != null or log_air: {
2308 break :log_air debugLogScopeEnabled("illegal-air") or debugLogScopeEnabled("legal-air") or debugLogScopeEnabled("air");
2309 }) {
23102310 zcu.codegen_prog_node.increaseEstimatedTotalItems(1);
23112311 comp.link_prog_node.increaseEstimatedTotalItems(1);
23122312
......@@ -4522,32 +4522,28 @@ fn runCodegenInner(pt: Zcu.PerThread, func_index: InternPool.Index, air: *Air) e
45224522 tracy_trace.addText(fqn.toSlice(ip));
45234523 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
45274536 if (codegen.legalizeFeatures(pt, nav)) |features| {
4528 try air.legalize(pt, features);
4529 // Verify the AIR again post-legalization.
4537 // Verify the AIR again pre-legalization.
45304538 Air.Verify.run(pt, func_index, air);
4539 try air.legalize(pt, features);
45314540 }
45324541
4533 var liveness: ?Air.Liveness = if (codegen.wantsLiveness(pt, nav))
4534 try .analyze(zcu, air.*, ip)
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 }
4542 std.log.scoped(.@"legal-air").debug("{f}", .{&ap});
4543 Air.Verify.run(pt, func_index, air);
45504544
4545 if (codegen.wantsLiveness(pt, nav)) liveness = try .analyze(zcu, air.*, ip);
4546 std.log.scoped(.air).debug("{f}", .{&ap});
45514547 if (std.debug.runtime_safety) verify_liveness: {
45524548 var verify: Air.Liveness.Verify = .{
45534549 .gpa = gpa,
......@@ -4577,17 +4573,3 @@ fn runCodegenInner(pt: Zcu.PerThread, func_index: InternPool.Index, air: *Air) e
45774573
45784574 return codegen.generateFunction(lf, pt, func_index, air, &liveness);
45794575}
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");
1010const Air = @import("../Air.zig");
1111const codegen = @import("../codegen.zig");
1212const Compilation = @import("../Compilation.zig");
13const debugLogScopeEnabled = @import("../main.zig").debugLogScopeEnabled;
1314const InternPool = @import("../InternPool.zig");
1415const link = @import("../link.zig");
1516const Module = @import("../Module.zig");
......@@ -331,12 +332,10 @@ pub const Object = struct {
331332 }
332333
333334 pub const EmitOptions = struct {
334 pre_ir_path: ?[]const u8,
335 pre_bc_path: ?[]const u8,
336335 bin_path: ?[:0]const u8,
337336 asm_path: ?[:0]const u8,
338 post_ir_path: ?[:0]const u8,
339 post_bc_path: ?[:0]const u8,
337 opt_ir_path: ?[:0]const u8,
338 opt_bc_path: ?[:0]const u8,
340339
341340 is_debug: bool,
342341 is_small: bool,
......@@ -351,6 +350,7 @@ pub const Object = struct {
351350 const comp = zcu.comp;
352351 const io = comp.io;
353352 const diags = &comp.link_diags;
353 const target = &comp.root_mod.resolved_target.result;
354354
355355 {
356356 if (o.errors_len_variable != .none) {
......@@ -403,7 +403,7 @@ pub const Object = struct {
403403 const behavior_max = try o.builder.metadataConstant(try o.builder.intConst(.i32, 7));
404404 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| {
407407 module_flags.appendAssumeCapacity(try o.builder.metadataTuple(&.{
408408 behavior_error,
409409 (try o.builder.metadataString("target-abi")).toMetadata(),
......@@ -411,7 +411,7 @@ pub const Object = struct {
411411 }));
412412 }
413413
414 const pic_level = target_util.picLevel(&comp.root_mod.resolved_target.result);
414 const pic_level = target_util.picLevel(target);
415415 if (comp.root_mod.pic) {
416416 module_flags.appendAssumeCapacity(try o.builder.metadataTuple(&.{
417417 behavior_min,
......@@ -434,7 +434,7 @@ pub const Object = struct {
434434 (try o.builder.metadataString("Code Model")).toMetadata(),
435435 try o.builder.metadataConstant(try o.builder.intConst(.i32, @as(
436436 i32,
437 switch (codeModel(comp.root_mod.code_model, &comp.root_mod.resolved_target.result)) {
437 switch (codeModel(comp.root_mod.code_model, target)) {
438438 .default => unreachable,
439439 .tiny => 0,
440440 .small => 1,
......@@ -480,7 +480,6 @@ pub const Object = struct {
480480 }
481481 }
482482
483 const target = &comp.root_mod.resolved_target.result;
484483 if (target.os.tag == .windows and (target.cpu.arch == .x86_64 or target.cpu.arch == .x86)) {
485484 // Add the "RegCallv4" flag so that any functions using `x86_regcallcc` use regcall
486485 // v4, which is essentially a requirement on Windows. See corresponding logic in
......@@ -515,21 +514,26 @@ pub const Object = struct {
515514
516515 const emit_asm_msg = options.asm_path orelse "(none)";
517516 const emit_bin_msg = options.bin_path orelse "(none)";
518 const post_llvm_ir_msg = options.post_ir_path orelse "(none)";
519 const post_llvm_bc_msg = options.post_bc_path orelse "(none)";
517 const opt_llvm_ir_msg = options.opt_ir_path orelse "(none)";
518 const opt_llvm_bc_msg = options.opt_bc_path orelse "(none)";
520519 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,
522521 });
522 const log_opt_llvm_ir = debugLogScopeEnabled("opt-llvm-ir");
523523
524524 const context, const module = emit: {
525 if (options.pre_ir_path) |path| {
526 if (std.mem.eql(u8, path, "-")) {
527 o.builder.dump(io);
528 } else {
529 o.builder.printToFilePath(io, Io.Dir.cwd(), path) catch |err| {
530 log.err("failed printing LLVM module to \"{s}\": {t}", .{ path, err });
531 };
532 }
525 {
526 var p: Builder.Print = .{ .name = comp.root_name, .builder = &o.builder, .err = null };
527 std.log.scoped(.@"llvm-ir").debug("{f}", .{&p});
528 if (p.err) |err| return err;
529 }
530
531 if (target.ofmt == .llvmir) {
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;
533537 }
534538
535539 const bitcode = try o.builder.toBitcode(o.gpa, .{
......@@ -538,23 +542,26 @@ pub const Object = struct {
538542 });
539543 defer o.gpa.free(bitcode);
540544
541 if (options.pre_bc_path) |path| {
542 var file = Io.Dir.cwd().createFile(io, path, .{}) catch |err|
543 return diags.fail("failed to create '{s}': {t}", .{ path, err });
545 if (target.ofmt == .llvmbc) {
546 const path = comp.bin_file.?.emit;
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 });
544549 defer file.close(io);
545550
546551 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;
548554 }
549555
550556 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
553560 if (!build_options.have_llvm or !comp.config.use_lib_llvm) {
554561 return diags.fail("emitting without libllvm not implemented", .{});
555562 }
556563
557 initializeLLVMTarget(io, comp.root_mod.resolved_target.result.cpu.arch);
564 initializeLLVMTarget(io, target.cpu.arch);
558565
559566 const context: *bindings.Context = .create();
560567 errdefer context.dispose();
......@@ -577,9 +584,9 @@ pub const Object = struct {
577584 };
578585 defer context.dispose();
579586
580 var target: *bindings.Target = undefined;
587 var llvm_target: *bindings.Target = undefined;
581588 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()) {
583590 defer bindings.disposeMessage(error_message);
584591 return diags.fail("LLVM failed to parse '{s}': {s}", .{ target_triple_sentinel, error_message });
585592 }
......@@ -598,7 +605,7 @@ pub const Object = struct {
598605 else
599606 .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)) {
602609 .default => .Default,
603610 .tiny => .Tiny,
604611 .small => .Small,
......@@ -607,24 +614,22 @@ pub const Object = struct {
607614 .large => .Large,
608615 };
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
615617 var target_machine = bindings.TargetMachine.create(
616 target,
618 llvm_target,
617619 target_triple_sentinel,
618 if (comp.root_mod.resolved_target.result.cpu.model.llvm_name) |s| s.ptr else null,
619 comp.root_mod.resolved_target.llvm_cpu_features.?,
620 if (target.cpu.model.llvm_name) |s| s.ptr else null,
621 comp.root_mod.llvm_cpu_features.?,
620622 opt_level,
621623 reloc_mode,
622624 code_model,
623625 comp.function_sections,
624626 comp.data_sections,
625 float_abi,
626 if (target_util.llvmMachineAbi(&comp.root_mod.resolved_target.result)) |s| s.ptr else null,
627 target_util.useEmulatedTls(&comp.root_mod.resolved_target.result),
627 switch (target.abi.float()) {
628 .hard => .Hard,
629 .soft => .Soft,
630 },
631 if (target_util.llvmMachineAbi(target)) |s| s.ptr else null,
632 target_util.useEmulatedTls(target),
628633 );
629634 errdefer target_machine.dispose();
630635
......@@ -634,7 +639,10 @@ pub const Object = struct {
634639
635640 // Unfortunately, LLVM shits the bed when we ask for both binary and assembly.
636641 // 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);
638646 var lowered_options: bindings.TargetMachine.EmitOptions = .{
639647 .is_debug = options.is_debug,
640648 .is_small = options.is_small,
......@@ -648,11 +656,12 @@ pub const Object = struct {
648656 .allow_fast_isel = true,
649657 // LLVM's RISC-V backend for some reason enables the machine outliner by default even
650658 // 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(),
652660 .asm_filename = null,
653661 .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,
655 .bitcode_filename = if (options.post_bc_path) |x| x.ptr else null,
662 .llvm_ir_filename = if (options.opt_ir_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
657666 // `.coverage` value is only used when `.sancov` is enabled.
658667 .sancov = options.fuzz or comp.config.san_cov_trace_pc_guard,
......@@ -684,33 +693,31 @@ pub const Object = struct {
684693 };
685694 if (options.asm_path != null and options.bin_path != null) {
686695 if (target_machine.emitToFile(module, &error_message, &lowered_options)) {
687 defer bindings.disposeMessage(error_message);
688696 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,
690698 });
691699 }
692700 lowered_options.bin_filename = null;
693701 lowered_options.llvm_ir_filename = null;
694702 lowered_options.bitcode_filename = null;
703 lowered_options.llvm_ir_out = null;
695704 }
696
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
705 if (options.time_report) |_| lowered_options.time_report_out = &time_report_c_str;
702706 lowered_options.asm_filename = if (options.asm_path) |x| x.ptr else null;
703707 if (target_machine.emitToFile(module, &error_message, &lowered_options)) {
704708 defer bindings.disposeMessage(error_message);
705709 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,
707711 });
708712 }
709 if (options.time_report) |tr| {
710 defer std.c.free(time_report_c_str);
711 const time_report_data = std.mem.span(time_report_c_str);
712 assert(tr.llvm_pass_timings.len == 0);
713 tr.llvm_pass_timings = try comp.gpa.dupe(u8, time_report_data);
713 if (log_opt_llvm_ir) std.log.scoped(.@"opt-llvm-ir").debug("{s}", .{
714 llvm_ir_c_str orelse return error.OutOfMemory,
715 });
716 if (options.time_report) |time_report| {
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 ));
714721 }
715722 }
716723
......@@ -2184,10 +2191,10 @@ pub const Object = struct {
21842191 .value = try o.builder.string(s),
21852192 } }, &o.builder);
21862193 }
2187 if (owner_mod.resolved_target.llvm_cpu_features) |s| {
2194 if (owner_mod.llvm_cpu_features) |s| {
21882195 try attributes.addFnAttr(.{ .string = .{
21892196 .kind = try o.builder.string("target-features"),
2190 .value = try o.builder.string(std.mem.span(s)),
2197 .value = try o.builder.string(s),
21912198 } }, &o.builder);
21922199 }
21932200
src/codegen/llvm/bindings.zig+3-2
......@@ -51,7 +51,7 @@ pub const Module = opaque {
5151};
5252
5353pub const disposeMessage = LLVMDisposeMessage;
54extern fn LLVMDisposeMessage(Message: [*:0]const u8) void;
54extern fn LLVMDisposeMessage(Message: ?[*:0]const u8) void;
5555
5656pub const TargetMachine = opaque {
5757 pub const FloatABI = enum(c_int) {
......@@ -85,7 +85,7 @@ pub const TargetMachine = opaque {
8585 pub const EmitOptions = extern struct {
8686 is_debug: bool,
8787 is_small: bool,
88 time_report_out: ?*[*:0]u8,
88 time_report_out: ?*?[*:0]u8,
8989 tsan: bool,
9090 sancov: bool,
9191 lto: LtoPhase,
......@@ -95,6 +95,7 @@ pub const TargetMachine = opaque {
9595 bin_filename: ?[*:0]const u8,
9696 llvm_ir_filename: ?[*:0]const u8,
9797 bitcode_filename: ?[*:0]const u8,
98 llvm_ir_out: ?*?[*:0]u8,
9899 coverage: Coverage,
99100
100101 pub const LtoPhase = enum(c_int) {
src/codegen/riscv64/CodeGen.zig+1-1
......@@ -27,7 +27,7 @@ const Target = std.Target;
2727const log = std.log.scoped(.riscv_codegen);
2828const tracking_log = std.log.scoped(.tracking);
2929const 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");
3131const Alignment = InternPool.Alignment;
3232
3333const bits = @import("bits.zig");
src/codegen/x86_64/CodeGen.zig+1-1
......@@ -5,7 +5,7 @@ const link = @import("../../link.zig");
55const log = std.log.scoped(.codegen);
66const tracking_log = std.log.scoped(.tracking);
77const 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");
99const Writer = std.Io.Writer;
1010
1111const Air = @import("../../Air.zig");
src/dev.zig+2
......@@ -112,6 +112,7 @@ pub const Env = enum {
112112 .loongarch_backend,
113113 .spork8_backend,
114114 .lld_linker,
115 .llvm_linker,
115116 .coff_linker,
116117 .elf_linker,
117118 .elf2_linker,
......@@ -333,6 +334,7 @@ pub const Feature = enum {
333334 spork8_backend,
334335
335336 lld_linker,
337 llvm_linker,
336338 coff_linker,
337339 elf_linker,
338340 elf2_linker,
src/libs/freebsd.zig-4
......@@ -1120,10 +1120,6 @@ fn buildSharedLib(
11201120 .emit_bin = .{ .yes_path = try bin_directory.join(arena, &.{basename}) },
11211121 .verbose_cc = comp.verbose_cc,
11221122 .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,
11271123 .clang_passthrough_mode = comp.clang_passthrough_mode,
11281124 .version = version,
11291125 .version_script = .{
src/libs/glibc.zig-4
......@@ -1268,10 +1268,6 @@ fn buildSharedLib(
12681268 .emit_bin = .{ .yes_path = try bin_directory.join(arena, &.{basename}) },
12691269 .verbose_cc = comp.verbose_cc,
12701270 .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,
12751271 .clang_passthrough_mode = comp.clang_passthrough_mode,
12761272 .version = version,
12771273 .version_script = .{
src/libs/libcxx.zig-8
......@@ -260,10 +260,6 @@ pub fn buildLibCxx(comp: *Compilation, prog_node: std.Progress.Node) BuildError!
260260 .c_source_files = c_source_files.items,
261261 .verbose_cc = comp.verbose_cc,
262262 .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,
267263 .clang_passthrough_mode = comp.clang_passthrough_mode,
268264 .skip_linker_dependencies = true,
269265 .environ_map = comp.environ_map,
......@@ -445,10 +441,6 @@ pub fn buildLibCxxAbi(comp: *Compilation, prog_node: std.Progress.Node) BuildErr
445441 .c_source_files = c_source_files.items,
446442 .verbose_cc = comp.verbose_cc,
447443 .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,
452444 .clang_passthrough_mode = comp.clang_passthrough_mode,
453445 .skip_linker_dependencies = true,
454446 .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
295295 .c_source_files = c_source_files.items,
296296 .verbose_cc = comp.verbose_cc,
297297 .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,
302298 .clang_passthrough_mode = comp.clang_passthrough_mode,
303299 .skip_linker_dependencies = skip_linker_dependencies,
304300 .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
157157 .c_source_files = &c_source_files,
158158 .verbose_cc = comp.verbose_cc,
159159 .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,
164160 .clang_passthrough_mode = comp.clang_passthrough_mode,
165161 .skip_linker_dependencies = true,
166162 .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
246246 .emit_bin = .yes_cache,
247247 .verbose_cc = comp.verbose_cc,
248248 .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,
252249 .clang_passthrough_mode = comp.clang_passthrough_mode,
253250 .c_source_files = &.{
254251 .{
src/libs/netbsd.zig-4
......@@ -771,10 +771,6 @@ fn buildSharedLib(
771771 .emit_bin = .{ .yes_path = try bin_directory.join(arena, &.{basename}) },
772772 .verbose_cc = comp.verbose_cc,
773773 .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,
778774 .clang_passthrough_mode = comp.clang_passthrough_mode,
779775 .version = version,
780776 .soname = soname,
src/libs/openbsd.zig-4
......@@ -691,10 +691,6 @@ fn buildSharedLib(
691691 .emit_bin = .{ .yes_path = try bin_directory.join(arena, &.{basename}) },
692692 .verbose_cc = comp.verbose_cc,
693693 .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,
698694 .clang_passthrough_mode = comp.clang_passthrough_mode,
699695 .soname = soname,
700696 .c_source_files = &c_source_files,
src/link.zig+35-4
......@@ -550,6 +550,7 @@ pub const File = struct {
550550 return &ptr.base;
551551 },
552552 .lld => unreachable, // not known from ofmt
553 .llvm => |tag| return createDummy(arena, tag, comp, emit),
553554 }
554555 }
555556
......@@ -573,9 +574,26 @@ pub const File = struct {
573574 return &ptr.base;
574575 },
575576 .lld => unreachable, // not known from ofmt
577 .llvm => |tag| return createDummy(arena, tag, comp, emit),
576578 }
577579 }
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
579597 pub fn cast(base: *File, comptime tag: Tag) if (dev.env.supports(tag.devFeature())) ?*tag.Type() else ?noreturn {
580598 return if (dev.env.supports(tag.devFeature()) and base.tag == tag) @fieldParentPtr("base", base) else null;
581599 }
......@@ -606,7 +624,7 @@ pub const File = struct {
606624 const gpa = comp.gpa;
607625 const io = comp.io;
608626 switch (base.tag) {
609 .lld => assert(base.file == null),
627 .lld, .llvm => assert(base.file == null),
610628 .elf, .macho, .wasm => {
611629 dev.checkAny(&.{ .coff_linker, .elf_linker, .macho_linker, .plan9_linker, .wasm_linker });
612630 if (base.file != null) return;
......@@ -706,7 +724,7 @@ pub const File = struct {
706724 if (!base.canMakeExecutable())
707725 return;
708726 switch (base.tag) {
709 .lld => assert(base.file == null),
727 .lld, .llvm => assert(base.file == null),
710728 .elf => if (base.file) |f| {
711729 dev.check(.elf_linker);
712730 f.close(io);
......@@ -827,6 +845,7 @@ pub const File = struct {
827845
828846 switch (base.tag) {
829847 .lld => unreachable,
848 .llvm => unreachable,
830849 .plan9 => unreachable,
831850 inline else => |tag| {
832851 dev.check(tag.devFeature());
......@@ -862,6 +881,7 @@ pub const File = struct {
862881 assert(pt.zcu.llvm_object == null);
863882 switch (base.tag) {
864883 .lld => unreachable,
884 .llvm => unreachable,
865885 .plan9 => unreachable,
866886 inline else => |tag| {
867887 dev.check(tag.devFeature());
......@@ -897,6 +917,7 @@ pub const File = struct {
897917 }
898918 switch (base.tag) {
899919 .lld => unreachable,
920 .llvm => unreachable,
900921 .plan9 => unreachable,
901922 .spirv => {},
902923 .coff => {},
......@@ -941,6 +962,7 @@ pub const File = struct {
941962 base.releaseLock();
942963 if (base.file) |f| f.close(io);
943964 switch (base.tag) {
965 .llvm => {},
944966 .plan9 => unreachable,
945967 inline else => |tag| {
946968 dev.check(tag.devFeature());
......@@ -1003,6 +1025,7 @@ pub const File = struct {
10031025 }
10041026 assert(base.post_prelink);
10051027 switch (base.tag) {
1028 .llvm => {},
10061029 .plan9 => unreachable,
10071030 inline else => |tag| {
10081031 dev.check(tag.devFeature());
......@@ -1030,6 +1053,7 @@ pub const File = struct {
10301053
10311054 switch (base.tag) {
10321055 .lld => unreachable,
1056 .llvm => unreachable,
10331057 .plan9 => unreachable,
10341058 inline else => |tag| {
10351059 dev.check(tag.devFeature());
......@@ -1056,6 +1080,7 @@ pub const File = struct {
10561080 assert(base.comp.zcu.?.llvm_object == null);
10571081 switch (base.tag) {
10581082 .lld => unreachable,
1083 .llvm => unreachable,
10591084 .c => unreachable,
10601085 .spirv => unreachable,
10611086 .wasm => unreachable,
......@@ -1078,6 +1103,7 @@ pub const File = struct {
10781103 assert(pt.zcu.llvm_object == null);
10791104 switch (base.tag) {
10801105 .lld => unreachable,
1106 .llvm => unreachable,
10811107 .c => unreachable,
10821108 .spirv => unreachable,
10831109 .wasm => unreachable,
......@@ -1095,6 +1121,7 @@ pub const File = struct {
10951121 assert(base.comp.zcu.?.llvm_object == null);
10961122 switch (base.tag) {
10971123 .lld => unreachable,
1124 .llvm => unreachable,
10981125 .c => unreachable,
10991126 .spirv => unreachable,
11001127 .wasm => unreachable,
......@@ -1124,6 +1151,7 @@ pub const File = struct {
11241151 .spirv,
11251152 .plan9,
11261153 .lld,
1154 .llvm,
11271155 .spork8,
11281156 => return .unimplemented,
11291157 inline else => |tag| {
......@@ -1240,7 +1268,7 @@ pub const File = struct {
12401268 dev.check(tag.devFeature());
12411269 return @as(*tag.Type(), @fieldParentPtr("base", base)).loadInput(input);
12421270 },
1243 .c, .spork8, .plan9, .lld => {},
1271 .c, .spork8, .plan9, .lld, .llvm => {},
12441272 }
12451273 }
12461274
......@@ -1352,6 +1380,7 @@ pub const File = struct {
13521380 coff,
13531381 elf,
13541382 elf2,
1383 llvm,
13551384 macho,
13561385 macho2,
13571386 c,
......@@ -1366,13 +1395,14 @@ pub const File = struct {
13661395 .coff => Coff,
13671396 .elf => Elf,
13681397 .elf2 => Elf2,
1398 .llvm => File,
13691399 .macho => MachO,
13701400 .macho2 => MachO2,
13711401 .c => C,
13721402 .wasm => Wasm,
13731403 .spirv => Spirv,
13741404 .lld => Lld,
1375 .plan9 => comptime unreachable,
1405 .plan9 => unreachable,
13761406 .spork8 => Spork8,
13771407 };
13781408 }
......@@ -1381,6 +1411,7 @@ pub const File = struct {
13811411 return switch (ofmt) {
13821412 .coff => .coff,
13831413 .elf => if (use_new_linker) .elf2 else .elf,
1414 .llvmbc, .llvmir => .llvm,
13841415 .macho => if (use_new_linker) .macho2 else .macho,
13851416 .wasm => .wasm,
13861417 .plan9 => .plan9,
src/link/Elf.zig+1-3
......@@ -860,9 +860,7 @@ fn flushInner(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id) !void {
860860
861861 // Dump the state for easy debugging.
862862 // State can be dumped via `--debug-log link_state`.
863 if (build_options.enable_logging) {
864 state_log.debug("{f}", .{self.dumpState()});
865 }
863 state_log.debug("{f}", .{self.dumpState()});
866864
867865 // Beyond this point, everything has been allocated a virtual address and we can resolve
868866 // 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 {
291291 if (metadata.rodata_state != .unused) metadata.rodata_state = .flushed;
292292 }
293293
294 if (build_options.enable_logging) {
294 if (build_options.enable_debug_extensions) {
295295 const active = elf_file.base.comp.zcu.?.activate(tid);
296296 defer active.deactivate();
297297 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 {
9898}
9999
100100fn 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
103103 assert(atom.visited);
104104 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 {
5151 try allocateAllocSections(elf_file);
5252 try elf_file.allocateNonAllocSections();
5353
54 if (build_options.enable_logging) {
55 state_log.debug("{f}", .{elf_file.dumpState()});
56 }
54 state_log.debug("{f}", .{elf_file.dumpState()});
5755
5856 try elf_file.writeMergeSections();
5957 try writeSyntheticSections(elf_file);
......@@ -117,10 +115,8 @@ pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation) !void {
117115 break :blk pos;
118116 };
119117
120 if (build_options.enable_logging) {
121 state_log.debug("ar_symtab\n{f}\n", .{ar_symtab.fmt(elf_file)});
122 state_log.debug("ar_strtab\n{f}\n", .{ar_strtab});
123 }
118 state_log.debug("ar_symtab\n{f}\n", .{ar_symtab.fmt(elf_file)});
119 state_log.debug("ar_strtab\n{f}\n", .{ar_strtab});
124120
125121 const buffer = try gpa.alloc(u8, total_size);
126122 defer gpa.free(buffer);
......@@ -193,9 +189,7 @@ pub fn flushObject(elf_file: *Elf, comp: *Compilation) !void {
193189 try allocateAllocSections(elf_file);
194190 try elf_file.allocateNonAllocSections();
195191
196 if (build_options.enable_logging) {
197 state_log.debug("{f}", .{elf_file.dumpState()});
198 }
192 state_log.debug("{f}", .{elf_file.dumpState()});
199193
200194 try writeAtoms(elf_file);
201195 try elf_file.writeMergeSections();
src/link/MachO.zig+1-3
......@@ -456,9 +456,7 @@ pub fn flush(
456456 self.allocateSegments();
457457 self.allocateSyntheticSymbols();
458458
459 if (build_options.enable_logging) {
460 state_log.debug("{f}", .{self.dumpState()});
461 }
459 state_log.debug("{f}", .{self.dumpState()});
462460
463461 // Beyond this point, everything has been allocated a virtual address and we can resolve
464462 // 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 {
123123 atom.getName(macho_file),
124124 });
125125
126 if (build_options.enable_logging)
126 if (build_options.enable_debug_extensions) {
127127 track_live_level.incr();
128 }
128129
129130 for (atom.getRelocs(macho_file)) |rel| {
130131 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 {
6161 };
6262 allocateSegment(macho_file);
6363
64 if (build_options.enable_logging) {
65 state_log.debug("{f}", .{macho_file.dumpState()});
66 }
64 state_log.debug("{f}", .{macho_file.dumpState()});
6765
6866 try writeSections(macho_file);
6967 sortRelocs(macho_file);
......@@ -107,9 +105,7 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation) link.Error!void {
107105 return diags.fail("failed to allocate sections: {s}", .{@errorName(err)});
108106 allocateSegment(macho_file);
109107
110 if (build_options.enable_logging) {
111 state_log.debug("{f}", .{macho_file.dumpState()});
112 }
108 state_log.debug("{f}", .{macho_file.dumpState()});
113109
114110 try writeSections(macho_file);
115111 sortRelocs(macho_file);
......@@ -185,9 +181,7 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation) link.Error!void {
185181 break :blk pos;
186182 };
187183
188 if (build_options.enable_logging) {
189 state_log.debug("ar_symtab\n{f}\n", .{ar_symtab.fmt(macho_file)});
190 }
184 state_log.debug("ar_symtab\n{f}\n", .{ar_symtab.fmt(macho_file)});
191185
192186 const buffer = try gpa.alloc(u8, total_size);
193187 defer gpa.free(buffer);
src/main.zig+40-74
......@@ -42,11 +42,8 @@ const thread_stack_size = 60 << 20;
4242
4343pub const std_options: std.Options = .{
4444 .logFn = log,
45
46 .log_level = switch (builtin.mode) {
47 .debug => .debug,
48 .safe, .fast => .info,
49 .small => .err,
45 .log_level = switch (build_options.log_level) {
46 inline else => |log_level| @field(std.log.Level, @tagName(log_level)),
5047 },
5148};
5249pub const std_options_cwd = if (native_os == .wasi) wasi_cwd else null;
......@@ -104,7 +101,7 @@ const normal_usage =
104101 \\ help Print this help and exit
105102 \\ cache-cat Print a zig-cache manifest file as zon
106103 \\ std View standard library documentation in a browser
107 \\ libc Display native libc paths file or validate one
104 \\ libc Print native libc paths file or validate one
108105 \\ targets List available compilation targets
109106 \\ version Print version number and exit
110107 \\ zen Print Zen of Zig and exit
......@@ -126,7 +123,15 @@ const debug_usage = normal_usage ++
126123
127124const 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
131136pub fn log(
132137 comptime level: std.log.Level,
......@@ -135,18 +140,11 @@ pub fn log(
135140 args: anytype,
136141) void {
137142 // Hide debug messages unless:
138 // * logging enabled with `-Dlog`.
143 // * logging enabled with `-Ddebug-extensions` or `-Dlog=debug`.
139144 // * the --debug-log arg for the scope has been provided
140 if (@backingInt(level) > @backingInt(std.options.log_level) or
141 @backingInt(level) > @backingInt(std.log.Level.info))
142 {
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;
145 switch (level) {
146 else => {},
147 .debug => if (!debugLogScopeEnabled(@tagName(scope))) return,
150148 }
151149
152150 // Otherwise, use the default implementation.
......@@ -557,11 +555,14 @@ const compile_usage =
557555 \\ -fno-emit-docs (default) Do not produce docs/ dir with html documentation
558556 \\ -femit-implib[=path] (default) Produce an import .lib when building a Windows DLL
559557 \\ -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
561558 \\ --cache-dir [path] Override the local cache directory
562559 \\ --global-cache-dir [path] Override the global cache directory
563560 \\ --zig-lib-dir [path] Override path to Zig installation lib directory
564561 \\ --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
565566 \\
566567 \\Global Compile Options:
567568 \\ --name [name] Compilation unit name (not a file path)
......@@ -593,7 +594,6 @@ const compile_usage =
593594 \\ -fpatchable-function-entry=[num] Add num NOPs of padding in function prologues
594595 \\ -mexec-model=[value] (WASI) Execution model
595596 \\ -municode (Windows) Use wmain/wWinMain as entry point
596 \\ --time-report Send timing diagnostics to '--listen' clients
597597 \\
598598 \\Per-Module Compile Options:
599599 \\ --dep [[import=]name] Add an entry to the next module's import table
......@@ -604,13 +604,15 @@ const compile_usage =
604604 \\ safe Enable both safety checks and machine code optimizations
605605 \\ small Prioritize small binary size. Safety checks off.
606606 \\ -ofmt=[fmt] Override target object format
607 \\ elf Executable and Linking Format
608607 \\ c C source code
609 \\ wasm WebAssembly
610608 \\ coff Common Object File Format (Windows)
609 \\ elf Executable and Linking Format
610 \\ llvmir LLVM text intermediate representation
611 \\ llvmbc LLVM binary intermediate representation
611612 \\ macho macOS relocatables
612 \\ spirv Standard, Portable Intermediate Representation V (SPIR-V)
613613 \\ plan9 Plan 9 from Bell Labs object format
614 \\ spirv Standard, Portable Intermediate Representation V (SPIR-V)
615 \\ wasm WebAssembly
614616 \\ hex (planned feature) Intel IHEX
615617 \\ raw (planned feature) Dump machine code directly
616618 \\ -mcpu [cpu] Specify target CPU and feature set
......@@ -791,15 +793,6 @@ const compile_usage =
791793 \\Debug Options (Zig Compiler Development):
792794 \\ -fopt-bisect-limit=[limit] Only run [limit] first LLVM optimization passes
793795 \\ -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
803796 \\ --debug-log [scope] Enable printing debug/info log messages for scope
804797 \\ --debug-compile-errors Crash with helpful diagnostics at the first compile error
805798 \\ --debug-link-snapshot Dump linker state and output file information for troubleshooting
......@@ -933,17 +926,11 @@ fn buildOutputType(
933926 var listen: Listen = .none;
934927 var debug_compile_errors = false;
935928 var debug_incremental = false;
936 var verbose_link = (native_os != .wasi or builtin.link_libc) and
937 EnvVar.ZIG_VERBOSE_LINK.isSet(environ_map);
938929 var verbose_cc = (native_os != .wasi or builtin.link_libc) and
939930 EnvVar.ZIG_VERBOSE_CC.isSet(environ_map);
940 var verbose_air = false;
941 var verbose_intern_pool = false;
942 var verbose_generic_instances = false;
943 var verbose_llvm_ir: ?[]const u8 = null;
944 var verbose_llvm_bc: ?[]const u8 = null;
931 var verbose_link = (native_os != .wasi or builtin.link_libc) and
932 EnvVar.ZIG_VERBOSE_LINK.isSet(environ_map);
945933 var link_depfile: ?[]const u8 = null;
946 var verbose_llvm_cpu_features = false;
947934 var time_report = false;
948935 var stack_report = false;
949936 var show_builtin = false;
......@@ -1809,24 +1796,10 @@ fn buildOutputType(
18091796 } else {
18101797 warn("Zig was compiled without debug extensions. --debug-compile-errors has no effect.", .{});
18111798 }
1812 } else if (mem.eql(u8, arg, "--verbose-link")) {
1813 verbose_link = true;
18141799 } else if (mem.eql(u8, arg, "--verbose-cc")) {
18151800 verbose_cc = true;
1816 } else if (mem.eql(u8, arg, "--verbose-air")) {
1817 verbose_air = 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;
1801 } else if (mem.eql(u8, arg, "--verbose-link")) {
1802 verbose_link = true;
18301803 } else if (mem.cutPrefix(u8, arg, "-T")) |rest| {
18311804 linker_script = rest;
18321805 } else if (mem.cutPrefix(u8, arg, "-L")) |rest| {
......@@ -3729,13 +3702,7 @@ fn buildOutputType(
37293702 .libc_installation = if (create_module.libc_installation) |*lci| lci else null,
37303703 .verbose_cc = verbose_cc,
37313704 .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,
37373705 .link_depfile = link_depfile,
3738 .verbose_llvm_cpu_features = verbose_llvm_cpu_features,
37393706 .time_report = time_report,
37403707 .stack_report = stack_report,
37413708 .build_id = build_id,
......@@ -3956,10 +3923,10 @@ fn buildOutputType(
39563923 });
39573924 }
39583925
3959 try test_exec_args.ensureUnusedCapacity(arena, 2 * log_scopes.items.len + @intFromBool(verbose_link) + @intFromBool(verbose_cc));
3960 for (log_scopes.items) |log_scope| test_exec_args.appendSliceAssumeCapacity(&.{ "--debug-log", log_scope });
3961 if (verbose_link) test_exec_args.appendAssumeCapacity("--verbose-link");
3926 try test_exec_args.ensureUnusedCapacity(arena, 2 * log_scopes.count() + @intFromBool(verbose_link) + @intFromBool(verbose_cc));
3927 for (log_scopes.keys()) |log_scope| test_exec_args.appendSliceAssumeCapacity(&.{ "--debug-log", log_scope });
39623928 if (verbose_cc) test_exec_args.appendAssumeCapacity("--verbose-cc");
3929 if (verbose_link) test_exec_args.appendAssumeCapacity("--verbose-link");
39633930 }
39643931
39653932 try runOrTest(
......@@ -5627,17 +5594,17 @@ fn cmdAstCheck(arena: Allocator, io: Io, args: []const []const u8, environ_map:
56275594 }
56285595 }
56295596
5630 const display_path = zig_source_path orelse "<stdin>";
5597 const print_path = zig_source_path orelse "<stdin>";
56315598 const source: [:0]const u8 = s: {
56325599 var f = if (zig_source_path) |p| file: {
56335600 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 });
56355602 };
56365603 } else Io.File.stdin();
56375604 defer if (zig_source_path != null) f.close(io);
56385605 var file_reader: Io.File.Reader = f.reader(io, &stdin_buffer);
56395606 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 });
56415608 };
56425609 };
56435610
......@@ -5661,7 +5628,7 @@ fn cmdAstCheck(arena: Allocator, io: Io, args: []const []const u8, environ_map:
56615628
56625629 if (zir.hasCompileErrors()) {
56635630 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);
56655632 var error_bundle = try wip_errors.toOwnedBundle("");
56665633 try error_bundle.renderToStderr(io, .{}, color);
56675634 if (zir.loweringFailed()) {
......@@ -5731,7 +5698,7 @@ fn cmdAstCheck(arena: Allocator, io: Io, args: []const []const u8, environ_map:
57315698 const zoir = try ZonGen.generate(arena, tree, .{});
57325699 if (zoir.hasCompileErrors()) {
57335700 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);
57355702 var error_bundle = try wip_errors.toOwnedBundle("");
57365703 error_bundle.renderToStderr(io, .{}, color) catch {};
57375704 process.exit(1);
......@@ -6254,9 +6221,8 @@ fn randInt(io: Io, comptime T: type) T {
62546221}
62556222
62566223fn addDebugLog(arena: Allocator, scope_name: []const u8) error{OutOfMemory}!void {
6257 if (!build_options.enable_logging) {
6258 warn("Zig was compiled without logging enabled (-Dlog). --debug-log has no effect.", .{});
6259 } else {
6260 try log_scopes.append(arena, scope_name);
6224 switch (build_options.log_level) {
6225 else => warn("Zig was compiled without logging enabled (-Dlog). --debug-log has no effect.", .{}),
6226 .debug => try log_scopes.put(arena, try arena.dupe(u8, scope_name), {}),
62616227 }
62626228}
src/target.zig+2
......@@ -193,6 +193,8 @@ pub fn hasLlvmSupport(target: *const std.Target, ofmt: std.Target.ObjectFormat)
193193 .coff,
194194 .elf,
195195 .hex,
196 .llvmbc,
197 .llvmir,
196198 .macho,
197199 .spirv,
198200 .raw,
src/zig_llvm.cpp+5-3
......@@ -410,6 +410,10 @@ ZIG_EXTERN_C bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machi
410410 // Code generation phase
411411 codegen_pm.run(llvm_module);
412412
413 if (options->llvm_ir_out != nullptr) {
414 *options->llvm_ir_out = LLVMPrintModuleToString(module_ref);
415 }
416
413417 if (options->llvm_ir_filename) {
414418 if (LLVMPrintModuleToFile(module_ref, options->llvm_ir_filename, error_message)) {
415419 return true;
......@@ -430,9 +434,7 @@ ZIG_EXTERN_C bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machi
430434 auto os = raw_string_ostream(out_str);
431435 TimerGroup::printAll(os);
432436 TimerGroup::clearAll();
433 auto c_str = (char *)malloc(out_str.length() + 1);
434 strcpy(c_str, out_str.c_str());
435 *options->time_report_out = c_str;
437 *options->time_report_out = LLVMCreateMessage(out_str.c_str());
436438 }
437439 return false;
438440}
src/zig_llvm.h+6-2
......@@ -67,8 +67,8 @@ struct ZigLLVMEmitOptions {
6767 bool is_debug;
6868 bool is_small;
6969 // If not null, and `ZigLLVMTargetMachineEmitToFile` returns `false` indicating success, this
70 // `char *` will be populated with a `malloc`-allocated string containing the serialized (as
71 // JSON) time report data. The caller is responsible for freeing that memory.
70 // `char *` will be populated with the serialized (as JSON) time report data. The caller is
71 // responsible for freeing that memory with `disposeMessage`.
7272 char **time_report_out;
7373 bool tsan;
7474 bool sancov;
......@@ -79,6 +79,10 @@ struct ZigLLVMEmitOptions {
7979 const char *bin_filename;
8080 const char *llvm_ir_filename;
8181 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;
8286 ZigLLVMCoverageOptions coverage;
8387};
8488
stage1/config.zig.in+1-1
......@@ -6,7 +6,7 @@ pub const llvm_has_xtensa = false;
66pub const version: [:0]const u8 = "@RESOLVED_ZIG_VERSION@";
77pub const semver = @import("std").SemanticVersion.parse(version) catch unreachable;
88pub const enable_debug_extensions = false;
9pub const enable_logging = false;
9pub const log_level: @import("std").log.Level = .err;
1010pub const enable_link_snapshots = false;
1111pub const enable_tracy = false;
1212pub const value_tracing = false;