Rewrite `precompute_borrows_out_of_scope` for fewer hash table lookups.
It now does one hash table lookup per basic block, instead of one per
statement. This is worthwhile because this function is hot for NLL
builds of `ucd`.
I haven't measured the effect of this yet because I'm having trouble doing optimized builds of rustc that are suitable for profiling (#53916). I will do an online perf run instead.
r? @nikomatsakis
It now does one hash table lookup per basic block, instead of one per
statement. This is worthwhile because this function is hot for NLL
builds of `ucd`.
`BitSlice` fixes
`propagate_bits_into_entry_set_for` and `BitSlice::bitwise` are hot for some benchmarks under NLL. I tried and failed to speed them up. (Increasing the size of `bit_slice::Word` from `usize` to `u128` caused a slowdown, even though decreasing the size of `bitvec::Word` from `u128` to `u64` also caused a slowdown. Weird.)
Anyway, along the way I fixed up several problems in and around the `BitSlice` code.
r? @nikomatsakis
The strategy is this:
- we compute SCCs once all outlives constraints are known
- we allocate a set of values **per region** for storing liveness
- we allocate a set of values **per SCC** for storing the final values
- when we add a liveness constraint to the region R, we also add it
to the final value of the SCC to which R belongs
- then we can apply the constraints by just walking the DAG for the
SCCs and union'ing the children (which have their liveness
constraints within)
There are a few intermediate refactorings that I really ought to have
broken out into their own commits:
- reverse the constraint graph so that `R1: R2` means `R1 -> R2` and
not `R2 -> R1`. This fits better with the SCC computation and new
style of inference (`->` now means "take value from" and not "push
value into")
- this does affect some of the UI tests, since they traverse the
graph, but mostly the artificial ones and they don't necessarily
seem worse
- put some things (constraint set, etc) into `Rc`. This lets us root
them to permit mutation and iteration. It also guarantees they don't
change, which is critical to the correctness of the algorithm.
- Generalize various helpers that previously operated only on points
to work on any sort of region element.
Currently `Word` is `usize`, and there are various places in the code
that assume this.
This patch mostly just changes `usize` occurrences to `Word`. Most of
the changes were found as compile errors when I changed `Word` to a type
other than `usize`, but there was one non-obvious case in
librustc_mir/dataflow/mod.rs that caused bounds check failures before I
fixed it.
(This is just the data structure changes and some boilerplate match
code that followed from it; the actual emission of these statements
comes in a follow-up commit.)
See #48431 for discussion as to why this was necessary and what we hoped to
accomplish. A brief summary:
- the first implementation of 2-phase borrows was hard to limit in the way we
wanted. That is, it was too good at accepting all 2-phase borrows rather than
just autorefs =)
- Numerous diagnostic regressions were introduced by 2-phase borrow support
which were difficult to fix
[NLL] Add false edges out of infinite loops
Resolves#46036 by adding a `cleanup` member to the `FalseEdges` terminator kind. There's also a small doc fix to one of the other comments in `into.rs` which I can pull out in to another PR if desired =)
This PR should pass CI but the test suite has been relatively unstable on my system so I'm not 100% sure.
r? @nikomatsakis
Sometimes a simple goto misses the cleanup/unwind edges. Specifically, in the
case of infinite loops such as those introduced by a loop statement without any
other out edges. Analogous to TerminatorKind::FalseEdges; this new terminator
kind is used when we want borrowck to consider an unwind path, but real control
flow should never actually take it.