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
20072007 @panic("sadly stage2 is omitted from this build to save memory on the CI server");
20082008 const module = self.bin_file.options.module.?;
20092009 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
20632010 assert(decl.ty.hasCodeGenBits());
20642011
20652012 self.bin_file.updateDecl(module, decl) catch |err| switch (err) {
......@@ -2069,7 +2016,7 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
20692016 continue;
20702017 },
20712018 else => {
2072 try module.failed_decls.ensureCapacity(gpa, module.failed_decls.count() + 1);
2019 try module.failed_decls.ensureUnusedCapacity(gpa, 1);
20732020 module.failed_decls.putAssumeCapacityNoClobber(decl, try Module.ErrorMsg.create(
20742021 gpa,
20752022 decl.srcLoc(),
......@@ -2123,7 +2070,7 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
21232070
21242071 if (builtin.mode == .Debug and self.verbose_air) {
21252072 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);
21272074 std.debug.print("# End Function AIR: {s}:\n", .{decl.name});
21282075 }
21292076
......@@ -2207,7 +2154,7 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
22072154 @panic("sadly stage2 is omitted from this build to save memory on the CI server");
22082155 const module = self.bin_file.options.module.?;
22092156 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);
22112158 module.failed_decls.putAssumeCapacityNoClobber(decl, try Module.ErrorMsg.create(
22122159 gpa,
22132160 decl.srcLoc(),
src/codegen.zig+7-11
......@@ -481,7 +481,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
481481 fn finishAir(bt: *BigTomb, result: MCValue) void {
482482 const is_used = !bt.function.liveness.isUnused(bt.inst);
483483 if (is_used) {
484 log.debug("{} => {}", .{ bt.inst, result });
484 log.debug("%{d} => {}", .{ bt.inst, result });
485485 const branch = &bt.function.branch_stack.items[bt.function.branch_stack.items.len - 1];
486486 branch.inst_table.putAssumeCapacityNoClobber(bt.inst, result);
487487 }
......@@ -871,12 +871,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
871871 // zig fmt: on
872872 }
873873 if (std.debug.runtime_safety) {
874 if (self.air_bookkeeping != old_air_bookkeeping + 1) {
875 std.debug.panic(
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] });
874 if (self.air_bookkeeping < old_air_bookkeeping + 1) {
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] });
880876 }
881877 }
882878 }
......@@ -963,7 +959,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
963959 }
964960 const is_used = @truncate(u1, tomb_bits) == 0;
965961 if (is_used) {
966 log.debug("{} => {}", .{ inst, result });
962 log.debug("%{d} => {}", .{ inst, result });
967963 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
968964 branch.inst_table.putAssumeCapacityNoClobber(inst, result);
969965 }
......@@ -1350,10 +1346,10 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
13501346 self.register_manager.registers[index] = inst;
13511347 }
13521348 }
1353 log.debug("reusing {} => {}", .{ reg, inst });
1349 log.debug("%{d} => {} (reused)", .{ inst, reg });
13541350 },
13551351 .stack_offset => |off| {
1356 log.debug("reusing stack offset {} => {}", .{ off, inst });
1352 log.debug("%{d} => stack offset {d} (reused)", .{ inst, off });
13571353 },
13581354 else => return false,
13591355 }
......@@ -2852,7 +2848,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
28522848 const un_op = self.air.instructions.items(.data)[inst].un_op;
28532849 const operand = try self.resolveInst(un_op);
28542850 try self.ret(operand);
2855 return self.finishAirBookkeeping();
2851 return self.finishAir(inst, .dead, .{ un_op, .none, .none });
28562852 }
28572853
28582854 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;
44
55const Module = @import("Module.zig");
66const Value = @import("value.zig").Value;
7const Zir = @import("Zir.zig");
78const Air = @import("Air.zig");
89const 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 {
1112 const instruction_bytes = air.instructions.len *
1213 // Here we don't use @sizeOf(Air.Inst.Data) because it would include
1314 // 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 {
5152 .gpa = gpa,
5253 .arena = &arena.allocator,
5354 .air = air,
55 .zir = zir,
5456 .liveness = liveness,
55 .indent = 0,
57 .indent = 2,
5658 };
5759 const stream = std.io.getStdErr().writer();
5860 writer.writeAllConstants(stream) catch return;
61 stream.writeByte('\n') catch return;
5962 writer.writeBody(stream, air.getMainBody()) catch return;
6063}
6164
......@@ -63,6 +66,7 @@ const Writer = struct {
6366 gpa: *Allocator,
6467 arena: *Allocator,
6568 air: Air,
69 zir: Zir,
6670 liveness: Liveness,
6771 indent: usize,
6872
......@@ -84,13 +88,13 @@ const Writer = struct {
8488 fn writeBody(w: *Writer, s: anytype, body: []const Air.Inst.Index) @TypeOf(s).Error!void {
8589 for (body) |inst| {
8690 try s.writeByteNTimes(' ', w.indent);
87 try s.print("%{d} ", .{inst});
88 try w.writeInst(s, inst);
8991 if (w.liveness.isUnused(inst)) {
90 try s.writeAll(") unused\n");
92 try s.print("%{d}!", .{inst});
9193 } else {
92 try s.writeAll(")\n");
94 try s.print("%{d} ", .{inst});
9395 }
96 try w.writeInst(s, inst);
97 try s.writeAll(")\n");
9498 }
9599 }
96100
......@@ -176,21 +180,21 @@ const Writer = struct {
176180 }
177181
178182 fn writeTyStr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
179 _ = w;
180 _ = inst;
181 try s.writeAll("TODO");
183 const ty_str = w.air.instructions.items(.data)[inst].ty_str;
184 const name = w.zir.nullTerminatedString(ty_str.str);
185 try s.print("\"{}\", {}", .{ std.zig.fmtEscapes(name), ty_str.ty });
182186 }
183187
184188 fn writeBinOp(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
185189 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);
187191 try s.writeAll(", ");
188 try w.writeInstRef(s, bin_op.rhs);
192 try w.writeOperand(s, inst, 1, bin_op.rhs);
189193 }
190194
191195 fn writeUnOp(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
192196 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);
194198 }
195199
196200 fn writeNoOp(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
......@@ -208,7 +212,7 @@ const Writer = struct {
208212 fn writeTyOp(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
209213 const ty_op = w.air.instructions.items(.data)[inst].ty_op;
210214 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);
212216 }
213217
214218 fn writeBlock(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
......@@ -229,7 +233,7 @@ const Writer = struct {
229233 const ty_pl = w.air.instructions.items(.data)[inst].ty_pl;
230234 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);
233237 try s.print(", {d}", .{extra.data.field_index});
234238 }
235239
......@@ -259,21 +263,21 @@ const Writer = struct {
259263 fn writeCall(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
260264 const pl_op = w.air.instructions.items(.data)[inst].pl_op;
261265 const extra = w.air.extraData(Air.Call, pl_op.payload);
262 const args = w.air.extra[extra.end..][0..extra.data.args_len];
263 try w.writeInstRef(s, pl_op.operand);
266 const args = @bitCast([]const Air.Inst.Ref, w.air.extra[extra.end..][0..extra.data.args_len]);
267 try w.writeOperand(s, inst, 0, pl_op.operand);
264268 try s.writeAll(", [");
265269 for (args) |arg, i| {
266270 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);
268272 }
269273 try s.writeAll("]");
270274 }
271275
272276 fn writeBr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
273277 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);
275279 try s.writeAll(", ");
276 try w.writeInstRef(s, br.operand);
280 try w.writeOperand(s, inst, 0, br.operand);
277281 }
278282
279283 fn writeCondBr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
......@@ -281,16 +285,35 @@ const Writer = struct {
281285 const extra = w.air.extraData(Air.CondBr, pl_op.payload);
282286 const then_body = w.air.extra[extra.end..][0..extra.data.then_body_len];
283287 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);
286291 try s.writeAll(", {\n");
287292 const old_indent = w.indent;
288293 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
290304 try w.writeBody(s, then_body);
291305 try s.writeByteNTimes(' ', old_indent);
292306 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
294317 try w.writeBody(s, else_body);
295318 w.indent = old_indent;
296319
......@@ -304,7 +327,7 @@ const Writer = struct {
304327 var extra_index: usize = switch_br.end;
305328 var case_i: u32 = 0;
306329
307 try w.writeInstRef(s, pl_op.operand);
330 try w.writeOperand(s, inst, 0, pl_op.operand);
308331 const old_indent = w.indent;
309332 w.indent += 2;
310333
......@@ -317,7 +340,7 @@ const Writer = struct {
317340 try s.writeAll(", [");
318341 for (items) |item, item_i| {
319342 if (item_i != 0) try s.writeAll(", ");
320 try w.writeInstRef(s, item);
343 try w.writeInstRef(s, item, false);
321344 }
322345 try s.writeAll("] => {\n");
323346 w.indent += 2;
......@@ -342,19 +365,49 @@ const Writer = struct {
342365 try s.writeAll("}");
343366 }
344367
345 fn writeInstRef(w: *Writer, s: anytype, inst: Air.Inst.Ref) @TypeOf(s).Error!void {
346 var i: usize = @enumToInt(inst);
368 fn writeOperand(
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
348392 if (i < Air.Inst.Ref.typed_value_map.len) {
349 return s.print("@{}", .{inst});
393 return s.print("@{}", .{operand});
350394 }
351395 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);
354398 }
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 {
357406 _ = 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 }
359412 }
360413};