| ... | @@ -810,7 +810,7 @@ const BigTomb = struct { | ... | @@ -810,7 +810,7 @@ const BigTomb = struct { |
| 810 | }; | 810 | }; |
| 811 | | 811 | |
| 812 | fn iterateBigTomb(self: *Self, inst: Air.Inst.Index, operand_count: usize) !BigTomb { | 812 | fn iterateBigTomb(self: *Self, inst: Air.Inst.Index, operand_count: usize) !BigTomb { |
| 813 | try self.currentBranch().values.ensureUnusedCapacity(self.gpa, @intCast(u32, operand_count + 1)); | 813 | try self.currentBranch().values.ensureUnusedCapacity(self.gpa, operand_count + 1); |
| 814 | return BigTomb{ | 814 | return BigTomb{ |
| 815 | .gen = self, | 815 | .gen = self, |
| 816 | .inst = inst, | 816 | .inst = inst, |
| ... | @@ -826,7 +826,7 @@ fn processDeath(self: *Self, ref: Air.Inst.Ref) void { | ... | @@ -826,7 +826,7 @@ fn processDeath(self: *Self, ref: Air.Inst.Ref) void { |
| 826 | // TODO: Upon branch consolidation free any locals if needed. | 826 | // TODO: Upon branch consolidation free any locals if needed. |
| 827 | const value = self.currentBranch().values.getPtr(ref) orelse return; | 827 | const value = self.currentBranch().values.getPtr(ref) orelse return; |
| 828 | if (value.* != .local) return; | 828 | if (value.* != .local) return; |
| 829 | std.debug.print("Decreasing reference for ref: %{?d}\n", .{Air.refToIndex(ref)}); | 829 | log.debug("Decreasing reference for ref: %{?d}\n", .{Air.refToIndex(ref)}); |
| 830 | value.local.references -= 1; // if this panics, a call to `reuseOperand` was forgotten by the developer | 830 | value.local.references -= 1; // if this panics, a call to `reuseOperand` was forgotten by the developer |
| 831 | if (value.local.references == 0) { | 831 | if (value.local.references == 0) { |
| 832 | value.free(self); | 832 | value.free(self); |
| ... | @@ -989,18 +989,23 @@ fn allocLocal(self: *Self, ty: Type) InnerError!WValue { | ... | @@ -989,18 +989,23 @@ fn allocLocal(self: *Self, ty: Type) InnerError!WValue { |
| 989 | const valtype = typeToValtype(ty, self.target); | 989 | const valtype = typeToValtype(ty, self.target); |
| 990 | switch (valtype) { | 990 | switch (valtype) { |
| 991 | .i32 => if (self.free_locals_i32.popOrNull()) |index| { | 991 | .i32 => if (self.free_locals_i32.popOrNull()) |index| { |
| | 992 | log.debug("reusing local ({d}) of type {}\n", .{ index, valtype }); |
| 992 | return WValue{ .local = .{ .value = index, .references = 1 } }; | 993 | return WValue{ .local = .{ .value = index, .references = 1 } }; |
| 993 | }, | 994 | }, |
| 994 | .i64 => if (self.free_locals_i64.popOrNull()) |index| { | 995 | .i64 => if (self.free_locals_i64.popOrNull()) |index| { |
| | 996 | log.debug("reusing local ({d}) of type {}\n", .{ index, valtype }); |
| 995 | return WValue{ .local = .{ .value = index, .references = 1 } }; | 997 | return WValue{ .local = .{ .value = index, .references = 1 } }; |
| 996 | }, | 998 | }, |
| 997 | .f32 => if (self.free_locals_f32.popOrNull()) |index| { | 999 | .f32 => if (self.free_locals_f32.popOrNull()) |index| { |
| | 1000 | log.debug("reusing local ({d}) of type {}\n", .{ index, valtype }); |
| 998 | return WValue{ .local = .{ .value = index, .references = 1 } }; | 1001 | return WValue{ .local = .{ .value = index, .references = 1 } }; |
| 999 | }, | 1002 | }, |
| 1000 | .f64 => if (self.free_locals_f64.popOrNull()) |index| { | 1003 | .f64 => if (self.free_locals_f64.popOrNull()) |index| { |
| | 1004 | log.debug("reusing local ({d}) of type {}\n", .{ index, valtype }); |
| 1001 | return WValue{ .local = .{ .value = index, .references = 1 } }; | 1005 | return WValue{ .local = .{ .value = index, .references = 1 } }; |
| 1002 | }, | 1006 | }, |
| 1003 | } | 1007 | } |
| | 1008 | log.debug("new local of type {}\n", .{valtype}); |
| 1004 | // no local was free to be re-used, so allocate a new local instead | 1009 | // no local was free to be re-used, so allocate a new local instead |
| 1005 | return self.ensureAllocLocal(ty); | 1010 | return self.ensureAllocLocal(ty); |
| 1006 | } | 1011 | } |
| ... | @@ -1888,7 +1893,8 @@ fn genInst(self: *Self, inst: Air.Inst.Index) InnerError!void { | ... | @@ -1888,7 +1893,8 @@ fn genInst(self: *Self, inst: Air.Inst.Index) InnerError!void { |
| 1888 | fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | 1893 | fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 1889 | for (body) |inst| { | 1894 | for (body) |inst| { |
| 1890 | const old_bookkeeping_value = self.air_bookkeeping; | 1895 | const old_bookkeeping_value = self.air_bookkeeping; |
| 1891 | try self.currentBranch().values.ensureUnusedCapacity(self.gpa, Liveness.bpi); | 1896 | // TODO: Determine why we need to pre-allocate an extra 4 possible values here. |
| | 1897 | try self.currentBranch().values.ensureUnusedCapacity(self.gpa, Liveness.bpi + 4); |
| 1892 | try self.genInst(inst); | 1898 | try self.genInst(inst); |
| 1893 | | 1899 | |
| 1894 | if (builtin.mode == .Debug and self.air_bookkeeping < old_bookkeeping_value + 1) { | 1900 | if (builtin.mode == .Debug and self.air_bookkeeping < old_bookkeeping_value + 1) { |
| ... | @@ -1897,10 +1903,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -1897,10 +1903,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 1897 | self.air.instructions.items(.tag)[inst], | 1903 | self.air.instructions.items(.tag)[inst], |
| 1898 | }); | 1904 | }); |
| 1899 | } | 1905 | } |
| 1900 | // if (result != .none) { | | |
| 1901 | // assert(result != .stack); // not allowed to store stack values as we cannot keep track of where they are on the stack | | |
| 1902 | // try self.values.putNoClobber(self.gpa, Air.indexToRef(inst), result); | | |
| 1903 | // } | | |
| 1904 | } | 1906 | } |
| 1905 | } | 1907 | } |
| 1906 | | 1908 | |
| ... | @@ -2844,65 +2846,43 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) InnerError!void { | ... | @@ -2844,65 +2846,43 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) InnerError!void { |
| 2844 | | 2846 | |
| 2845 | try self.branches.ensureUnusedCapacity(self.gpa, 2); | 2847 | try self.branches.ensureUnusedCapacity(self.gpa, 2); |
| 2846 | | 2848 | |
| 2847 | const else_stack = self.branches.addOneAssumeCapacity(); | 2849 | self.branches.appendAssumeCapacity(.{}); |
| 2848 | else_stack.* = .{}; | | |
| 2849 | defer else_stack.deinit(self.gpa); | | |
| 2850 | | | |
| 2851 | try self.currentBranch().values.ensureUnusedCapacity(self.gpa, @intCast(u32, liveness_condbr.else_deaths.len)); | 2850 | try self.currentBranch().values.ensureUnusedCapacity(self.gpa, @intCast(u32, liveness_condbr.else_deaths.len)); |
| 2852 | for (liveness_condbr.else_deaths) |death| { | 2851 | for (liveness_condbr.else_deaths) |death| { |
| 2853 | self.processDeath(Air.indexToRef(death)); | 2852 | self.processDeath(Air.indexToRef(death)); |
| 2854 | std.debug.print("Death inst: %{d}\n", .{death}); | | |
| 2855 | } | 2853 | } |
| 2856 | try self.genBody(else_body); | 2854 | try self.genBody(else_body); |
| 2857 | try self.endBlock(); | 2855 | try self.endBlock(); |
| 2858 | else_stack.* = self.branches.pop(); | 2856 | var else_stack = self.branches.pop(); |
| | 2857 | defer else_stack.deinit(self.gpa); |
| 2859 | | 2858 | |
| 2860 | // Outer block that matches the condition | 2859 | // Outer block that matches the condition |
| 2861 | const then_stack = self.branches.addOneAssumeCapacity(); | 2860 | self.branches.appendAssumeCapacity(.{}); |
| 2862 | then_stack.* = .{}; | | |
| 2863 | defer then_stack.deinit(self.gpa); | | |
| 2864 | | | |
| 2865 | try self.currentBranch().values.ensureUnusedCapacity(self.gpa, @intCast(u32, liveness_condbr.then_deaths.len)); | 2861 | try self.currentBranch().values.ensureUnusedCapacity(self.gpa, @intCast(u32, liveness_condbr.then_deaths.len)); |
| 2866 | for (liveness_condbr.then_deaths) |death| { | 2862 | for (liveness_condbr.then_deaths) |death| { |
| 2867 | self.processDeath(Air.indexToRef(death)); | 2863 | self.processDeath(Air.indexToRef(death)); |
| 2868 | std.debug.print("Death inst: %{d}\n", .{death}); | | |
| 2869 | } | 2864 | } |
| 2870 | try self.genBody(then_body); | 2865 | try self.genBody(then_body); |
| 2871 | then_stack.* = self.branches.pop(); | 2866 | var then_stack = self.branches.pop(); |
| | 2867 | defer then_stack.deinit(self.gpa); |
| 2872 | | 2868 | |
| 2873 | try self.canonicaliseBranches(then_stack, else_stack); | 2869 | try self.mergeBranch(&else_stack); |
| | 2870 | try self.mergeBranch(&then_stack); |
| 2874 | | 2871 | |
| 2875 | // TODO: Branch consilidation to process deaths from branches | | |
| 2876 | self.finishAir(inst, .none, &.{}); | 2872 | self.finishAir(inst, .none, &.{}); |
| 2877 | } | 2873 | } |
| 2878 | | 2874 | |
| 2879 | fn canonicaliseBranches(self: *Self, canon_branch: *Branch, target_branch: *Branch) !void { | 2875 | fn mergeBranch(self: *Self, branch: *const Branch) !void { |
| 2880 | const parent = self.currentBranch(); | 2876 | const parent = self.currentBranch(); |
| 2881 | | 2877 | |
| 2882 | const target_slice = target_branch.values.entries.slice(); | 2878 | const target_slice = branch.values.entries.slice(); |
| 2883 | const target_keys = target_slice.items(.key); | 2879 | const target_keys = target_slice.items(.key); |
| 2884 | const target_values = target_slice.items(.value); | 2880 | const target_values = target_slice.items(.value); |
| 2885 | | 2881 | |
| 2886 | try parent.values.ensureUnusedCapacity(self.gpa, target_branch.values.count()); | 2882 | try parent.values.ensureUnusedCapacity(self.gpa, branch.values.count()); |
| 2887 | for (target_keys) |key, index| { | 2883 | for (target_keys) |key, index| { |
| 2888 | const value = target_values[index]; | 2884 | // TODO: process deaths from branches |
| 2889 | const canon_value = if (canon_branch.values.fetchSwapRemove(key)) |canon_entry| { | 2885 | parent.values.putAssumeCapacity(key, target_values[index]); |
| 2890 | // try parent.values.putAssumeCapacity(key, canon_entry.value); | | |
| 2891 | _ = canon_entry; | | |
| 2892 | // _ = result_value; | | |
| 2893 | @panic("HMMMM THIS occurs"); | | |
| 2894 | // break :result_value canon_entry.value; | | |
| 2895 | } else value; | | |
| 2896 | | | |
| 2897 | parent.values.putAssumeCapacity(key, canon_value); | | |
| 2898 | } | | |
| 2899 | | | |
| 2900 | try parent.values.ensureUnusedCapacity(self.gpa, canon_branch.values.count()); | | |
| 2901 | const canon_slice = canon_branch.values.entries.slice(); | | |
| 2902 | const canon_keys = canon_slice.items(.key); | | |
| 2903 | const canon_values = canon_slice.items(.value); | | |
| 2904 | for (canon_keys) |key, index| { | | |
| 2905 | parent.values.putAssumeCapacity(key, canon_values[index]); | | |
| 2906 | } | 2886 | } |
| 2907 | } | 2887 | } |
| 2908 | | 2888 | |
| ... | @@ -3173,6 +3153,9 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) InnerError!void { | ... | @@ -3173,6 +3153,9 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) InnerError!void { |
| 3173 | const target = try self.resolveInst(pl_op.operand); | 3153 | const target = try self.resolveInst(pl_op.operand); |
| 3174 | const target_ty = self.air.typeOf(pl_op.operand); | 3154 | const target_ty = self.air.typeOf(pl_op.operand); |
| 3175 | const switch_br = self.air.extraData(Air.SwitchBr, pl_op.payload); | 3155 | const switch_br = self.air.extraData(Air.SwitchBr, pl_op.payload); |
| | 3156 | const liveness = try self.liveness.getSwitchBr(self.gpa, inst, switch_br.data.cases_len + 1); |
| | 3157 | defer self.gpa.free(liveness.deaths); |
| | 3158 | |
| 3176 | var extra_index: usize = switch_br.end; | 3159 | var extra_index: usize = switch_br.end; |
| 3177 | var case_i: u32 = 0; | 3160 | var case_i: u32 = 0; |
| 3178 | | 3161 | |
| ... | @@ -3283,7 +3266,7 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) InnerError!void { | ... | @@ -3283,7 +3266,7 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) InnerError!void { |
| 3283 | }; | 3266 | }; |
| 3284 | | 3267 | |
| 3285 | try self.branches.ensureUnusedCapacity(self.gpa, case_list.items.len + @boolToInt(has_else_body)); | 3268 | try self.branches.ensureUnusedCapacity(self.gpa, case_list.items.len + @boolToInt(has_else_body)); |
| 3286 | for (case_list.items) |case| { | 3269 | for (case_list.items) |case, index| { |
| 3287 | // when sparse, we use if/else-chain, so emit conditional checks | 3270 | // when sparse, we use if/else-chain, so emit conditional checks |
| 3288 | if (is_sparse) { | 3271 | if (is_sparse) { |
| 3289 | // for single value prong we can emit a simple if | 3272 | // for single value prong we can emit a simple if |
| ... | @@ -3318,18 +3301,31 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) InnerError!void { | ... | @@ -3318,18 +3301,31 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) InnerError!void { |
| 3318 | try self.endBlock(); | 3301 | try self.endBlock(); |
| 3319 | } | 3302 | } |
| 3320 | } | 3303 | } |
| 3321 | // try self.branches.items | | |
| 3322 | self.branches.appendAssumeCapacity(.{}); | 3304 | self.branches.appendAssumeCapacity(.{}); |
| | 3305 | |
| | 3306 | try self.currentBranch().values.ensureUnusedCapacity(self.gpa, liveness.deaths[index].len); |
| | 3307 | for (liveness.deaths[index]) |operand| { |
| | 3308 | self.processDeath(Air.indexToRef(operand)); |
| | 3309 | } |
| 3323 | try self.genBody(case.body); | 3310 | try self.genBody(case.body); |
| 3324 | try self.endBlock(); | 3311 | try self.endBlock(); |
| 3325 | _ = self.branches.pop(); | 3312 | var case_branch = self.branches.pop(); |
| | 3313 | defer case_branch.deinit(self.gpa); |
| | 3314 | try self.mergeBranch(&case_branch); |
| 3326 | } | 3315 | } |
| 3327 | | 3316 | |
| 3328 | if (has_else_body) { | 3317 | if (has_else_body) { |
| 3329 | self.branches.appendAssumeCapacity(.{}); | 3318 | self.branches.appendAssumeCapacity(.{}); |
| | 3319 | const else_deaths = liveness.deaths.len - 1; |
| | 3320 | try self.currentBranch().values.ensureUnusedCapacity(self.gpa, liveness.deaths[else_deaths].len); |
| | 3321 | for (liveness.deaths[else_deaths]) |operand| { |
| | 3322 | self.processDeath(Air.indexToRef(operand)); |
| | 3323 | } |
| 3330 | try self.genBody(else_body); | 3324 | try self.genBody(else_body); |
| 3331 | try self.endBlock(); | 3325 | try self.endBlock(); |
| 3332 | _ = self.branches.pop(); | 3326 | var else_branch = self.branches.pop(); |
| | 3327 | defer else_branch.deinit(self.gpa); |
| | 3328 | try self.mergeBranch(&else_branch); |
| 3333 | } | 3329 | } |
| 3334 | self.finishAir(inst, .none, &.{}); | 3330 | self.finishAir(inst, .none, &.{}); |
| 3335 | } | 3331 | } |