authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2020-10-20 23:10:15+03:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2020-10-30 15:58:13+02:00
log3cc68bd9138b5fda6d6066d9c49f7e1b5e04a5ee
treea588e7b5e31c4e2eb9fcd44fbbb9aec441029fc6
parent769d5a9c435c5c145983e4d3af1706924248e367
signaturelock-open Commit is signed but in an unrecognized format.

stage2: switch liveness analysis


2 files changed, 105 insertions(+), 6 deletions(-)

src/liveness.zig+85
......@@ -144,6 +144,91 @@ fn analyzeInst(
144144 // instruction, and the deaths flag for the CondBr instruction will indicate whether the
145145 // condition's lifetime ends immediately before entering any branch.
146146 },
147 .switchbr => {
148 const inst = base.castTag(.switchbr).?;
149
150 const Table = std.AutoHashMap(*ir.Inst, void);
151 const case_tables = try table.allocator.alloc(Table, inst.cases.len + 1); // +1 for else
152 defer table.allocator.free(case_tables);
153
154 std.mem.set(Table, case_tables, Table.init(table.allocator));
155 defer for (case_tables) |*ct| ct.deinit();
156
157 for (inst.cases) |case, i| {
158 try analyzeWithTable(arena, table, &case_tables[i], case.body);
159
160 // Reset the table back to its state from before the case.
161 var it = case_tables[i].iterator();
162 while (it.next()) |entry| {
163 table.removeAssertDiscard(entry.key);
164 }
165 }
166 { // else
167 try analyzeWithTable(arena, table, &case_tables[case_tables.len - 1], inst.else_body);
168
169 // Reset the table back to its state from before the case.
170 var it = case_tables[case_tables.len - 1].iterator();
171 while (it.next()) |entry| {
172 table.removeAssertDiscard(entry.key);
173 }
174 }
175
176 const List = std.ArrayList(*ir.Inst);
177 const case_deaths = try table.allocator.alloc(List, case_tables.len); // +1 for else
178 defer table.allocator.free(case_deaths);
179
180 std.mem.set(List, case_deaths, List.init(table.allocator));
181 defer for (case_deaths) |*cd| cd.deinit();
182
183 var total_deaths: u32 = 0;
184 for (case_tables) |*ct, i| {
185 total_deaths += ct.count();
186 var it = ct.iterator();
187 while (it.next()) |entry| {
188 const case_death = entry.key;
189 for (case_tables) |*ct_inner, j| {
190 if (i == j) continue;
191 if (!ct_inner.contains(case_death)) {
192 try case_deaths[i].append(case_death);
193 }
194 }
195 // undo resetting the table
196 _ = try table.put(case_death, {});
197 }
198 }
199
200 // Now we have to correctly populate new_set.
201 if (new_set) |ns| {
202 try ns.ensureCapacity(@intCast(u32, ns.count() + total_deaths));
203 for (case_tables) |*ct| {
204 var it = ct.iterator();
205 while (it.next()) |entry| {
206 _ = ns.putAssumeCapacity(entry.key, {});
207 }
208 }
209 }
210
211 total_deaths = 0;
212 for (case_deaths[0 .. case_deaths.len - 1]) |*ct, i| {
213 inst.cases[i].index = total_deaths;
214 const len = std.math.cast(@TypeOf(inst.else_deaths), ct.items.len) catch return error.OutOfMemory;
215 inst.cases[i].deaths = len;
216 total_deaths += len;
217 }
218 { // else
219 const else_deaths = std.math.cast(@TypeOf(inst.else_deaths), case_deaths[case_deaths.len - 1].items.len) catch return error.OutOfMemory;
220 inst.else_index = total_deaths;
221 inst.else_deaths = else_deaths;
222 total_deaths += else_deaths;
223 }
224
225 const allocated_slice = try arena.alloc(*ir.Inst, total_deaths);
226 inst.deaths = allocated_slice.ptr;
227 for (case_deaths[0 .. case_deaths.len - 1]) |*cd, i| {
228 std.mem.copy(*ir.Inst, inst.caseDeaths(i), cd.items);
229 }
230 std.mem.copy(*ir.Inst, inst.elseDeaths(), case_deaths[case_deaths.len - 1].items);
231 },
147232 else => {},
148233 }
149234
src/zir.zig+20-6
......@@ -2578,9 +2578,15 @@ const EmitZIR = struct {
25782578 var body_tmp = std.ArrayList(*Inst).init(self.allocator);
25792579 defer body_tmp.deinit();
25802580
2581 for (old_inst.cases) |case, i| {
2581 for (old_inst.cases) |*case, i| {
25822582 body_tmp.items.len = 0;
25832583
2584 const case_deaths = try self.arena.allocator.alloc(*Inst, old_inst.caseDeaths(i).len);
2585 for (old_inst.caseDeaths(i)) |death, j| {
2586 case_deaths[j] = try self.resolveInst(new_body, death);
2587 }
2588 try self.body_metadata.put(&cases[i].body, .{ .deaths = case_deaths });
2589
25842590 try self.emitBody(case.body, inst_table, &body_tmp);
25852591 const item = (try self.emitTypedValue(inst.src, .{
25862592 .ty = old_inst.target_ptr.ty.elemType(),
......@@ -2592,12 +2598,20 @@ const EmitZIR = struct {
25922598 .body = .{ .instructions = try self.arena.allocator.dupe(*Inst, body_tmp.items) },
25932599 };
25942600 }
2601 { // else
2602 const else_deaths = try self.arena.allocator.alloc(*Inst, old_inst.elseDeaths().len);
2603 for (old_inst.elseDeaths()) |death, j| {
2604 else_deaths[j] = try self.resolveInst(new_body, death);
2605 }
2606 try self.body_metadata.put(&new_inst.positionals.else_body, .{ .deaths = else_deaths });
2607
2608 body_tmp.items.len = 0;
2609 try self.emitBody(old_inst.else_body, inst_table, &body_tmp);
2610 new_inst.positionals.else_body = .{
2611 .instructions = try self.arena.allocator.dupe(*Inst, body_tmp.items),
2612 };
2613 }
25952614
2596 body_tmp.items.len = 0;
2597 try self.emitBody(old_inst.else_body, inst_table, &body_tmp);
2598 new_inst.positionals.else_body = .{
2599 .instructions = try self.arena.allocator.dupe(*Inst, body_tmp.items),
2600 };
26012615 break :blk &new_inst.base;
26022616 },
26032617 .varptr => @panic("TODO"),