-
Notifications
You must be signed in to change notification settings - Fork 14k
Description
@nnethercote reports that the liveness computations do a lot of allocations. Indeed, the liveness results are stored in a Vec<IdxSetBuf>:
rust/src/librustc_mir/util/liveness.rs
Line 59 in 2808460
| pub ins: IndexVec<BasicBlock, LocalSet>, |
rust/src/librustc_mir/util/liveness.rs
Line 49 in 2808460
| pub type LocalSet = IdxSetBuf<Local>; |
This means that we will allocate a separate bitset for the ins (and outs!) of each basic block. This is rather inefficient. The other dataflow implementations use a different setup. They have just one big index set which has the bits for every basic block in one allocation. They also avoid allocating both an ins and outs -- since liveness is a reverse analysis, they would basically have only the single outs vector (what is live on exit).
The ins vector is only used during generation of the liveness results here (as well as some assertions and debug printouts later on):
rust/src/librustc_mir/util/liveness.rs
Lines 139 to 144 in 2808460
| // outs[b] = ∪ {ins of successors} | |
| bits.clear(); | |
| for &successor in mir.basic_blocks()[b].terminator().successors() { | |
| bits.union(&ins[successor]); | |
| } | |
| outs[b].clone_from(&bits); |
In fact, you don't really need it there -- instead, when you process a block X, you would compute take outs[X], subtract the kills and add the defs, and then take that resulting bit set and propagate it to each predecessor of X.