Skip to content
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

Closed

Conversation

simonvandel
Copy link
Contributor

@simonvandel simonvandel commented Nov 10, 2020

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:

_1 = 4;
_2 = &_1;
_3 = *_2

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.

In the following example _2 is not available in bb2, since we do not know if _2 = &5 is executed.

bb0 {
  _2 = &_1;
  switchInt(_1) -> [4: bb1, otherwise: bb2]
}

bb1 {
  _2 = &5;
}

bb2 {
  _3 = *_2
}

fixes #78368

and use it to implement unneeded deref mir-opt pass
@rust-highfive
Copy link
Collaborator

r? @petrochenkov

(rust_highfive has picked a reviewer for you, use r? to override)

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Nov 10, 2020
@petrochenkov
Copy link
Contributor

@ecstatic-morse is no longer active, so r? @jonas-schievink or @tmiasko, I guess?

@jonas-schievink
Copy link
Contributor

@bors try @rust-timer queue

@rust-timer
Copy link
Collaborator

Awaiting bors try build completion

@bors
Copy link
Contributor

bors commented Nov 10, 2020

⌛ Trying commit 44437da with merge e1fd1a66ec83a1be47f918e7c546d28a13b90012...

@bors
Copy link
Contributor

bors commented Nov 10, 2020

☀️ Try build successful - checks-actions
Build commit: e1fd1a66ec83a1be47f918e7c546d28a13b90012 (e1fd1a66ec83a1be47f918e7c546d28a13b90012)

@rust-timer
Copy link
Collaborator

Queued e1fd1a66ec83a1be47f918e7c546d28a13b90012 with parent cf9cf7c, future comparison URL.

@rust-timer
Copy link
Collaborator

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 rollup- to bors.

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
@rustbot modify labels: +S-waiting-on-review -S-waiting-on-perf

Copy link
Contributor

@jonas-schievink jonas-schievink left a 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
}
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why was this deleted?

Copy link
Contributor Author

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.
Copy link
Contributor

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.

Copy link
Contributor Author

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.

@jonas-schievink
Copy link
Contributor

r? @oli-obk

_args: &[mir::Operand<'tcx>],
_dest_place: mir::Place<'tcx>,
) {
// Conservatively do not try to reason about calls
Copy link
Contributor Author

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

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;
Copy link
Contributor

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.

@oli-obk
Copy link
Contributor

oli-obk commented Nov 13, 2020

@bors try @rust-timer queue

@rust-timer
Copy link
Collaborator

Awaiting bors try build completion

@bors
Copy link
Contributor

bors commented Nov 13, 2020

⌛ Trying commit 78b013c with merge 1baa642e3635e423d55a5980b5a83a02ed883bee...

@bors
Copy link
Contributor

bors commented Nov 13, 2020

☀️ Try build successful - checks-actions
Build commit: 1baa642e3635e423d55a5980b5a83a02ed883bee (1baa642e3635e423d55a5980b5a83a02ed883bee)

@rust-timer
Copy link
Collaborator

Queued 1baa642e3635e423d55a5980b5a83a02ed883bee with parent a38f8fb, future comparison URL.

@rust-timer
Copy link
Collaborator

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 rollup- to bors.

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
@rustbot modify labels: +S-waiting-on-review -S-waiting-on-perf

@oli-obk
Copy link
Contributor

oli-obk commented Nov 13, 2020

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
@simonvandel
Copy link
Contributor Author

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?

@bjorn3
Copy link
Member

bjorn3 commented Nov 15, 2020

@bors try @rust-timer queue

@rust-timer
Copy link
Collaborator

Awaiting bors try build completion

@bors
Copy link
Contributor

bors commented Nov 15, 2020

⌛ Trying commit 7102506 with merge 18df179800c8caf37dfb5354d01f8792a7b34d38...

@bors
Copy link
Contributor

bors commented Nov 15, 2020

☀️ Try build successful - checks-actions
Build commit: 18df179800c8caf37dfb5354d01f8792a7b34d38 (18df179800c8caf37dfb5354d01f8792a7b34d38)

@rust-timer
Copy link
Collaborator

Queued 18df179800c8caf37dfb5354d01f8792a7b34d38 with parent 603ab5b, future comparison URL.

@rust-timer
Copy link
Collaborator

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 rollup- to bors.

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
@rustbot modify labels: +S-waiting-on-review -S-waiting-on-perf

@JohnCSimon JohnCSimon added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Nov 30, 2020
@crlf0710
Copy link
Member

@simonvandel Ping from triage: What's the current status of this? And it has merge conflicts now.

@simonvandel
Copy link
Contributor Author

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.

@simonvandel simonvandel closed this Jan 3, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Avoid backtracking in "deref_of_address" MIR optimization
10 participants