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

Add a MIR pass manager #77665

Closed

Conversation

ecstatic-morse
Copy link
Contributor

@ecstatic-morse ecstatic-morse commented Oct 7, 2020

A minor refactoring to transform/mod.rs. It moves MIR phase handling and optimization level/soundness checking into a single module. By using an RAII-style PassManager, we can interleave calls to run_passes with various lints/error-checking. This also adds a flag, -Zmir-opt-skip-pass, which allows skipping MIR optimization passes by name.

I'm not sure this is exactly the direction we want to go, but I really want some form of the declarative OptLevel in this PR.

cc #72515 @rust-lang/wg-mir-opt

r? @wesleywiser

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Oct 7, 2020
@ecstatic-morse ecstatic-morse force-pushed the mir-pass-manager branch 3 times, most recently from 203d27c to 67142ed Compare October 7, 2020 19:39
Comment on lines -207 to -210
if mir_phase == MirPhase::Optimization {
validate::Validator { when: format!("end of phase {:?}", mir_phase), mir_phase }
.run_pass(tcx, body);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Currently we are always running validation at least once and -Zvalidate-mir enables extra validation after each pass. I mentioning this since it is unclear if changing this was intentional.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good catch! This was accident on my part. Besides disabling unsound optimizations below MIR opt-level 2 and only running cleanup passes if we ran the preceding pass in the pipeline (both up for debate), this PR shouldn't have any functional changes.

@bors
Copy link
Contributor

bors commented Oct 8, 2020

☔ The latest upstream changes (presumably #77597) made this pull request unmergeable. Please resolve the merge conflicts.

Note that reviewers usually do not review pull requests until merge conflicts are resolved! Once you resolve the conflicts, you should change the labels applied by bors to indicate that your PR is ready for review. Post this as a comment to change the labels:

@rustbot modify labels: +S-waiting-on-review -S-waiting-on-author

/// A `Cleanup` pass is skipped if the pass immediately preceding it is skipped.
//
// FIXME: Maybe we want to run the cleanup unless *all* passes between it and the last cleanup
// were skipped?
Copy link
Contributor

Choose a reason for hiding this comment

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

This seems a bit fragile to me. Several optimizations nowadays don't need a cleanup after them, because they just invoke the appropriate cleanup method within themselves. Maybe we should migrate to that scheme in general and get rid of all the cleanup passes? That could make diffs harder to read though, so not sure. It does make diffs harder to read in some of the passes with integrated cleanup

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, I don't really have a good solution for this. The status quo is equivalent to giving each instance of a cleanup pass a different LEVEL. I could do this with const-generics, or I could switch from an associated const to an instance method. The latter would make the MirPass trait object-safe again, meaning I could get rid of the run_passes macro, but I really like the declarative nature of associated constants.

Copy link
Contributor

Choose a reason for hiding this comment

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

Thinking about it again, to preserve the current situation, only running a cleanup if the MIR wasn't modified since the last same cleanup doesn't seem too bad. Approximating "MIR wasn't modified" with "no MIR passes were run" is also ok.

The FIXME should be resolved before this PR is merged, as otherwise we may be missing cleanups that were previously triggered even if there were multiple other not-running optimizations in between.

/// itself.
pub mir_phase: MirPhase,
}
pub fn validate_body_during_phase(
Copy link
Member

Choose a reason for hiding this comment

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

This function seems to only be used through validate_body.

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'm aware. It'll be useful later.

@wesleywiser
Copy link
Member

I didn't give high level feedback with my review comments but I really like the direction of this PR in general and I'd be happy to r+ it once the review feedback is resolved!

@ecstatic-morse ecstatic-morse force-pushed the mir-pass-manager branch 2 times, most recently from 1a7ed98 to 7a8729d Compare October 11, 2020 01:43
In general, read-only passes should not be declared as a `MirPass`,
since they always run and their MIR dump provides no additional
information.
These don't actually test anything since whoever implemented
`-Zunsound-mir-opts` forgot to set it when unsound passes were checked.
They break now that the passes are skipped entirely without
`-Zunsound-mir-opts` instead of just being no-ops.
@ecstatic-morse ecstatic-morse marked this pull request as ready for review October 11, 2020 02:36
@bors
Copy link
Contributor

bors commented Oct 13, 2020

☔ The latest upstream changes (presumably #77796) made this pull request unmergeable. Please resolve the merge conflicts.

Note that reviewers usually do not review pull requests until merge conflicts are resolved! Once you resolve the conflicts, you should change the labels applied by bors to indicate that your PR is ready for review. Post this as a comment to change the labels:

@rustbot modify labels: +S-waiting-on-review -S-waiting-on-author

@camelid camelid added A-MIR Area: Mid-level IR (MIR) - https://blog.rust-lang.org/2016/04/19/MIR.html A-mir-opt Area: MIR optimizations S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Oct 30, 2020
@camelid
Copy link
Member

camelid commented Nov 20, 2020

@ecstatic-morse Could you resolve the merge conflicts?

@Dylan-DPC-zz
Copy link

closing this due to inactivity

@camelid camelid added S-inactive Status: Inactive and waiting on the author. This is often applied to closed PRs. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Nov 25, 2020
bors added a commit to rust-lang-ci/rust that referenced this pull request Dec 5, 2021
…li-obk

Add a MIR pass manager (Taylor's Version)

The final draft of rust-lang#91386 and rust-lang#77665.

While the compile-time constraints in rust-lang#91386 are cool, I decided on a more minimal approach for now. I want to explore phase constraints and maybe relative-ordering constraints in the future, though. This should preserve existing behavior **exactly** (please let me know if it doesn't) while making the following changes to the way we organize things today:

- Each `MirPhase` now corresponds to a single MIR pass. `run_passes` is not responsible for listing the correct MIR phase.
- `run_passes` no longer silently skips passes if the declared MIR phase is greater than or equal to the body's. This has bitten me multiple times. If you want this behavior, you can always branch on `body.phase` yourself.
- If your pass is solely to emit errors, you can use the `MirLint` interface instead, which gets a shared reference to `Body` instead of a mutable one. By differentiating the two, I hope to make it clearer in the short term where lints belong in the pipeline. In the long term perhaps we could enforce this at compile-time?
- MIR is no longer dumped for passes that aren't enabled, or for lints.

I tried to check that `-Zvalidate` still works correctly, since the MIR phase is now updated as soon as the associated pass is done, instead of at the end of all the passes in `run_passes`. However, it looks like `-Zvalidate` is broken with current nightlies anyways 😢 (it spits out a bunch of errors).

cc `@oli-obk` `@wesleywiser`

r? rust-lang/wg-mir-opt
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-MIR Area: Mid-level IR (MIR) - https://blog.rust-lang.org/2016/04/19/MIR.html A-mir-opt Area: MIR optimizations S-inactive Status: Inactive and waiting on the author. This is often applied to closed PRs.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants