Use GrowableBitSet in the main loop of rustc_mir_transform::sroa - #162623
Conversation
|
Some changes occurred to MIR optimizations cc @rust-lang/wg-mir-opt |
|
rustbot has assigned @hanna-kruppe. Use Why was this reviewer chosen?The reviewer was selected based on:
|
|
This is not perf-motivated, but let's check perf. @bors try @rust-timer queue |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Use GrowableBitSet in the main loop of `rustc_mir_transform::sroa`
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
Finished benchmarking commit (f34c9f4): comparison URL. Overall result: no relevant changes - no action neededBenchmarking means the PR may be perf-sensitive. Consider adding rollup=never if this change is not fit for rolling up. @rustbot label: -S-waiting-on-perf -perf-regression Instruction countThis perf run didn't have relevant results for this metric. Max RSS (memory usage)Results (primary 0.4%, secondary -3.0%)A less reliable metric. May be of interest, but not used to determine the overall result above.
CyclesResults (primary -0.0%)A less reliable metric. May be of interest, but not used to determine the overall result above.
Binary sizeResults (primary -0.0%, secondary -0.1%)A less reliable metric. May be of interest, but not used to determine the overall result above.
Bootstrap: 478.978s -> 477.993s (-0.21%) |
|
Perf came back neutral, so removing the rollup=never. @bors rollup=maybe |
There was a problem hiding this comment.
Some of the things SROA does with these bit sets seem a bit silly to me, but that's pre-existing, and I agree that a growable bit set is more natural for what it is doing. The GrowableBitSet cleanup and size_of reduction are also nice.
r=me with small suggestions
| for (local, replacements) in replacements.fragments.iter_enumerated() { | ||
| ) -> GrowableBitSet<Local> { | ||
| let mut all_dead_locals = GrowableBitSet::new_empty(); | ||
| // Fill the GrowableBitSet in reverse so that it only allocates once. |
There was a problem hiding this comment.
The reason for doing this instead of just starting with GrowableBitSet::with_capacity(num_locals) is to make the early-out (no replacements) case cheaper, right?
(And I guess slightly less work if the largest-numbered local with replacement is much less than num_locals, but if that mattered a lot then ReplacementMap should probably track the maximum.)
Mostly asking to confirm my understanding, but if this is right it might be useful to extend the comment. (And if I got it wrong, the comment should very likely be clarified!)
There was a problem hiding this comment.
To be honest I was mostly thinking of the general case, where the highest-numbered replacement is much less than the number of locals, and felt very clever when I noticed that reverse iteration would always allocate the perfect number of words. 😅
But the no-allocation case is also worth noting, so I've updated the comment.
(All of this is not super important to the intent of the PR; it's just some drive-by mini-optimizations that possibly don't even matter in practice.)
There was a problem hiding this comment.
I wonder if we need to construct the bit set here at all. It seems like we could avoid iterating over the whole map by already building the bit set in compute_flattening as part of ReplacementMap . It even seems possible to carry over the "only allocate enough words for the dead locals" trick over to that function.
But more generally, the pass seems fairly wasteful in its use of bit sets and IndexVecs, creating everything from scratch in every iteration and from the second iteration only focusing on the newly added locals that have the highest indices. Maybe it doesn't matter in practice, but I wonder if there's a more elegant formulation that maintains state across iterations and puts new locals and changed statements into a worklist.
|
|
||
| #[test] | ||
| fn growable_union() { | ||
| // Create two input sets with partly-overlapping values, and different sizes. |
There was a problem hiding this comment.
Optional nit: maybe add an assert that words.len() is indeed different? It's fairly obvious that they'll be different looking at the current implementation, but if that changes (e.g. eagerly initialize more words than strictly needed to reduce frequent tiny memsets) then the test may become less useful than intended.
| self.domain_size = min_domain_size; | ||
| } | ||
|
|
||
| fn ensure(&mut self, min_domain_size: usize) { |
There was a problem hiding this comment.
Since "domain size" isn't a thing any more, I'd suggest:
- Rename the parameter from
min_domain_sizeto something likemin_lenormin_bits - Change the doc comment to talk about "allocated and reserved" as in
ensure_words, rather than "set can hold n elements"
|
This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed. Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers. |
After the separation from `DenseBitSet` and the removal of unused methods, growable bitsets have no need to track an explicit domain size separate from the length of their storage vec.
The bitset entries tracked by this code don't have a naturally fixed domain, so using GrowableBitSet makes more sense than repeatedly resizing a DenseBitSet.
|
r=me once CI is green |
|
PR CI is green. @bors r=hanna-kruppe |
…uwer Rollup of 6 pull requests Successful merges: - #162623 (Use GrowableBitSet in the main loop of `rustc_mir_transform::sroa`) - #162678 (Disconnect `rustc_codegen_ssa` from `rustc_mir_transform`) - #162641 (Remove unused arguments of functions) - #162663 (Rustdoc issue template: fix typo in comment ("thorugh")) - #162684 (Add `E0747` explanation for `type/const` mismatch case) - #162685 (Stabilize `Vec::from_fn`)
…uwer Rollup of 6 pull requests Successful merges: - #162623 (Use GrowableBitSet in the main loop of `rustc_mir_transform::sroa`) - #162678 (Disconnect `rustc_codegen_ssa` from `rustc_mir_transform`) - #162641 (Remove unused arguments of functions) - #162663 (Rustdoc issue template: fix typo in comment ("thorugh")) - #162684 (Add `E0747` explanation for `type/const` mismatch case) - #162685 (Stabilize `Vec::from_fn`)
Rollup merge of #162623 - Zalathar:growable, r=hanna-kruppe Use GrowableBitSet in the main loop of `rustc_mir_transform::sroa` - Follow-up to #161957 --- The first commit is a cleanup based on #161957 (comment) by @panstromek. After having disconnected GrowableBitSet from DenseBitSet and removed unused methods, there is no longer any reason to keep track of a separate `domain_size` in GrowableBitSet. After that, I wanted to get rid of `DenseBitSet::enlarge`, since having it around is not a good fit for the intended purpose of DenseBitSet as a fixed-domain set. After looking more closely at the code in `rustc_mir_transform::sroa` that uses it, I concluded that that code would be better off using GrowableBitSet instead. GrowableBitSet is just as dense, but avoids the need to set a fixed domain size in advance. The changes to SROA require adding `GrowableBitSet::union`, which is easier after having removed `domain_size`. (I am not deeply familiar with the SROA pass, but its usage of bitsets seems fairly straightforward in this case.) There should be no change to compiler output.
Box<[Word]>for word storage inDenseBitSet#161957The first commit is a cleanup based on #161957 (comment) by @panstromek. After having disconnected GrowableBitSet from DenseBitSet and removed unused methods, there is no longer any reason to keep track of a separate
domain_sizein GrowableBitSet.After that, I wanted to get rid of
DenseBitSet::enlarge, since having it around is not a good fit for the intended purpose of DenseBitSet as a fixed-domain set. After looking more closely at the code inrustc_mir_transform::sroathat uses it, I concluded that that code would be better off using GrowableBitSet instead. GrowableBitSet is just as dense, but avoids the need to set a fixed domain size in advance.The changes to SROA require adding
GrowableBitSet::union, which is easier after having removeddomain_size.(I am not deeply familiar with the SROA pass, but its usage of bitsets seems fairly straightforward in this case.)
There should be no change to compiler output.