mirror of
https://github.com/ziglang/zig.git
synced 2026-02-13 12:59:04 +00:00
stage2: switch liveness analysis
This commit is contained in:
parent
769d5a9c43
commit
3cc68bd913
@ -144,6 +144,91 @@ fn analyzeInst(
|
||||
// instruction, and the deaths flag for the CondBr instruction will indicate whether the
|
||||
// condition's lifetime ends immediately before entering any branch.
|
||||
},
|
||||
.switchbr => {
|
||||
const inst = base.castTag(.switchbr).?;
|
||||
|
||||
const Table = std.AutoHashMap(*ir.Inst, void);
|
||||
const case_tables = try table.allocator.alloc(Table, inst.cases.len + 1); // +1 for else
|
||||
defer table.allocator.free(case_tables);
|
||||
|
||||
std.mem.set(Table, case_tables, Table.init(table.allocator));
|
||||
defer for (case_tables) |*ct| ct.deinit();
|
||||
|
||||
for (inst.cases) |case, i| {
|
||||
try analyzeWithTable(arena, table, &case_tables[i], case.body);
|
||||
|
||||
// Reset the table back to its state from before the case.
|
||||
var it = case_tables[i].iterator();
|
||||
while (it.next()) |entry| {
|
||||
table.removeAssertDiscard(entry.key);
|
||||
}
|
||||
}
|
||||
{ // else
|
||||
try analyzeWithTable(arena, table, &case_tables[case_tables.len - 1], inst.else_body);
|
||||
|
||||
// Reset the table back to its state from before the case.
|
||||
var it = case_tables[case_tables.len - 1].iterator();
|
||||
while (it.next()) |entry| {
|
||||
table.removeAssertDiscard(entry.key);
|
||||
}
|
||||
}
|
||||
|
||||
const List = std.ArrayList(*ir.Inst);
|
||||
const case_deaths = try table.allocator.alloc(List, case_tables.len); // +1 for else
|
||||
defer table.allocator.free(case_deaths);
|
||||
|
||||
std.mem.set(List, case_deaths, List.init(table.allocator));
|
||||
defer for (case_deaths) |*cd| cd.deinit();
|
||||
|
||||
var total_deaths: u32 = 0;
|
||||
for (case_tables) |*ct, i| {
|
||||
total_deaths += ct.count();
|
||||
var it = ct.iterator();
|
||||
while (it.next()) |entry| {
|
||||
const case_death = entry.key;
|
||||
for (case_tables) |*ct_inner, j| {
|
||||
if (i == j) continue;
|
||||
if (!ct_inner.contains(case_death)) {
|
||||
try case_deaths[i].append(case_death);
|
||||
}
|
||||
}
|
||||
// undo resetting the table
|
||||
_ = try table.put(case_death, {});
|
||||
}
|
||||
}
|
||||
|
||||
// Now we have to correctly populate new_set.
|
||||
if (new_set) |ns| {
|
||||
try ns.ensureCapacity(@intCast(u32, ns.count() + total_deaths));
|
||||
for (case_tables) |*ct| {
|
||||
var it = ct.iterator();
|
||||
while (it.next()) |entry| {
|
||||
_ = ns.putAssumeCapacity(entry.key, {});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
total_deaths = 0;
|
||||
for (case_deaths[0 .. case_deaths.len - 1]) |*ct, i| {
|
||||
inst.cases[i].index = total_deaths;
|
||||
const len = std.math.cast(@TypeOf(inst.else_deaths), ct.items.len) catch return error.OutOfMemory;
|
||||
inst.cases[i].deaths = len;
|
||||
total_deaths += len;
|
||||
}
|
||||
{ // else
|
||||
const else_deaths = std.math.cast(@TypeOf(inst.else_deaths), case_deaths[case_deaths.len - 1].items.len) catch return error.OutOfMemory;
|
||||
inst.else_index = total_deaths;
|
||||
inst.else_deaths = else_deaths;
|
||||
total_deaths += else_deaths;
|
||||
}
|
||||
|
||||
const allocated_slice = try arena.alloc(*ir.Inst, total_deaths);
|
||||
inst.deaths = allocated_slice.ptr;
|
||||
for (case_deaths[0 .. case_deaths.len - 1]) |*cd, i| {
|
||||
std.mem.copy(*ir.Inst, inst.caseDeaths(i), cd.items);
|
||||
}
|
||||
std.mem.copy(*ir.Inst, inst.elseDeaths(), case_deaths[case_deaths.len - 1].items);
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
|
||||
|
||||
26
src/zir.zig
26
src/zir.zig
@ -2578,9 +2578,15 @@ const EmitZIR = struct {
|
||||
var body_tmp = std.ArrayList(*Inst).init(self.allocator);
|
||||
defer body_tmp.deinit();
|
||||
|
||||
for (old_inst.cases) |case, i| {
|
||||
for (old_inst.cases) |*case, i| {
|
||||
body_tmp.items.len = 0;
|
||||
|
||||
const case_deaths = try self.arena.allocator.alloc(*Inst, old_inst.caseDeaths(i).len);
|
||||
for (old_inst.caseDeaths(i)) |death, j| {
|
||||
case_deaths[j] = try self.resolveInst(new_body, death);
|
||||
}
|
||||
try self.body_metadata.put(&cases[i].body, .{ .deaths = case_deaths });
|
||||
|
||||
try self.emitBody(case.body, inst_table, &body_tmp);
|
||||
const item = (try self.emitTypedValue(inst.src, .{
|
||||
.ty = old_inst.target_ptr.ty.elemType(),
|
||||
@ -2592,12 +2598,20 @@ const EmitZIR = struct {
|
||||
.body = .{ .instructions = try self.arena.allocator.dupe(*Inst, body_tmp.items) },
|
||||
};
|
||||
}
|
||||
{ // else
|
||||
const else_deaths = try self.arena.allocator.alloc(*Inst, old_inst.elseDeaths().len);
|
||||
for (old_inst.elseDeaths()) |death, j| {
|
||||
else_deaths[j] = try self.resolveInst(new_body, death);
|
||||
}
|
||||
try self.body_metadata.put(&new_inst.positionals.else_body, .{ .deaths = else_deaths });
|
||||
|
||||
body_tmp.items.len = 0;
|
||||
try self.emitBody(old_inst.else_body, inst_table, &body_tmp);
|
||||
new_inst.positionals.else_body = .{
|
||||
.instructions = try self.arena.allocator.dupe(*Inst, body_tmp.items),
|
||||
};
|
||||
}
|
||||
|
||||
body_tmp.items.len = 0;
|
||||
try self.emitBody(old_inst.else_body, inst_table, &body_tmp);
|
||||
new_inst.positionals.else_body = .{
|
||||
.instructions = try self.arena.allocator.dupe(*Inst, body_tmp.items),
|
||||
};
|
||||
break :blk &new_inst.base;
|
||||
},
|
||||
.varptr => @panic("TODO"),
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user