| ... | ... | @@ -103,16 +103,8 @@ fn LivenessPassData(comptime pass: LivenessPass) type { |
| 103 | 103 | /// Every `block` currently under analysis. |
| 104 | 104 | block_scopes: std.AutoHashMapUnmanaged(Air.Inst.Index, BlockScope) = .{}, |
| 105 | 105 | |
| 106 | | /// The set of deaths which should be made to occur at the earliest possible point in |
| 107 | | /// this control flow branch. These instructions die when they are last referenced in |
| 108 | | /// the current branch; if unreferenced, they die at the start of the branch. Populated |
| 109 | | /// when a `br` instruction is reached. If deaths are common to all branches of control |
| 110 | | /// flow, they may be bubbled up to the parent branch. |
| 111 | | branch_deaths: std.AutoHashMapUnmanaged(Air.Inst.Index, void) = .{}, |
| 112 | | |
| 113 | | /// The set of instructions currently alive. Instructions which must die in this branch |
| 114 | | /// (i.e. those in `branch_deaths`) are not in this set, because they must die before |
| 115 | | /// this point. |
| 106 | /// The set of instructions currently alive in the current control |
| 107 | /// flow branch. |
| 116 | 108 | live_set: std.AutoHashMapUnmanaged(Air.Inst.Index, void) = .{}, |
| 117 | 109 | |
| 118 | 110 | /// The extra data initialized by the `loop_analysis` pass for this pass to consume. |
| ... | ... | @@ -130,7 +122,6 @@ fn LivenessPassData(comptime pass: LivenessPass) type { |
| 130 | 122 | block.live_set.deinit(gpa); |
| 131 | 123 | } |
| 132 | 124 | self.block_scopes.deinit(gpa); |
| 133 | | self.branch_deaths.deinit(gpa); |
| 134 | 125 | self.live_set.deinit(gpa); |
| 135 | 126 | self.old_extra.deinit(gpa); |
| 136 | 127 | } |
| ... | ... | @@ -172,7 +163,7 @@ pub fn analyze(gpa: Allocator, air: Air) Allocator.Error!Liveness { |
| 172 | 163 | data.old_extra = a.extra; |
| 173 | 164 | a.extra = .{}; |
| 174 | 165 | try analyzeBody(&a, .main_analysis, &data, main_body); |
| 175 | | assert(data.branch_deaths.count() == 0); |
| 166 | assert(data.live_set.count() == 0); |
| 176 | 167 | } |
| 177 | 168 | |
| 178 | 169 | return .{ |
| ... | ... | @@ -870,47 +861,6 @@ fn analyzeBody( |
| 870 | 861 | } |
| 871 | 862 | } |
| 872 | 863 | |
| 873 | | const ControlBranchInfo = struct { |
| 874 | | branch_deaths: std.AutoHashMapUnmanaged(Air.Inst.Index, void) = .{}, |
| 875 | | live_set: std.AutoHashMapUnmanaged(Air.Inst.Index, void) = .{}, |
| 876 | | }; |
| 877 | | |
| 878 | | /// Helper function for running `analyzeBody`, but resetting `branch_deaths` and `live_set` to their |
| 879 | | /// original states before returning, returning the modified versions of them. Only makes sense in |
| 880 | | /// the `main_analysis` pass. |
| 881 | | fn analyzeBodyResetBranch( |
| 882 | | a: *Analysis, |
| 883 | | comptime pass: LivenessPass, |
| 884 | | data: *LivenessPassData(pass), |
| 885 | | body: []const Air.Inst.Index, |
| 886 | | ) !ControlBranchInfo { |
| 887 | | switch (pass) { |
| 888 | | .main_analysis => {}, |
| 889 | | else => @compileError("Liveness.analyzeBodyResetBranch only makes sense in LivenessPass.main_analysis"), |
| 890 | | } |
| 891 | | |
| 892 | | const gpa = a.gpa; |
| 893 | | |
| 894 | | const old_branch_deaths = try data.branch_deaths.clone(a.gpa); |
| 895 | | defer { |
| 896 | | data.branch_deaths.deinit(gpa); |
| 897 | | data.branch_deaths = old_branch_deaths; |
| 898 | | } |
| 899 | | |
| 900 | | const old_live_set = try data.live_set.clone(a.gpa); |
| 901 | | defer { |
| 902 | | data.live_set.deinit(gpa); |
| 903 | | data.live_set = old_live_set; |
| 904 | | } |
| 905 | | |
| 906 | | try analyzeBody(a, pass, data, body); |
| 907 | | |
| 908 | | return .{ |
| 909 | | .branch_deaths = data.branch_deaths.move(), |
| 910 | | .live_set = data.live_set.move(), |
| 911 | | }; |
| 912 | | } |
| 913 | | |
| 914 | 864 | fn analyzeInst( |
| 915 | 865 | a: *Analysis, |
| 916 | 866 | comptime pass: LivenessPass, |
| ... | ... | @@ -1325,17 +1275,13 @@ fn analyzeOperands( |
| 1325 | 1275 | const usize_index = (inst * bpi) / @bitSizeOf(usize); |
| 1326 | 1276 | |
| 1327 | 1277 | // This logic must synchronize with `will_die_immediately` in `AnalyzeBigOperands.init`. |
| 1328 | | var immediate_death = false; |
| 1329 | | if (data.branch_deaths.remove(inst)) { |
| 1330 | | log.debug("[{}] %{}: resolved branch death to birth (immediate death)", .{ pass, inst }); |
| 1331 | | immediate_death = true; |
| 1332 | | assert(!data.live_set.contains(inst)); |
| 1333 | | } else if (data.live_set.remove(inst)) { |
| 1278 | const immediate_death = if (data.live_set.remove(inst)) blk: { |
| 1334 | 1279 | log.debug("[{}] %{}: removed from live set", .{ pass, inst }); |
| 1335 | | } else { |
| 1280 | break :blk false; |
| 1281 | } else blk: { |
| 1336 | 1282 | log.debug("[{}] %{}: immediate death", .{ pass, inst }); |
| 1337 | | immediate_death = true; |
| 1338 | | } |
| 1283 | break :blk true; |
| 1284 | }; |
| 1339 | 1285 | |
| 1340 | 1286 | var tomb_bits: Bpi = @as(Bpi, @boolToInt(immediate_death)) << (bpi - 1); |
| 1341 | 1287 | |
| ... | ... | @@ -1362,9 +1308,6 @@ fn analyzeOperands( |
| 1362 | 1308 | if ((try data.live_set.fetchPut(gpa, operand, {})) == null) { |
| 1363 | 1309 | log.debug("[{}] %{}: added %{} to live set (operand dies here)", .{ pass, inst, operand }); |
| 1364 | 1310 | tomb_bits |= mask; |
| 1365 | | if (data.branch_deaths.remove(operand)) { |
| 1366 | | log.debug("[{}] %{}: resolved branch death of %{} to this usage", .{ pass, inst, operand }); |
| 1367 | | } |
| 1368 | 1311 | } |
| 1369 | 1312 | } |
| 1370 | 1313 | } |
| ... | ... | @@ -1391,17 +1334,6 @@ fn analyzeFuncEnd( |
| 1391 | 1334 | }, |
| 1392 | 1335 | |
| 1393 | 1336 | .main_analysis => { |
| 1394 | | const gpa = a.gpa; |
| 1395 | | |
| 1396 | | // Note that we preserve previous branch deaths - anything that needs to die in our |
| 1397 | | // "parent" branch also needs to die for us. |
| 1398 | | |
| 1399 | | try data.branch_deaths.ensureUnusedCapacity(gpa, data.live_set.count()); |
| 1400 | | var it = data.live_set.keyIterator(); |
| 1401 | | while (it.next()) |key| { |
| 1402 | | const alive = key.*; |
| 1403 | | data.branch_deaths.putAssumeCapacity(alive, {}); |
| 1404 | | } |
| 1405 | 1337 | data.live_set.clearRetainingCapacity(); |
| 1406 | 1338 | }, |
| 1407 | 1339 | } |
| ... | ... | @@ -1427,26 +1359,6 @@ fn analyzeInstBr( |
| 1427 | 1359 | .main_analysis => { |
| 1428 | 1360 | const block_scope = data.block_scopes.get(br.block_inst).?; // we should always be breaking from an enclosing block |
| 1429 | 1361 | |
| 1430 | | // We mostly preserve previous branch deaths - anything that should die for our |
| 1431 | | // enclosing branch should die for us too. However, if our break target requires such an |
| 1432 | | // operand to be alive, it's actually not something we want to kill, since its "last |
| 1433 | | // use" (i.e. the point at which it should die) is outside of our scope. |
| 1434 | | var it = block_scope.live_set.keyIterator(); |
| 1435 | | while (it.next()) |key| { |
| 1436 | | const alive = key.*; |
| 1437 | | _ = data.branch_deaths.remove(alive); |
| 1438 | | } |
| 1439 | | log.debug("[{}] %{}: preserved branch deaths are {}", .{ pass, inst, fmtInstSet(&data.branch_deaths) }); |
| 1440 | | |
| 1441 | | // Anything that's currently alive but our target doesn't need becomes a branch death. |
| 1442 | | it = data.live_set.keyIterator(); |
| 1443 | | while (it.next()) |key| { |
| 1444 | | const alive = key.*; |
| 1445 | | if (!block_scope.live_set.contains(alive)) { |
| 1446 | | _ = try data.branch_deaths.put(gpa, alive, {}); |
| 1447 | | log.debug("[{}] %{}: added branch death of {}", .{ pass, inst, alive }); |
| 1448 | | } |
| 1449 | | } |
| 1450 | 1362 | const new_live_set = try block_scope.live_set.clone(gpa); |
| 1451 | 1363 | data.live_set.deinit(gpa); |
| 1452 | 1364 | data.live_set = new_live_set; |
| ... | ... | @@ -1607,10 +1519,6 @@ fn analyzeInstLoop( |
| 1607 | 1519 | try data.live_set.ensureUnusedCapacity(gpa, @intCast(u32, loop_live.len)); |
| 1608 | 1520 | for (loop_live) |alive| { |
| 1609 | 1521 | data.live_set.putAssumeCapacity(alive, {}); |
| 1610 | | // If the loop requires a branch death operand to be alive, it's not something we |
| 1611 | | // want to kill: its "last use" (i.e. the point at which it should die) is the loop |
| 1612 | | // body itself. |
| 1613 | | _ = data.branch_deaths.remove(alive); |
| 1614 | 1522 | } |
| 1615 | 1523 | |
| 1616 | 1524 | log.debug("[{}] %{}: block live set is {}", .{ pass, inst, fmtInstSet(&data.live_set) }); |
| ... | ... | @@ -1675,61 +1583,19 @@ fn analyzeInstCondBr( |
| 1675 | 1583 | }, |
| 1676 | 1584 | |
| 1677 | 1585 | .main_analysis => { |
| 1678 | | var then_info: ControlBranchInfo = switch (inst_type) { |
| 1679 | | .cond_br => try analyzeBodyResetBranch(a, pass, data, then_body), |
| 1680 | | .@"try", .try_ptr => blk: { |
| 1681 | | var branch_deaths = try data.branch_deaths.clone(gpa); |
| 1682 | | errdefer branch_deaths.deinit(gpa); |
| 1683 | | var live_set = try data.live_set.clone(gpa); |
| 1684 | | errdefer live_set.deinit(gpa); |
| 1685 | | break :blk .{ |
| 1686 | | .branch_deaths = branch_deaths, |
| 1687 | | .live_set = live_set, |
| 1688 | | }; |
| 1689 | | }, |
| 1690 | | }; |
| 1691 | | defer then_info.branch_deaths.deinit(gpa); |
| 1692 | | defer then_info.live_set.deinit(gpa); |
| 1693 | | |
| 1694 | | // If this is a `try`, the "then body" (rest of the branch) might have referenced our |
| 1695 | | // result. If so, we want to avoid this value being considered live while analyzing the |
| 1696 | | // else branch. |
| 1697 | 1586 | switch (inst_type) { |
| 1698 | | .cond_br => {}, |
| 1699 | | .@"try", .try_ptr => _ = data.live_set.remove(inst), |
| 1587 | .cond_br => try analyzeBody(a, pass, data, then_body), |
| 1588 | .@"try", .try_ptr => {}, // The "then body" is just the remainder of this block |
| 1700 | 1589 | } |
| 1590 | var then_live = data.live_set.move(); |
| 1591 | defer then_live.deinit(gpa); |
| 1701 | 1592 | |
| 1702 | 1593 | try analyzeBody(a, pass, data, else_body); |
| 1703 | | var else_info: ControlBranchInfo = .{ |
| 1704 | | .branch_deaths = data.branch_deaths.move(), |
| 1705 | | .live_set = data.live_set.move(), |
| 1706 | | }; |
| 1707 | | defer else_info.branch_deaths.deinit(gpa); |
| 1708 | | defer else_info.live_set.deinit(gpa); |
| 1594 | var else_live = data.live_set.move(); |
| 1595 | defer else_live.deinit(gpa); |
| 1709 | 1596 | |
| 1710 | | // Any queued deaths shared between both branches can be queued for us instead |
| 1711 | | { |
| 1712 | | var it = then_info.branch_deaths.keyIterator(); |
| 1713 | | while (it.next()) |key| { |
| 1714 | | const death = key.*; |
| 1715 | | if (else_info.branch_deaths.remove(death)) { |
| 1716 | | // We'll remove it from then_deaths below |
| 1717 | | try data.branch_deaths.put(gpa, death, {}); |
| 1718 | | } |
| 1719 | | } |
| 1720 | | log.debug("[{}] %{}: bubbled deaths {}", .{ pass, inst, fmtInstSet(&data.branch_deaths) }); |
| 1721 | | it = data.branch_deaths.keyIterator(); |
| 1722 | | while (it.next()) |key| { |
| 1723 | | const death = key.*; |
| 1724 | | assert(then_info.branch_deaths.remove(death)); |
| 1725 | | } |
| 1726 | | } |
| 1727 | | |
| 1728 | | log.debug("[{}] %{}: remaining 'then' branch deaths are {}", .{ pass, inst, fmtInstSet(&then_info.branch_deaths) }); |
| 1729 | | log.debug("[{}] %{}: remaining 'else' branch deaths are {}", .{ pass, inst, fmtInstSet(&else_info.branch_deaths) }); |
| 1730 | | |
| 1731 | | // Deaths that occur in one branch but not another need to be made to occur at the start |
| 1732 | | // of the other branch. |
| 1597 | // Operands which are alive in one branch but not the other need to die at the start of |
| 1598 | // the peer branch. |
| 1733 | 1599 | |
| 1734 | 1600 | var then_mirrored_deaths: std.ArrayListUnmanaged(Air.Inst.Index) = .{}; |
| 1735 | 1601 | defer then_mirrored_deaths.deinit(gpa); |
| ... | ... | @@ -1737,14 +1603,12 @@ fn analyzeInstCondBr( |
| 1737 | 1603 | var else_mirrored_deaths: std.ArrayListUnmanaged(Air.Inst.Index) = .{}; |
| 1738 | 1604 | defer else_mirrored_deaths.deinit(gpa); |
| 1739 | 1605 | |
| 1740 | | // Note: this invalidates `else_info.live_set`, but expands `then_info.live_set` to |
| 1741 | | // be their union |
| 1606 | // Note: this invalidates `else_live`, but expands `then_live` to be their union |
| 1742 | 1607 | { |
| 1743 | | var it = then_info.live_set.keyIterator(); |
| 1608 | var it = then_live.keyIterator(); |
| 1744 | 1609 | while (it.next()) |key| { |
| 1745 | 1610 | const death = key.*; |
| 1746 | | if (else_info.live_set.remove(death)) continue; // removing makes the loop below faster |
| 1747 | | if (else_info.branch_deaths.contains(death)) continue; |
| 1611 | if (else_live.remove(death)) continue; // removing makes the loop below faster |
| 1748 | 1612 | |
| 1749 | 1613 | // If this is a `try`, the "then body" (rest of the branch) might have |
| 1750 | 1614 | // referenced our result. We want to avoid killing this value in the else branch |
| ... | ... | @@ -1756,16 +1620,14 @@ fn analyzeInstCondBr( |
| 1756 | 1620 | |
| 1757 | 1621 | try else_mirrored_deaths.append(gpa, death); |
| 1758 | 1622 | } |
| 1759 | | // Since we removed common stuff above, `else_info.live_set` is now only operands |
| 1623 | // Since we removed common stuff above, `else_live` is now only operands |
| 1760 | 1624 | // which are *only* alive in the else branch |
| 1761 | | it = else_info.live_set.keyIterator(); |
| 1625 | it = else_live.keyIterator(); |
| 1762 | 1626 | while (it.next()) |key| { |
| 1763 | 1627 | const death = key.*; |
| 1764 | | if (!then_info.branch_deaths.contains(death)) { |
| 1765 | | try then_mirrored_deaths.append(gpa, death); |
| 1766 | | } |
| 1767 | | // Make `then_info.live_set` contain the full live set (i.e. union of both) |
| 1768 | | try then_info.live_set.put(gpa, death, {}); |
| 1628 | try then_mirrored_deaths.append(gpa, death); |
| 1629 | // Make `then_live` contain the full live set (i.e. union of both) |
| 1630 | try then_live.put(gpa, death, {}); |
| 1769 | 1631 | } |
| 1770 | 1632 | } |
| 1771 | 1633 | |
| ... | ... | @@ -1773,29 +1635,20 @@ fn analyzeInstCondBr( |
| 1773 | 1635 | log.debug("[{}] %{}: 'else' branch mirrored deaths are {}", .{ pass, inst, fmtInstList(else_mirrored_deaths.items) }); |
| 1774 | 1636 | |
| 1775 | 1637 | data.live_set.deinit(gpa); |
| 1776 | | data.live_set = then_info.live_set.move(); |
| 1638 | data.live_set = then_live.move(); // Really the union of both live sets |
| 1777 | 1639 | |
| 1778 | 1640 | log.debug("[{}] %{}: new live set is {}", .{ pass, inst, fmtInstSet(&data.live_set) }); |
| 1779 | 1641 | |
| 1780 | | // Write the branch deaths to `extra` |
| 1781 | | const then_death_count = then_info.branch_deaths.count() + @intCast(u32, then_mirrored_deaths.items.len); |
| 1782 | | const else_death_count = else_info.branch_deaths.count() + @intCast(u32, else_mirrored_deaths.items.len); |
| 1783 | | |
| 1642 | // Write the mirrored deaths to `extra` |
| 1643 | const then_death_count = @intCast(u32, then_mirrored_deaths.items.len); |
| 1644 | const else_death_count = @intCast(u32, else_mirrored_deaths.items.len); |
| 1784 | 1645 | try a.extra.ensureUnusedCapacity(gpa, std.meta.fields(CondBr).len + then_death_count + else_death_count); |
| 1785 | 1646 | const extra_index = a.addExtraAssumeCapacity(CondBr{ |
| 1786 | 1647 | .then_death_count = then_death_count, |
| 1787 | 1648 | .else_death_count = else_death_count, |
| 1788 | 1649 | }); |
| 1789 | 1650 | a.extra.appendSliceAssumeCapacity(then_mirrored_deaths.items); |
| 1790 | | { |
| 1791 | | var it = then_info.branch_deaths.keyIterator(); |
| 1792 | | while (it.next()) |key| a.extra.appendAssumeCapacity(key.*); |
| 1793 | | } |
| 1794 | 1651 | a.extra.appendSliceAssumeCapacity(else_mirrored_deaths.items); |
| 1795 | | { |
| 1796 | | var it = else_info.branch_deaths.keyIterator(); |
| 1797 | | while (it.next()) |key| a.extra.appendAssumeCapacity(key.*); |
| 1798 | | } |
| 1799 | 1652 | try a.special.put(gpa, inst, extra_index); |
| 1800 | 1653 | }, |
| 1801 | 1654 | } |
| ... | ... | @@ -1838,61 +1691,24 @@ fn analyzeInstSwitchBr( |
| 1838 | 1691 | const DeathSet = std.AutoHashMapUnmanaged(Air.Inst.Index, void); |
| 1839 | 1692 | const DeathList = std.ArrayListUnmanaged(Air.Inst.Index); |
| 1840 | 1693 | |
| 1841 | | var case_infos = try gpa.alloc(ControlBranchInfo, ncases + 1); // +1 for else |
| 1842 | | defer gpa.free(case_infos); |
| 1694 | var case_live_sets = try gpa.alloc(std.AutoHashMapUnmanaged(Air.Inst.Index, void), ncases + 1); // +1 for else |
| 1695 | defer gpa.free(case_live_sets); |
| 1843 | 1696 | |
| 1844 | | @memset(case_infos, .{}); |
| 1845 | | defer for (case_infos) |*info| { |
| 1846 | | info.branch_deaths.deinit(gpa); |
| 1847 | | info.live_set.deinit(gpa); |
| 1848 | | }; |
| 1697 | @memset(case_live_sets, .{}); |
| 1698 | defer for (case_live_sets) |*live_set| live_set.deinit(gpa); |
| 1849 | 1699 | |
| 1850 | 1700 | var air_extra_index: usize = switch_br.end; |
| 1851 | | for (case_infos[0..ncases]) |*info| { |
| 1701 | for (case_live_sets[0..ncases]) |*live_set| { |
| 1852 | 1702 | const case = a.air.extraData(Air.SwitchBr.Case, air_extra_index); |
| 1853 | 1703 | const case_body = a.air.extra[case.end + case.data.items_len ..][0..case.data.body_len]; |
| 1854 | 1704 | air_extra_index = case.end + case.data.items_len + case_body.len; |
| 1855 | | info.* = try analyzeBodyResetBranch(a, pass, data, case_body); |
| 1705 | try analyzeBody(a, pass, data, case_body); |
| 1706 | live_set.* = data.live_set.move(); |
| 1856 | 1707 | } |
| 1857 | 1708 | { // else |
| 1858 | 1709 | const else_body = a.air.extra[air_extra_index..][0..switch_br.data.else_body_len]; |
| 1859 | 1710 | try analyzeBody(a, pass, data, else_body); |
| 1860 | | case_infos[ncases] = .{ |
| 1861 | | .branch_deaths = data.branch_deaths.move(), |
| 1862 | | .live_set = data.live_set.move(), |
| 1863 | | }; |
| 1864 | | } |
| 1865 | | |
| 1866 | | // Queued deaths common to all cases can be bubbled up |
| 1867 | | { |
| 1868 | | // We can't remove from the set we're iterating over, so we'll store the shared deaths here |
| 1869 | | // temporarily to remove them |
| 1870 | | var shared_deaths: DeathSet = .{}; |
| 1871 | | defer shared_deaths.deinit(gpa); |
| 1872 | | |
| 1873 | | var it = case_infos[0].branch_deaths.keyIterator(); |
| 1874 | | while (it.next()) |key| { |
| 1875 | | const death = key.*; |
| 1876 | | for (case_infos[1..]) |*info| { |
| 1877 | | if (!info.branch_deaths.contains(death)) break; |
| 1878 | | } else try shared_deaths.put(gpa, death, {}); |
| 1879 | | } |
| 1880 | | |
| 1881 | | log.debug("[{}] %{}: bubbled deaths {}", .{ pass, inst, fmtInstSet(&shared_deaths) }); |
| 1882 | | |
| 1883 | | try data.branch_deaths.ensureUnusedCapacity(gpa, shared_deaths.count()); |
| 1884 | | it = shared_deaths.keyIterator(); |
| 1885 | | while (it.next()) |key| { |
| 1886 | | const death = key.*; |
| 1887 | | data.branch_deaths.putAssumeCapacity(death, {}); |
| 1888 | | for (case_infos) |*info| { |
| 1889 | | _ = info.branch_deaths.remove(death); |
| 1890 | | } |
| 1891 | | } |
| 1892 | | |
| 1893 | | for (case_infos, 0..) |*info, i| { |
| 1894 | | log.debug("[{}] %{}: case {} remaining branch deaths are {}", .{ pass, inst, i, fmtInstSet(&info.branch_deaths) }); |
| 1895 | | } |
| 1711 | case_live_sets[ncases] = data.live_set.move(); |
| 1896 | 1712 | } |
| 1897 | 1713 | |
| 1898 | 1714 | const mirrored_deaths = try gpa.alloc(DeathList, ncases + 1); |
| ... | ... | @@ -1905,20 +1721,20 @@ fn analyzeInstSwitchBr( |
| 1905 | 1721 | var all_alive: DeathSet = .{}; |
| 1906 | 1722 | defer all_alive.deinit(gpa); |
| 1907 | 1723 | |
| 1908 | | for (case_infos) |*info| { |
| 1909 | | try all_alive.ensureUnusedCapacity(gpa, info.live_set.count()); |
| 1910 | | var it = info.live_set.keyIterator(); |
| 1724 | for (case_live_sets) |*live_set| { |
| 1725 | try all_alive.ensureUnusedCapacity(gpa, live_set.count()); |
| 1726 | var it = live_set.keyIterator(); |
| 1911 | 1727 | while (it.next()) |key| { |
| 1912 | 1728 | const alive = key.*; |
| 1913 | 1729 | all_alive.putAssumeCapacity(alive, {}); |
| 1914 | 1730 | } |
| 1915 | 1731 | } |
| 1916 | 1732 | |
| 1917 | | for (mirrored_deaths, case_infos) |*mirrored, *info| { |
| 1733 | for (mirrored_deaths, case_live_sets) |*mirrored, *live_set| { |
| 1918 | 1734 | var it = all_alive.keyIterator(); |
| 1919 | 1735 | while (it.next()) |key| { |
| 1920 | 1736 | const alive = key.*; |
| 1921 | | if (!info.live_set.contains(alive) and !info.branch_deaths.contains(alive)) { |
| 1737 | if (!live_set.contains(alive)) { |
| 1922 | 1738 | // Should die at the start of this branch |
| 1923 | 1739 | try mirrored.append(gpa, alive); |
| 1924 | 1740 | } |
| ... | ... | @@ -1935,27 +1751,18 @@ fn analyzeInstSwitchBr( |
| 1935 | 1751 | log.debug("[{}] %{}: new live set is {}", .{ pass, inst, fmtInstSet(&data.live_set) }); |
| 1936 | 1752 | } |
| 1937 | 1753 | |
| 1938 | | const else_death_count = case_infos[ncases].branch_deaths.count() + @intCast(u32, mirrored_deaths[ncases].items.len); |
| 1939 | | |
| 1754 | const else_death_count = @intCast(u32, mirrored_deaths[ncases].items.len); |
| 1940 | 1755 | const extra_index = try a.addExtra(SwitchBr{ |
| 1941 | 1756 | .else_death_count = else_death_count, |
| 1942 | 1757 | }); |
| 1943 | | for (mirrored_deaths[0..ncases], case_infos[0..ncases]) |mirrored, info| { |
| 1944 | | const num = info.branch_deaths.count() + @intCast(u32, mirrored.items.len); |
| 1758 | for (mirrored_deaths[0..ncases]) |mirrored| { |
| 1759 | const num = @intCast(u32, mirrored.items.len); |
| 1945 | 1760 | try a.extra.ensureUnusedCapacity(gpa, num + 1); |
| 1946 | 1761 | a.extra.appendAssumeCapacity(num); |
| 1947 | 1762 | a.extra.appendSliceAssumeCapacity(mirrored.items); |
| 1948 | | { |
| 1949 | | var it = info.branch_deaths.keyIterator(); |
| 1950 | | while (it.next()) |key| a.extra.appendAssumeCapacity(key.*); |
| 1951 | | } |
| 1952 | 1763 | } |
| 1953 | 1764 | try a.extra.ensureUnusedCapacity(gpa, else_death_count); |
| 1954 | 1765 | a.extra.appendSliceAssumeCapacity(mirrored_deaths[ncases].items); |
| 1955 | | { |
| 1956 | | var it = case_infos[ncases].branch_deaths.keyIterator(); |
| 1957 | | while (it.next()) |key| a.extra.appendAssumeCapacity(key.*); |
| 1958 | | } |
| 1959 | 1766 | try a.special.put(gpa, inst, extra_index); |
| 1960 | 1767 | }, |
| 1961 | 1768 | } |
| ... | ... | @@ -1997,7 +1804,7 @@ fn AnalyzeBigOperands(comptime pass: LivenessPass) type { |
| 1997 | 1804 | |
| 1998 | 1805 | const will_die_immediately: bool = switch (pass) { |
| 1999 | 1806 | .loop_analysis => false, // track everything, since we don't have full liveness information yet |
| 2000 | | .main_analysis => data.branch_deaths.contains(inst) and !data.live_set.contains(inst), |
| 1807 | .main_analysis => !data.live_set.contains(inst), |
| 2001 | 1808 | }; |
| 2002 | 1809 | |
| 2003 | 1810 | return .{ |
| ... | ... | @@ -2048,9 +1855,6 @@ fn AnalyzeBigOperands(comptime pass: LivenessPass) type { |
| 2048 | 1855 | if ((try big.data.live_set.fetchPut(gpa, operand, {})) == null) { |
| 2049 | 1856 | log.debug("[{}] %{}: added %{} to live set (operand dies here)", .{ pass, big.inst, operand }); |
| 2050 | 1857 | big.extra_tombs[extra_byte] |= @as(u32, 1) << extra_bit; |
| 2051 | | if (big.data.branch_deaths.remove(operand)) { |
| 2052 | | log.debug("[{}] %{}: resolved branch death of %{} to this usage", .{ pass, big.inst, operand }); |
| 2053 | | } |
| 2054 | 1858 | } |
| 2055 | 1859 | }, |
| 2056 | 1860 | } |