authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-07-20 18:51:40-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-07-20 18:51:40-07:00
log1097b0ec77d421225250d981704aca6a617bd6b3
treefee35df2e1f8aa678fbffa87787709864bfd5759
parent91c4e28c5102223917ccf270fd466b796e0e0587

codegen: fix lowering of AIR return instruction

It incorrectly did not process the death of its operand. Additionally: * delete dead code accidentally introduced in fe14e339458a578657f3890f00d654a15c84422c * improve AIR printing code to include liveness data for operands. Now an exclamation point ("!") indicates the tombstone of an AIR instruction.

3 files changed, 91 insertions(+), 95 deletions(-)

src/Compilation.zig+3-56
...@@ -2007,59 +2007,6 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor...@@ -2007,59 +2007,6 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
2007 @panic("sadly stage2 is omitted from this build to save memory on the CI server");2007 @panic("sadly stage2 is omitted from this build to save memory on the CI server");
2008 const module = self.bin_file.options.module.?;2008 const module = self.bin_file.options.module.?;
2009 assert(decl.has_tv);2009 assert(decl.has_tv);
2010 if (decl.val.castTag(.function)) |payload| {
2011 if (decl.owns_tv) {
2012 const func = payload.data;
2013
2014 var air = switch (func.state) {
2015 .sema_failure, .dependency_failure => continue,
2016 .queued => module.analyzeFnBody(decl, func) catch |err| switch (err) {
2017 error.AnalysisFail => {
2018 assert(func.state != .in_progress);
2019 continue;
2020 },
2021 error.OutOfMemory => return error.OutOfMemory,
2022 },
2023 .in_progress => unreachable,
2024 .inline_only => unreachable, // don't queue work for this
2025 .success => unreachable, // don't queue it twice
2026 };
2027 defer air.deinit(gpa);
2028
2029 log.debug("analyze liveness of {s}", .{decl.name});
2030 var liveness = try Liveness.analyze(gpa, air, decl.namespace.file_scope.zir);
2031 defer liveness.deinit(gpa);
2032
2033 if (builtin.mode == .Debug and self.verbose_air) {
2034 std.debug.print("# Begin Function AIR: {s}:\n", .{decl.name});
2035 @import("print_air.zig").dump(gpa, air, liveness);
2036 std.debug.print("# End Function AIR: {s}:\n", .{decl.name});
2037 }
2038
2039 assert(decl.ty.hasCodeGenBits());
2040
2041 self.bin_file.updateFunc(module, func, air, liveness) catch |err| switch (err) {
2042 error.OutOfMemory => return error.OutOfMemory,
2043 error.AnalysisFail => {
2044 decl.analysis = .codegen_failure;
2045 continue;
2046 },
2047 else => {
2048 try module.failed_decls.ensureUnusedCapacity(gpa, 1);
2049 module.failed_decls.putAssumeCapacityNoClobber(decl, try Module.ErrorMsg.create(
2050 gpa,
2051 decl.srcLoc(),
2052 "unable to codegen: {s}",
2053 .{@errorName(err)},
2054 ));
2055 decl.analysis = .codegen_failure_retryable;
2056 continue;
2057 },
2058 };
2059 continue;
2060 }
2061 }
2062
2063 assert(decl.ty.hasCodeGenBits());2010 assert(decl.ty.hasCodeGenBits());
20642011
2065 self.bin_file.updateDecl(module, decl) catch |err| switch (err) {2012 self.bin_file.updateDecl(module, decl) catch |err| switch (err) {
...@@ -2069,7 +2016,7 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor...@@ -2069,7 +2016,7 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
2069 continue;2016 continue;
2070 },2017 },
2071 else => {2018 else => {
2072 try module.failed_decls.ensureCapacity(gpa, module.failed_decls.count() + 1);2019 try module.failed_decls.ensureUnusedCapacity(gpa, 1);
2073 module.failed_decls.putAssumeCapacityNoClobber(decl, try Module.ErrorMsg.create(2020 module.failed_decls.putAssumeCapacityNoClobber(decl, try Module.ErrorMsg.create(
2074 gpa,2021 gpa,
2075 decl.srcLoc(),2022 decl.srcLoc(),
...@@ -2123,7 +2070,7 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor...@@ -2123,7 +2070,7 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
21232070
2124 if (builtin.mode == .Debug and self.verbose_air) {2071 if (builtin.mode == .Debug and self.verbose_air) {
2125 std.debug.print("# Begin Function AIR: {s}:\n", .{decl.name});2072 std.debug.print("# Begin Function AIR: {s}:\n", .{decl.name});
2126 @import("print_air.zig").dump(gpa, air, liveness);2073 @import("print_air.zig").dump(gpa, air, decl.namespace.file_scope.zir, liveness);
2127 std.debug.print("# End Function AIR: {s}:\n", .{decl.name});2074 std.debug.print("# End Function AIR: {s}:\n", .{decl.name});
2128 }2075 }
21292076
...@@ -2207,7 +2154,7 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor...@@ -2207,7 +2154,7 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
2207 @panic("sadly stage2 is omitted from this build to save memory on the CI server");2154 @panic("sadly stage2 is omitted from this build to save memory on the CI server");
2208 const module = self.bin_file.options.module.?;2155 const module = self.bin_file.options.module.?;
2209 self.bin_file.updateDeclLineNumber(module, decl) catch |err| {2156 self.bin_file.updateDeclLineNumber(module, decl) catch |err| {
2210 try module.failed_decls.ensureCapacity(gpa, module.failed_decls.count() + 1);2157 try module.failed_decls.ensureUnusedCapacity(gpa, 1);
2211 module.failed_decls.putAssumeCapacityNoClobber(decl, try Module.ErrorMsg.create(2158 module.failed_decls.putAssumeCapacityNoClobber(decl, try Module.ErrorMsg.create(
2212 gpa,2159 gpa,
2213 decl.srcLoc(),2160 decl.srcLoc(),
src/codegen.zig+7-11
...@@ -481,7 +481,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -481,7 +481,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
481 fn finishAir(bt: *BigTomb, result: MCValue) void {481 fn finishAir(bt: *BigTomb, result: MCValue) void {
482 const is_used = !bt.function.liveness.isUnused(bt.inst);482 const is_used = !bt.function.liveness.isUnused(bt.inst);
483 if (is_used) {483 if (is_used) {
484 log.debug("{} => {}", .{ bt.inst, result });484 log.debug("%{d} => {}", .{ bt.inst, result });
485 const branch = &bt.function.branch_stack.items[bt.function.branch_stack.items.len - 1];485 const branch = &bt.function.branch_stack.items[bt.function.branch_stack.items.len - 1];
486 branch.inst_table.putAssumeCapacityNoClobber(bt.inst, result);486 branch.inst_table.putAssumeCapacityNoClobber(bt.inst, result);
487 }487 }
...@@ -871,12 +871,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -871,12 +871,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
871 // zig fmt: on871 // zig fmt: on
872 }872 }
873 if (std.debug.runtime_safety) {873 if (std.debug.runtime_safety) {
874 if (self.air_bookkeeping != old_air_bookkeeping + 1) {874 if (self.air_bookkeeping < old_air_bookkeeping + 1) {
875 std.debug.panic(875 std.debug.panic("in codegen.zig, handling of AIR instruction %{d} ('{}') did not do proper bookkeeping. Look for a missing call to finishAir.", .{ inst, air_tags[inst] });
876 \\in codegen.zig, handling of AIR instruction %{d} ('{}') did not do proper bookkeeping.
877 \\Look for a missing call to finishAir or an extra call to it.
878 \\
879 , .{ inst, air_tags[inst] });
880 }876 }
881 }877 }
882 }878 }
...@@ -963,7 +959,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -963,7 +959,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
963 }959 }
964 const is_used = @truncate(u1, tomb_bits) == 0;960 const is_used = @truncate(u1, tomb_bits) == 0;
965 if (is_used) {961 if (is_used) {
966 log.debug("{} => {}", .{ inst, result });962 log.debug("%{d} => {}", .{ inst, result });
967 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];963 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
968 branch.inst_table.putAssumeCapacityNoClobber(inst, result);964 branch.inst_table.putAssumeCapacityNoClobber(inst, result);
969 }965 }
...@@ -1350,10 +1346,10 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -1350,10 +1346,10 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
1350 self.register_manager.registers[index] = inst;1346 self.register_manager.registers[index] = inst;
1351 }1347 }
1352 }1348 }
1353 log.debug("reusing {} => {}", .{ reg, inst });1349 log.debug("%{d} => {} (reused)", .{ inst, reg });
1354 },1350 },
1355 .stack_offset => |off| {1351 .stack_offset => |off| {
1356 log.debug("reusing stack offset {} => {}", .{ off, inst });1352 log.debug("%{d} => stack offset {d} (reused)", .{ inst, off });
1357 },1353 },
1358 else => return false,1354 else => return false,
1359 }1355 }
...@@ -2852,7 +2848,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -2852,7 +2848,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
2852 const un_op = self.air.instructions.items(.data)[inst].un_op;2848 const un_op = self.air.instructions.items(.data)[inst].un_op;
2853 const operand = try self.resolveInst(un_op);2849 const operand = try self.resolveInst(un_op);
2854 try self.ret(operand);2850 try self.ret(operand);
2855 return self.finishAirBookkeeping();2851 return self.finishAir(inst, .dead, .{ un_op, .none, .none });
2856 }2852 }
28572853
2858 fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {2854 fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
src/print_air.zig+81-28
...@@ -4,10 +4,11 @@ const fmtIntSizeBin = std.fmt.fmtIntSizeBin;...@@ -4,10 +4,11 @@ const fmtIntSizeBin = std.fmt.fmtIntSizeBin;
44
5const Module = @import("Module.zig");5const Module = @import("Module.zig");
6const Value = @import("value.zig").Value;6const Value = @import("value.zig").Value;
7const Zir = @import("Zir.zig");
7const Air = @import("Air.zig");8const Air = @import("Air.zig");
8const Liveness = @import("Liveness.zig");9const Liveness = @import("Liveness.zig");
910
10pub fn dump(gpa: *Allocator, air: Air, liveness: Liveness) void {11pub fn dump(gpa: *Allocator, air: Air, zir: Zir, liveness: Liveness) void {
11 const instruction_bytes = air.instructions.len *12 const instruction_bytes = air.instructions.len *
12 // Here we don't use @sizeOf(Air.Inst.Data) because it would include13 // Here we don't use @sizeOf(Air.Inst.Data) because it would include
13 // the debug safety tag but we want to measure release size.14 // the debug safety tag but we want to measure release size.
...@@ -51,11 +52,13 @@ pub fn dump(gpa: *Allocator, air: Air, liveness: Liveness) void {...@@ -51,11 +52,13 @@ pub fn dump(gpa: *Allocator, air: Air, liveness: Liveness) void {
51 .gpa = gpa,52 .gpa = gpa,
52 .arena = &arena.allocator,53 .arena = &arena.allocator,
53 .air = air,54 .air = air,
55 .zir = zir,
54 .liveness = liveness,56 .liveness = liveness,
55 .indent = 0,57 .indent = 2,
56 };58 };
57 const stream = std.io.getStdErr().writer();59 const stream = std.io.getStdErr().writer();
58 writer.writeAllConstants(stream) catch return;60 writer.writeAllConstants(stream) catch return;
61 stream.writeByte('\n') catch return;
59 writer.writeBody(stream, air.getMainBody()) catch return;62 writer.writeBody(stream, air.getMainBody()) catch return;
60}63}
6164
...@@ -63,6 +66,7 @@ const Writer = struct {...@@ -63,6 +66,7 @@ const Writer = struct {
63 gpa: *Allocator,66 gpa: *Allocator,
64 arena: *Allocator,67 arena: *Allocator,
65 air: Air,68 air: Air,
69 zir: Zir,
66 liveness: Liveness,70 liveness: Liveness,
67 indent: usize,71 indent: usize,
6872
...@@ -84,13 +88,13 @@ const Writer = struct {...@@ -84,13 +88,13 @@ const Writer = struct {
84 fn writeBody(w: *Writer, s: anytype, body: []const Air.Inst.Index) @TypeOf(s).Error!void {88 fn writeBody(w: *Writer, s: anytype, body: []const Air.Inst.Index) @TypeOf(s).Error!void {
85 for (body) |inst| {89 for (body) |inst| {
86 try s.writeByteNTimes(' ', w.indent);90 try s.writeByteNTimes(' ', w.indent);
87 try s.print("%{d} ", .{inst});
88 try w.writeInst(s, inst);
89 if (w.liveness.isUnused(inst)) {91 if (w.liveness.isUnused(inst)) {
90 try s.writeAll(") unused\n");92 try s.print("%{d}!", .{inst});
91 } else {93 } else {
92 try s.writeAll(")\n");94 try s.print("%{d} ", .{inst});
93 }95 }
96 try w.writeInst(s, inst);
97 try s.writeAll(")\n");
94 }98 }
95 }99 }
96100
...@@ -176,21 +180,21 @@ const Writer = struct {...@@ -176,21 +180,21 @@ const Writer = struct {
176 }180 }
177181
178 fn writeTyStr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {182 fn writeTyStr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
179 _ = w;183 const ty_str = w.air.instructions.items(.data)[inst].ty_str;
180 _ = inst;184 const name = w.zir.nullTerminatedString(ty_str.str);
181 try s.writeAll("TODO");185 try s.print("\"{}\", {}", .{ std.zig.fmtEscapes(name), ty_str.ty });
182 }186 }
183187
184 fn writeBinOp(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {188 fn writeBinOp(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
185 const bin_op = w.air.instructions.items(.data)[inst].bin_op;189 const bin_op = w.air.instructions.items(.data)[inst].bin_op;
186 try w.writeInstRef(s, bin_op.lhs);190 try w.writeOperand(s, inst, 0, bin_op.lhs);
187 try s.writeAll(", ");191 try s.writeAll(", ");
188 try w.writeInstRef(s, bin_op.rhs);192 try w.writeOperand(s, inst, 1, bin_op.rhs);
189 }193 }
190194
191 fn writeUnOp(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {195 fn writeUnOp(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
192 const un_op = w.air.instructions.items(.data)[inst].un_op;196 const un_op = w.air.instructions.items(.data)[inst].un_op;
193 try w.writeInstRef(s, un_op);197 try w.writeOperand(s, inst, 0, un_op);
194 }198 }
195199
196 fn writeNoOp(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {200 fn writeNoOp(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
...@@ -208,7 +212,7 @@ const Writer = struct {...@@ -208,7 +212,7 @@ const Writer = struct {
208 fn writeTyOp(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {212 fn writeTyOp(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
209 const ty_op = w.air.instructions.items(.data)[inst].ty_op;213 const ty_op = w.air.instructions.items(.data)[inst].ty_op;
210 try s.print("{}, ", .{w.air.getRefType(ty_op.ty)});214 try s.print("{}, ", .{w.air.getRefType(ty_op.ty)});
211 try w.writeInstRef(s, ty_op.operand);215 try w.writeOperand(s, inst, 0, ty_op.operand);
212 }216 }
213217
214 fn writeBlock(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {218 fn writeBlock(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
...@@ -229,7 +233,7 @@ const Writer = struct {...@@ -229,7 +233,7 @@ const Writer = struct {
229 const ty_pl = w.air.instructions.items(.data)[inst].ty_pl;233 const ty_pl = w.air.instructions.items(.data)[inst].ty_pl;
230 const extra = w.air.extraData(Air.StructField, ty_pl.payload);234 const extra = w.air.extraData(Air.StructField, ty_pl.payload);
231235
232 try w.writeInstRef(s, extra.data.struct_ptr);236 try w.writeOperand(s, inst, 0, extra.data.struct_ptr);
233 try s.print(", {d}", .{extra.data.field_index});237 try s.print(", {d}", .{extra.data.field_index});
234 }238 }
235239
...@@ -259,21 +263,21 @@ const Writer = struct {...@@ -259,21 +263,21 @@ const Writer = struct {
259 fn writeCall(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {263 fn writeCall(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
260 const pl_op = w.air.instructions.items(.data)[inst].pl_op;264 const pl_op = w.air.instructions.items(.data)[inst].pl_op;
261 const extra = w.air.extraData(Air.Call, pl_op.payload);265 const extra = w.air.extraData(Air.Call, pl_op.payload);
262 const args = w.air.extra[extra.end..][0..extra.data.args_len];266 const args = @bitCast([]const Air.Inst.Ref, w.air.extra[extra.end..][0..extra.data.args_len]);
263 try w.writeInstRef(s, pl_op.operand);267 try w.writeOperand(s, inst, 0, pl_op.operand);
264 try s.writeAll(", [");268 try s.writeAll(", [");
265 for (args) |arg, i| {269 for (args) |arg, i| {
266 if (i != 0) try s.writeAll(", ");270 if (i != 0) try s.writeAll(", ");
267 try w.writeInstRef(s, @intToEnum(Air.Inst.Ref, arg));271 try w.writeOperand(s, inst, 1 + i, arg);
268 }272 }
269 try s.writeAll("]");273 try s.writeAll("]");
270 }274 }
271275
272 fn writeBr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {276 fn writeBr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
273 const br = w.air.instructions.items(.data)[inst].br;277 const br = w.air.instructions.items(.data)[inst].br;
274 try w.writeInstIndex(s, br.block_inst);278 try w.writeInstIndex(s, br.block_inst, false);
275 try s.writeAll(", ");279 try s.writeAll(", ");
276 try w.writeInstRef(s, br.operand);280 try w.writeOperand(s, inst, 0, br.operand);
277 }281 }
278282
279 fn writeCondBr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {283 fn writeCondBr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
...@@ -281,16 +285,35 @@ const Writer = struct {...@@ -281,16 +285,35 @@ const Writer = struct {
281 const extra = w.air.extraData(Air.CondBr, pl_op.payload);285 const extra = w.air.extraData(Air.CondBr, pl_op.payload);
282 const then_body = w.air.extra[extra.end..][0..extra.data.then_body_len];286 const then_body = w.air.extra[extra.end..][0..extra.data.then_body_len];
283 const else_body = w.air.extra[extra.end + then_body.len ..][0..extra.data.else_body_len];287 const else_body = w.air.extra[extra.end + then_body.len ..][0..extra.data.else_body_len];
288 const liveness_condbr = w.liveness.getCondBr(inst);
284289
285 try w.writeInstRef(s, pl_op.operand);290 try w.writeOperand(s, inst, 0, pl_op.operand);
286 try s.writeAll(", {\n");291 try s.writeAll(", {\n");
287 const old_indent = w.indent;292 const old_indent = w.indent;
288 w.indent += 2;293 w.indent += 2;
289294
295 if (liveness_condbr.then_deaths.len != 0) {
296 try s.writeByteNTimes(' ', w.indent);
297 for (liveness_condbr.then_deaths) |operand, i| {
298 if (i != 0) try s.writeAll(" ");
299 try s.print("%{d}!", .{operand});
300 }
301 try s.writeAll("\n");
302 }
303
290 try w.writeBody(s, then_body);304 try w.writeBody(s, then_body);
291 try s.writeByteNTimes(' ', old_indent);305 try s.writeByteNTimes(' ', old_indent);
292 try s.writeAll("}, {\n");306 try s.writeAll("}, {\n");
293307
308 if (liveness_condbr.else_deaths.len != 0) {
309 try s.writeByteNTimes(' ', w.indent);
310 for (liveness_condbr.else_deaths) |operand, i| {
311 if (i != 0) try s.writeAll(" ");
312 try s.print("%{d}!", .{operand});
313 }
314 try s.writeAll("\n");
315 }
316
294 try w.writeBody(s, else_body);317 try w.writeBody(s, else_body);
295 w.indent = old_indent;318 w.indent = old_indent;
296319
...@@ -304,7 +327,7 @@ const Writer = struct {...@@ -304,7 +327,7 @@ const Writer = struct {
304 var extra_index: usize = switch_br.end;327 var extra_index: usize = switch_br.end;
305 var case_i: u32 = 0;328 var case_i: u32 = 0;
306329
307 try w.writeInstRef(s, pl_op.operand);330 try w.writeOperand(s, inst, 0, pl_op.operand);
308 const old_indent = w.indent;331 const old_indent = w.indent;
309 w.indent += 2;332 w.indent += 2;
310333
...@@ -317,7 +340,7 @@ const Writer = struct {...@@ -317,7 +340,7 @@ const Writer = struct {
317 try s.writeAll(", [");340 try s.writeAll(", [");
318 for (items) |item, item_i| {341 for (items) |item, item_i| {
319 if (item_i != 0) try s.writeAll(", ");342 if (item_i != 0) try s.writeAll(", ");
320 try w.writeInstRef(s, item);343 try w.writeInstRef(s, item, false);
321 }344 }
322 try s.writeAll("] => {\n");345 try s.writeAll("] => {\n");
323 w.indent += 2;346 w.indent += 2;
...@@ -342,19 +365,49 @@ const Writer = struct {...@@ -342,19 +365,49 @@ const Writer = struct {
342 try s.writeAll("}");365 try s.writeAll("}");
343 }366 }
344367
345 fn writeInstRef(w: *Writer, s: anytype, inst: Air.Inst.Ref) @TypeOf(s).Error!void {368 fn writeOperand(
346 var i: usize = @enumToInt(inst);369 w: *Writer,
370 s: anytype,
371 inst: Air.Inst.Index,
372 op_index: usize,
373 operand: Air.Inst.Ref,
374 ) @TypeOf(s).Error!void {
375 const dies = if (op_index < Liveness.bpi - 1)
376 w.liveness.operandDies(inst, @intCast(Liveness.OperandInt, op_index))
377 else blk: {
378 // TODO
379 break :blk false;
380 };
381 return w.writeInstRef(s, operand, dies);
382 }
383
384 fn writeInstRef(
385 w: *Writer,
386 s: anytype,
387 operand: Air.Inst.Ref,
388 dies: bool,
389 ) @TypeOf(s).Error!void {
390 var i: usize = @enumToInt(operand);
347391
348 if (i < Air.Inst.Ref.typed_value_map.len) {392 if (i < Air.Inst.Ref.typed_value_map.len) {
349 return s.print("@{}", .{inst});393 return s.print("@{}", .{operand});
350 }394 }
351 i -= Air.Inst.Ref.typed_value_map.len;395 i -= Air.Inst.Ref.typed_value_map.len;
352396
353 return w.writeInstIndex(s, @intCast(Air.Inst.Index, i));397 return w.writeInstIndex(s, @intCast(Air.Inst.Index, i), dies);
354 }398 }
355399
356 fn writeInstIndex(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {400 fn writeInstIndex(
401 w: *Writer,
402 s: anytype,
403 inst: Air.Inst.Index,
404 dies: bool,
405 ) @TypeOf(s).Error!void {
357 _ = w;406 _ = w;
358 return s.print("%{d}", .{inst});407 if (dies) {
408 try s.print("%{d}!", .{inst});
409 } else {
410 try s.print("%{d}", .{inst});
411 }
359 }412 }
360};413};