-
Notifications
You must be signed in to change notification settings - Fork 12.8k
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
Add a MIR pass manager #77665
Conversation
203d27c
to
67142ed
Compare
if mir_phase == MirPhase::Optimization { | ||
validate::Validator { when: format!("end of phase {:?}", mir_phase), mir_phase } | ||
.run_pass(tcx, body); | ||
} |
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.
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.
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.
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.
☔ 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:
|
/// 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? |
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.
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
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.
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.
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.
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( |
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.
This function seems to only be used through validate_body
.
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'm aware. It'll be useful later.
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 |
1a7ed98
to
7a8729d
Compare
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.
7a8729d
to
d325564
Compare
☔ 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:
|
@ecstatic-morse Could you resolve the merge conflicts? |
closing this due to inactivity |
…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
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-stylePassManager
, we can interleave calls torun_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