-
Notifications
You must be signed in to change notification settings - Fork 13.3k
[MIR] Add Dominators to MIR and Add Graph Algorithms #34169
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @jroesch (or someone else) soon. If any changes to this PR are deemed necessary, please add them as extra commits. This ensures that the reviewer can see what has changed since they last reviewed the code. Due to the way GitHub handles out-of-date commits, this should also make it reasonably obvious what issues have or haven't been addressed. Large or tricky changes may require several passes of review and changes. Please see the contribution instructions for more information. |
Why is successors’ cache necessary? It is trivial to get up-to-date successors of a block currently. Seems like a super-waste to cache them and whatnot. |
I could imagine that looking back at a slightly out of date CFG could be useful in some situation. But, as |
// option. This file may not be copied, modified, or distributed | ||
// except according to those terms. | ||
|
||
use std::marker::PhantomData; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
probably we can use the bit-set that already exists in librustc_data_structures
? I think I just copied this one out of there...
It seems like caching successors isn't necessary, though I guess we do take advantage of it for de-duplication. But still -- we could easily do that on the fly in the graph iterator code. Given the current setup, you can't really look back on invalidated cache data, right? (Though that could be changed easily enough, if we wanted to let you save a snapshot.) |
cc @rust-lang/compiler |
Sure you can - clone the cache, e.g. |
bf82bc2
to
7cb75b4
Compare
d7ecb15
to
8ed531b
Compare
@arielb1 ok, cool. that's what I was going to suggest. seems like I need to have read your PR more carefully! That's the second point I got slightly off. :) |
pub fn new<'a, 'tcx>(mir: &Mir, cache: &Cache) -> Self { | ||
MirCfg { | ||
predecessors: cache.predecessors(mir).clone(), | ||
successors: calculate_successors(mir), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm; I expected to implement the graph trait directly on Mir
, versus having this intermediate type. Is the idea primarily to have a frozen snapshot for use when computing results, or were there other reasons to introduce MirCfg
?
After working on the implementation and discussing with @nikomatsakis, I/we think it's better to not move the dominators into the cache for now. Knowing the validity of the cache is a bit tricky. In particular, we envision a MIR transformation that only modifies To me, I'd like to land a PR that adds the CFG algorithms and then we can change the caching/invalidation strategy as we create more MIR analysis/transformations (rather than try to come up with the ideal design now). (I'm working on a commit that reflects this now.) |
40dddfd
to
d704a3c
Compare
@@ -144,6 +147,13 @@ impl<'tcx> Mir<'tcx> { | |||
pub fn predecessors_for(&self, bb: BasicBlock) -> Ref<Vec<BasicBlock>> { | |||
Ref::map(self.predecessors(), |p| &p[bb]) | |||
} | |||
|
|||
#[inline] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
An invalidate-on-any-change cache could be nice for preventing duplicate uses between passes.
If you don't want to wait for the world to recompile, you can run compile tests manually by |
☔ The latest upstream changes (presumably #34189) made this pull request unmergeable. Please resolve the merge conflicts. |
bfbcec6
to
03f7a7b
Compare
82c4ae9
to
bb21968
Compare
d7ef4bc
to
66d60c7
Compare
@bors r+ |
📌 Commit 66d60c7 has been approved by |
[MIR] Add Dominators to MIR and Add Graph Algorithms ~~This PR assumes PR #34149 lands.~~ Add generic graph algorithms to rustc_data_structures. Add dominators and successors to the ~~cache (that currently only holds predecessors).~~ `Mir`.
This replaces the previous implementation with the simple variant of Lengauer-Tarjan, which performs better in the general case. Performance on the keccak benchmark is about equivalent between the two, but we don't see regressions (and indeed see improvements) on other benchmarks, even on a partially optimized implementation. The implementation here follows that of the pseudocode in "Linear-Time Algorithms for Dominators and Related Problems" thesis by Loukas Georgiadis. The next few commits will optimize the implementation as suggested in the thesis. Several related works are cited in the comments within the implementation, as well. Implement the simple Lengauer-Tarjan algorithm This replaces the previous implementation (from rust-lang#34169), which has not been optimized since, with the simple variant of Lengauer-Tarjan which performs better in the general case. A previous attempt -- not kept in commit history -- attempted a replacement with a bitset-based implementation, but this led to regressions on perf.rust-lang.org benchmarks and equivalent wins for the keccak benchmark, so was rejected. The implementation here follows that of the pseudocode in "Linear-Time Algorithms for Dominators and Related Problems" thesis by Loukas Georgiadis. The next few commits will optimize the implementation as suggested in the thesis. Several related works are cited in the comments within the implementation, as well. On the keccak benchmark, we were previously spending 15% of our cycles computing the NCA / intersect function; this function is quite expensive, especially on modern CPUs, as it chases pointers on every iteration in a tight loop. With this commit, we spend ~0.05% of our time in dominator computation.
This PR assumes PR #34149 lands.Add generic graph algorithms to rustc_data_structures.
Add dominators and successors to the
cache (that currently only holds predecessors).Mir
.