-
Notifications
You must be signed in to change notification settings - Fork 12.7k
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
iterate_to_fixpoint
-> iterate_reachable_to_fixpoint
#94576
Conversation
* Renames `iterate_to_fixpoint` to `iterate_reachable_to_fixpoint`. * Adds to `framework::Enginge` a new method with the old name (`iterate_to_fixpoint`). The new method computes the fixpoint over all basic blocks, instead of just the reachable ones. * Changes one occurrence of `iterate_to_fixpoint` to `iterate_reachable_to_fixpoint` where the analysis seemed to care about only reachable basic blocks.
(rust-highfive has picked a reviewer for you, use r? to override) |
I'm not sure who is responsible for this code. |
I am taking the liberty of cc-ing @ecstatic-morse, who according to |
I don't think this is desirable. It's always advantageous to prune unreachable basic blocks before running a dataflow analysis. Dataflow is not meaningful for unreachable blocks. We should be pushing users towards that instead of adding more API surface. I'm happy to explain the changes that would be required in the generator transform to make this a reality. |
let mut dirty_queue: WorkQueue<BasicBlock> = | ||
WorkQueue::with_none(self.body.basic_blocks().len()); | ||
|
||
self.body.basic_blocks().indices().for_each(|bb| { | ||
dirty_queue.insert(bb); | ||
}); |
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.
The order in which blocks are added to the work queue is significant. I suspect this will hurt performance. It would be kind of fun to check though, since the basic block numbering is usually fairly close to RPO due to how we build MIR.
Please allow me to add some more context. In my analysis, I am identifying The analysis works beautifully with the new I understand the desire to not introduce additional API surface. But in that case, I feel a workaround ought to exist for folks like me. As best I can tell, if this PR is not merged, then the only alternative I have is to re-implement |
And to do this you're deleting edges in the CFG? You should use |
Yes, using
That won't work because my analysis is backward, and
This gives another way of looking at the problem. "Reachable" here means reachable from the start block. So by computing fixpoints over just "reachable" blocks, If you don't want to introduce additional API surface, then I think another way to fix this problem may be to change how the queue is primed for backward analyses. Essentially, replace this code: rust/compiler/rustc_mir_dataflow/src/framework/engine.rs Lines 214 to 218 in 8b67c5e
with this code: rust/compiler/rustc_mir_dataflow/src/framework/engine.rs Lines 193 to 195 in 8b67c5e
|
This is not a fundamental limitation. It's just a FIXME that no one ever got around to fixing. Unfortunately we don't keep any reverse-lookup data structures for Another way to do what you want is to extend
For better or worse, computer programs execute forwards, so reachability remains an important criterion.
Once again, the initial ordering of basic blocks in the work queue is important. Choosing a good one reduces the number of iterations it takes to reach fixpoint. Can you see why this is the case? That's why the code added unreachable ones at the end prior to #74169. |
Right, but the bottom line is: there are backward analyses that the current framework cannot handle. I have run into one; there are likely to be others. We could address my particular case by implementing Anyway, I feel as though I cannot convince you of my point of view. So, of the two suggestions you proposed, implementing Finally, just to answer your question:
Yes, but I think the order is a red herring. My point was about changing the work queue's contents, not its order. |
…tatic-morse Implement `apply_switch_int_edge_effects` for backward analyses See rust-lang#94576 for some discussion. r? `@ecstatic-morse`
The
rustc_mir_dataflow::framework::Engine
computes a fixpoint over just the reachable basic blocks instead of all of them, and does not offer a way to do the latter. This PR addresses that problem.Specifically, this PR does the following:
iterate_to_fixpoint
toiterate_reachable_to_fixpoint
.framework::Enginge
a new method with the old name (iterate_to_fixpoint
). The new method computes the fixpoint over all basic blocks, instead of just the reachable ones.iterate_to_fixpoint
toiterate_reachable_to_fixpoint
where the analysis seemed to care about only reachable basic blocks.For context, I asked this question in the Rust language forum. Then I noticed that
framework::Results
has bothvisit_with
andvisit_reachable_with
methods.Arguably, the current API is inconsistent (and perhaps even dangerous). Why would someone visit all basic blocks when
iterate_to_fixpoint
computes the fixpoint over just the reachable ones? It seems unlikely that someone would do this intentionally.Currently, there is just one call to
visit_reachable_with
in thecompiler
directory. That one call is related to a use ofMaybeRequiresStorage
. This PR changes its associated call toiterate_to_fixpoint
toiterate_reachable_to_fixpoint
, since that analysis seemed to really want just reachable basic blocks.Presumably, all calls to
visit_with
are either agnostic to whether they visit all or only reachable basic blocks, or really want all basic blocks. This PR effectively changes those calls to use the new method with the old name.