| ... | ... | @@ -144,6 +144,91 @@ fn analyzeInst( |
| 144 | 144 | // instruction, and the deaths flag for the CondBr instruction will indicate whether the |
| 145 | 145 | // condition's lifetime ends immediately before entering any branch. |
| 146 | 146 | }, |
| 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 | }, |
| 147 | 232 | else => {}, |
| 148 | 233 | } |
| 149 | 234 | |