-
Notifications
You must be signed in to change notification settings - Fork 13.2k
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
Introduce new dataflow implementation for available locals, use in existing pass #78928
Introduce new dataflow implementation for available locals, use in existing pass #78928
Conversation
and use it to implement unneeded deref mir-opt pass
(rust_highfive has picked a reviewer for you, use r? to override) |
@ecstatic-morse is no longer active, so r? @jonas-schievink or @tmiasko, I guess? |
@bors try @rust-timer queue |
Awaiting bors try build completion |
⌛ Trying commit 44437da with merge e1fd1a66ec83a1be47f918e7c546d28a13b90012... |
☀️ Try build successful - checks-actions |
Queued e1fd1a66ec83a1be47f918e7c546d28a13b90012 with parent cf9cf7c, future comparison URL. |
Finished benchmarking try commit (e1fd1a66ec83a1be47f918e7c546d28a13b90012): comparison url. Benchmarking this pull request likely means that it is perf-sensitive, so we're automatically marking it as not fit for rolling up. Please note that if the perf results are neutral, you should likely undo the rollup=never given below by specifying Importantly, though, if the results of this run are non-neutral do not roll this PR up -- it will mask other regressions or improvements in the roll up. @bors rollup=never |
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.
Unfortunately I don't really have the capacity to do a full review here, so r? @oli-obk
resume; // scope 0 at /the/src/instrument_coverage.rs:10:1: 16:2 | ||
} | ||
} | ||
|
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.
Why was this deleted?
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.
I renamed a test, but since bless does not cleanup already created diffs I ran a script myself to delete all diff files, and then ran bless again. Since ci passes, this file is not used in any test afaict.
/// In the above example, `_2` is available at the third statement, so the statement can be | ||
/// simplified to `_3 = _1`. | ||
/// In general, an available local can be used freely on any path from the definition of `_2` to | ||
/// statement `s`, if `_2` and its value is guaranteed to not be changed on all paths. |
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.
What's the difference between this and reaching definitions? It doesn't really seem like the best idea to introduce an ad-hoc analysis for a single minor optimization instead of using a well-known analysis that may have other uses in the future.
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.
I may be a bit off on the terminology here. What I implemented sounds like reaching definitions, yeah. Did I miss an implementation already in rustc?
"available expression analysis" is often the term I see used in compiler theory, which refers to an analysis that can answer if an expression can be reused at a point since it is not modified along the way from its definition.
I named the pass I implemented "available locals" since it tracks locals, not expressions. But I could probably more precisely name it reaching definitions.
I agree that a new dataflow analysis solely for this one optimization is a bit overkill, but I think the analysis in general can be applied in a lot of coming or existing passes.
r? @oli-obk |
_args: &[mir::Operand<'tcx>], | ||
_dest_place: mir::Place<'tcx>, | ||
) { | ||
// Conservatively do not try to reason about calls |
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.
We should take care here to invalidate operands that move locals, i'll fix this in a commit
…ive so do it as late as possible
If we need them, they will be added in the visitor that goes through assigns
It actually had no gain on my benchmark, but LLVM did decide to inline it when it now can
@@ -129,7 +131,7 @@ impl<'a, 'tcx> ResultsVisitor<'a, 'tcx> for UnneededDerefVisitor<'a, 'tcx> { | |||
stmt: &'mir Statement<'tcx>, | |||
location: Location, | |||
) { | |||
self.state = Some(state.clone()); | |||
self.state = state; |
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.
There's no need to use self
for the visit_rvalue
. You could also create a separate visitor that has a reference to Self
as a field and thus can have a reference with a lifetime in the state
field. If performance is the same, then I would definitely prefer that.
@bors try @rust-timer queue |
Awaiting bors try build completion |
⌛ Trying commit 78b013c with merge 1baa642e3635e423d55a5980b5a83a02ed883bee... |
☀️ Try build successful - checks-actions |
Queued 1baa642e3635e423d55a5980b5a83a02ed883bee with parent a38f8fb, future comparison URL. |
Finished benchmarking try commit (1baa642e3635e423d55a5980b5a83a02ed883bee): comparison url. Benchmarking this pull request likely means that it is perf-sensitive, so we're automatically marking it as not fit for rolling up. Please note that if the perf results are neutral, you should likely undo the rollup=never given below by specifying Importantly, though, if the results of this run are non-neutral do not roll this PR up -- it will mask other regressions or improvements in the roll up. @bors rollup=never |
The regressions are now mostly gone, but so are the improvements |
It's only important that the place referenced and the local we store it in is available at the time we try to apply the deref optimization
I'm a bit about of ideas for further things that can be done to improve the performance of the analysis. Can i get a perf run for the latest changes? |
@bors try @rust-timer queue |
Awaiting bors try build completion |
⌛ Trying commit 7102506 with merge 18df179800c8caf37dfb5354d01f8792a7b34d38... |
☀️ Try build successful - checks-actions |
Queued 18df179800c8caf37dfb5354d01f8792a7b34d38 with parent 603ab5b, future comparison URL. |
Finished benchmarking try commit (18df179800c8caf37dfb5354d01f8792a7b34d38): comparison url. Benchmarking this pull request likely means that it is perf-sensitive, so we're automatically marking it as not fit for rolling up. Please note that if the perf results are neutral, you should likely undo the rollup=never given below by specifying Importantly, though, if the results of this run are non-neutral do not roll this PR up -- it will mask other regressions or improvements in the roll up. @bors rollup=never |
@simonvandel Ping from triage: What's the current status of this? And it has merge conflicts now. |
I'll close the PR. The current implementation has some performance problems which is not obvious to me how to resolve. If MIR ever becomes SSA that will greatly simplify the implementation. If MIR gets optimized better in the future, it might then make sense to revive the PR, so it has less code to churn through. |
This PR introduces an availablity dataflow analysis for locals, and uses it to reimplement (hopefully soundly) an existing pass that removes unneeded derefs.
The availability analysis should be pretty generic so can be used in further passes where the question "can i freely use this local here?" arises.
It's my first contribution using the dataflow framework, so i'm curious how my implementation can be improved.
Availability analysis
A local is available at a given program point, if the value of the local can freely be used at the given program point.
Consider the following example:
In the above example,
_2
is available at the third statement, so the statement can be simplified to_3 = _1
.In general, an available local can be used freely on any path from the definition of
_2
to statements
, if_2
and its value is guaranteed to not be changed on all paths.In the following example
_2
is not available inbb2
, since we do not know if_2 = &5
is executed.fixes #78368