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

Fix the unsoundness in the early_otherwise_branch mir opt pass #91840

Merged
merged 2 commits into from
Jan 26, 2022

Conversation

JakobDegen
Copy link
Contributor

Closes #78496 .

This change is a significant rewrite of much of the pass. Exactly what it does is documented in the source file (with ascii art!), and all the changes that are made to the MIR that are not trivially sound are carefully documented. That being said, this is my first time touching MIR, so there are probably some invariants I did not know about that I broke.

This version of the optimization is also somewhat more flexible than the original; for example, we do not care how or where the value on which the parent is switching is computed. There is no requirement that any types be the same. This could be made even more flexible in the future by allowing a wider range of statements in the bodies of BBC, BBD (as long as they are all the same of course). This should be a good first step though.

Probably needs a perf run.

r? @oli-obk who reviewed things the last time this was touched

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Dec 12, 2021
Comment on lines +242 to +244
// - In `BB9`: Not possible since control flow might have reached `BB9` via the
// `otherwise` branch in `BBC, BBD` in the input to our transformation, which would
// have invalidated the data when computing `discriminant(P)`
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 realize now that depending on the MIR semantics, this may be incorrect. In particular, we can imagine BB9 doing something like this:

if Q == otherwise {
    use reference invalidated by P
}

This would have been correct before this pass, since P is only computed if Q does not take the otherwise branch; it's obviously no longer correct after the pass. That being said, this kind of a pattern can't ever pass borrowck (since borrowck will not consider that the conditions in the branch in BB1 and BB9 are the same). Is this a legal transformation for other optimizations to make? Or must the validity of all references (whenever they're used) in the MIR always follow only from the control flow? (hopefully I explained myself accurately there)

Copy link
Contributor

Choose a reason for hiding this comment

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

Great explanation, thanks. Unfortunately I don't have a good answer. MIR semantics are very underdocumented. As far as I know there is no opt that could cause such a pattern right now, but I'm wondering if we could write it with raw pointers and intrinsics

@camelid camelid added the T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. label Dec 13, 2021
@oli-obk
Copy link
Contributor

oli-obk commented Dec 13, 2021

Will review some time this week

@bors try @rust-timer queue

@rust-timer
Copy link
Collaborator

Awaiting bors try build completion.

@rustbot label: +S-waiting-on-perf

@rustbot rustbot added the S-waiting-on-perf Status: Waiting on a perf run to be completed. label Dec 13, 2021
@bors
Copy link
Contributor

bors commented Dec 13, 2021

⌛ Trying commit 396d8c60dbd6cb21d2176ac43f9f542c37fc404b with merge 236e8f85e050e93c72957ee20322d47010a24084...

@bors
Copy link
Contributor

bors commented Dec 13, 2021

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

@rust-timer
Copy link
Collaborator

Queued 236e8f85e050e93c72957ee20322d47010a24084 with parent f7fd79a, future comparison URL.

@rust-timer
Copy link
Collaborator

Finished benchmarking commit (236e8f85e050e93c72957ee20322d47010a24084): comparison url.

Summary: This change led to very large relevant regressions 😿 in compiler performance.

  • Very large regression in instruction counts (up to 6.3% on incr-unchanged builds of inflate)

If you disagree with this performance assessment, please file an issue in rust-lang/rustc-perf.

Benchmarking this pull request likely means that it is perf-sensitive, so we're automatically marking it as not fit for rolling up. While you can manually mark this PR as fit for rollup, we strongly recommend not doing so since this PR led to changes in compiler perf.

Next Steps: If you can justify the regressions found in this try perf run, please indicate this with @rustbot label: +perf-regression-triaged along with sufficient written justification. If you cannot justify the regressions please fix the regressions and do another perf run. If the next run shows neutral or positive results, the label will be automatically removed.

@bors rollup=never
@rustbot label: +S-waiting-on-review -S-waiting-on-perf +perf-regression

@rustbot rustbot added perf-regression Performance regression. and removed S-waiting-on-perf Status: Waiting on a perf run to be completed. labels Dec 13, 2021
@JakobDegen
Copy link
Contributor Author

JakobDegen commented Dec 13, 2021

After asking on zulip that particular one might be noise, but the rest still don't look like they're getting us anything. Will take a look later

@JakobDegen JakobDegen marked this pull request as draft December 14, 2021 03:20
@JakobDegen
Copy link
Contributor Author

This is causing issues with incremental and there are other things I want to look at too before this gets merged. I can close and re-open instead if that's preferable

This optimization pass previously made excessive assumptions as to the nature of
the blocks being optimized. We remove those assumptions and make sure to
rigorously justify all changes that are made to the MIR. Details can be found
in the file.
@JakobDegen
Copy link
Contributor Author

JakobDegen commented Dec 14, 2021

I've dropped the MIR-opt-level requirement to 2 so that this actually runs. Also fixed an ICE and made a couple of other adjustments. I think things should be ready for review.

I also did local perf runs of this and it was a flat zero across the board, so I'm not expecting this to bring many benefits. Having the opt be sound should be a good step forward regardless though.

@JakobDegen JakobDegen marked this pull request as ready for review December 14, 2021 11:29
@JakobDegen
Copy link
Contributor Author

Realize I forgot to comment on this: There had been a suggestion on the original version of this pass to do a BitAnd, thereby avoiding the extra branch and bb, but that's unfortunately not correct if 0 is one of the values that gets switched on. I could special case in a check for that, but I'm not sure the complexity is warranted.

@oli-obk
Copy link
Contributor

oli-obk commented Dec 15, 2021

I also did local perf runs of this and it was a flat zero across the board, so I'm not expecting this to bring many benefits. Having the opt be sound should be a good step forward regardless though.

Indeed, I just wanted to make sure we don't regress anything. I also agree with the "spurious noise" assessment on the one regression

@JakobDegen
Copy link
Contributor Author

@oli-obk will you get a chance to review this, or is there someone else I should ask? If there's no review capacity right now, I can close this until there is if that's preferable

@oli-obk
Copy link
Contributor

oli-obk commented Dec 27, 2021

Sorry, didn't get to this properly before Christmas. I'll get back to reviewing complex things like this mid January

@camelid
Copy link
Member

camelid commented Jan 25, 2022

triage: friendly ping @oli-obk :)

