authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-08-26 01:00:04-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-08-26 01:00:04-07:00
log0c5faa61aebca4215683d233dd52bf3a7a5d1db6
tree2ed6e829c2a74c5bb88384b420e11299eed6927f
parent237d9a105d5eec82aefc63da8e844c47d8990eea

stage2: codegen: fix reuseOperand not doing death bookkeeping


3 files changed, 79 insertions(+), 2 deletions(-)

src-self-hosted/codegen.zig+6-1
......@@ -632,6 +632,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
632632 /// Asserts there is already capacity to insert into top branch inst_table.
633633 fn processDeath(self: *Self, inst: *ir.Inst) void {
634634 if (inst.tag == .constant) return; // Constants are immortal.
635 // When editing this function, note that the logic must synchronize with `reuseOperand`.
635636 const prev_value = self.getResolvedInstValue(inst);
636637 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
637638 branch.inst_table.putAssumeCapacity(inst, .dead);
......@@ -951,6 +952,10 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
951952 // Prevent the operand deaths processing code from deallocating it.
952953 inst.clearOperandDeath(op_index);
953954
955 // That makes us responsible for doing the rest of the stuff that processDeath would have done.
956 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
957 branch.inst_table.putAssumeCapacity(inst.getOperand(op_index).?, .dead);
958
954959 return true;
955960 }
956961
......@@ -1666,7 +1671,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
16661671 // The instruction is only overridden in the else branch.
16671672 var i: usize = self.branch_stack.items.len - 2;
16681673 while (true) {
1669 i -= 1;
1674 i -= 1; // If this overflows, the question is: why wasn't the instruction marked dead?
16701675 if (self.branch_stack.items[i].inst_table.get(else_entry.key)) |mcv| {
16711676 assert(mcv != .dead);
16721677 break :blk mcv;
src-self-hosted/zir.zig+11-1
......@@ -954,6 +954,7 @@ pub const Module = struct {
954954
955955 pub const MetaData = struct {
956956 deaths: ir.Inst.DeathsInt,
957 addr: usize,
957958 };
958959
959960 pub const BodyMetaData = struct {
......@@ -1152,6 +1153,12 @@ const Writer = struct {
11521153 try self.writeInstToStream(stream, inst);
11531154 if (self.module.metadata.get(inst)) |metadata| {
11541155 try stream.print(" ; deaths=0b{b}", .{metadata.deaths});
1156 // This is conditionally compiled in because addresses mess up the tests due
1157 // to Address Space Layout Randomization. It's super useful when debugging
1158 // codegen.zig though.
1159 if (!std.builtin.is_test) {
1160 try stream.print(" 0x{x}", .{metadata.addr});
1161 }
11551162 }
11561163 self.indent -= 2;
11571164 try stream.writeByte('\n');
......@@ -2417,7 +2424,10 @@ const EmitZIR = struct {
24172424
24182425 .varptr => @panic("TODO"),
24192426 };
2420 try self.metadata.put(new_inst, .{ .deaths = inst.deaths });
2427 try self.metadata.put(new_inst, .{
2428 .deaths = inst.deaths,
2429 .addr = @ptrToInt(inst),
2430 });
24212431 try instructions.append(new_inst);
24222432 try inst_table.put(inst, new_inst);
24232433 }
test/stage2/test.zig+62
......@@ -694,6 +694,68 @@ pub fn addCases(ctx: *TestContext) !void {
694694 "",
695695 );
696696
697 // Reusing the registers of dead operands playing nicely with conditional branching.
698 case.addCompareOutput(
699 \\export fn _start() noreturn {
700 \\ assert(add(3, 4) == 791);
701 \\ assert(add(4, 3) == 79);
702 \\
703 \\ exit();
704 \\}
705 \\
706 \\fn add(a: u32, b: u32) u32 {
707 \\ const x: u32 = if (a < b) blk: {
708 \\ const c = a + b; // 7
709 \\ const d = a + c; // 10
710 \\ const e = d + b; // 14
711 \\ const f = d + e; // 24
712 \\ const g = e + f; // 38
713 \\ const h = f + g; // 62
714 \\ const i = g + h; // 100
715 \\ const j = i + d; // 110
716 \\ const k = i + j; // 210
717 \\ const l = k + c; // 217
718 \\ const m = l + d; // 227
719 \\ const n = m + e; // 241
720 \\ const o = n + f; // 265
721 \\ const p = o + g; // 303
722 \\ const q = p + h; // 365
723 \\ const r = q + i; // 465
724 \\ const s = r + j; // 575
725 \\ const t = s + k; // 785
726 \\ break :blk t;
727 \\ } else blk: {
728 \\ const t = b + b + a; // 10
729 \\ const c = a + t; // 14
730 \\ const d = c + t; // 24
731 \\ const e = d + t; // 34
732 \\ const f = e + t; // 44
733 \\ const g = f + t; // 54
734 \\ const h = c + g; // 68
735 \\ break :blk h + b; // 71
736 \\ };
737 \\ const y = x + a; // 788, 75
738 \\ const z = y + a; // 791, 79
739 \\ return z;
740 \\}
741 \\
742 \\pub fn assert(ok: bool) void {
743 \\ if (!ok) unreachable; // assertion failure
744 \\}
745 \\
746 \\fn exit() noreturn {
747 \\ asm volatile ("syscall"
748 \\ :
749 \\ : [number] "{rax}" (231),
750 \\ [arg1] "{rdi}" (0)
751 \\ : "rcx", "r11", "memory"
752 \\ );
753 \\ unreachable;
754 \\}
755 ,
756 "",
757 );
758
697759 // Character literals and multiline strings.
698760 case.addCompareOutput(
699761 \\export fn _start() noreturn {