@oli-obk
Copy link
Contributor

oli-obk commented Jan 26, 2022

Hmm I reviewed this before but obviously never wrote any conclusions. Well, third time's the charm. The opt is really well documented and structured and I feel confident it actually catches all the cases where it shouldn't run.

@bors r+ rollup=never

@bors
Copy link
Contributor

bors commented Jan 26, 2022

📌 Commit c0c13b7 has been approved by oli-obk

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jan 26, 2022
@bors
Copy link
Contributor

bors commented Jan 26, 2022

⌛ Testing commit c0c13b7 with merge a7f3757...

@bors
Copy link
Contributor

bors commented Jan 26, 2022

☀️ Test successful - checks-actions
Approved by: oli-obk
Pushing a7f3757 to master...

@bors bors added the merged-by-bors This PR was explicitly merged by bors. label Jan 26, 2022
@bors bors merged commit a7f3757 into rust-lang:master Jan 26, 2022
@rustbot rustbot added this to the 1.60.0 milestone Jan 26, 2022
@rust-timer
Copy link
Collaborator

Finished benchmarking commit (a7f3757): comparison url.

Summary: This benchmark run shows 99 relevant improvements 🎉 to instruction counts.

  • Average relevant regression: 1.3%
  • Average relevant improvement: -1.1%
  • Largest improvement in instruction counts: -6.9% on full builds of deeply-nested-async check

If you disagree with this performance assessment, please file an issue in rust-lang/rustc-perf.

@rustbot label: -perf-regression

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
merged-by-bors This PR was explicitly merged by bors. S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

EarlyOtherwiseBranch transformation is incorrect
8 participants