refactor(mir-transform): Merge can_be_overridden, is_required and is_enabled into one - #160015
refactor(mir-transform): Merge can_be_overridden, is_required and is_enabled into one#160015clubby789 wants to merge 2 commits into
can_be_overridden, is_required and is_enabled into one#160015Conversation
|
Some changes occurred to MIR optimizations cc @rust-lang/wg-mir-opt Some changes occurred in coverage instrumentation. cc @Zalathar |
|
|
|
Thanks for helping with the cleanup!
The two have slightly different semantics though, don't they? So I think we need a 3-variant enum here: passes that are actually required (as they implement parts of the MIR semantics), passes that are optional but not "optimizations", and passes that are truly just optimizations. An actually required pass should have an That still spreads the logic across both |
FWIW I had started doing this until I realized that |
This comment has been minimized.
This comment has been minimized.
Thinking a bit more about this... one way we could represent this is with an enum like this: enum PassEnabled {
/// This pass implements a mandatory lowering step, either to implement parts of the MIR semantics
/// or to bring MIR into a shape that is easier to deal with for later passes / codegen.
/// Passes using this cannot be disable via any means. They must not remove any UB.
Required,
/// This pass is optional, it can be controlled via `-Zmir-enable-passes`.
Optional {
/// Whether the pass should be enabled in this compilation session by default,
/// i.e., before applying `-Zmir-enable-passes` or `#[optimize(...)]`.
default_enabled: bool,
/// Whether this is an optimization pass. Only optimization passes are disabled by
/// `#[optimize(none)]`. A pass can be optional without being an optimization pass,
/// e.g. if it just adds extra debug checks that one can anyway also turn off.
optimization: bool,
}
}One could then have a few convenient constructors for the typical cases to make this less verbose. What I am missing in this proposal is a way to explicitly mark an optimization as "I promise not to remove UB". Maybe that should also be a field on /// If this is `true`, then the pass promises that *if `mir_opt_level() == 0`*, it will not remove any UB.
/// Passes that set this to `false` automatically get disabled at MIR optimization level 0.
preserves_ub: bool, |
7099c7f to
5a391ab
Compare
|
I wrote up an approach revolving around the below enum, with EDIT: Folded together /// Rules outlining when this pass may be overridden or suppressed.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub(crate) enum PassPolicy {
/// Part of MIR semantics and must run, even in Miri.
/// Such passes must therefore never remove UB, and should come with a comment justifying
/// why they must always run.
Required,
/// Not an optimization, but may be configured by `-Zmir-enable-passes`.
Optional {
/// Whether this pass should be enabled by default in this session in the absence of
/// an explicit `-Zmir-enable-passes`.
enabled_by_default: bool,
},
/// An optimization pass, which may also be suppressed by `#[optimize(none)]`.
Optimization {
/// Whether this pass should be enabled by default in this session in the absence of
/// an explicit `-Zmir-enable-passes` or `#[optimize]` attribute.
enabled_by_default: bool,
},
} |
5a391ab to
a94264c
Compare
can_be_overridden and is_requiredcan_be_overridden, is_required and is_enabled into one
This comment has been minimized.
This comment has been minimized.
|
That should also work. Not sure how many "optional" passes we have and whether the UB removal question even makes sense for them.
|
a94264c to
61676eb
Compare
| fn is_required(&self) -> bool { | ||
| self.1.is_required() | ||
| fn policy(&self, sess: &Session) -> PassPolicy { | ||
| self.1.policy(sess).and_enabled(sess.mir_opt_level() >= self.0 as usize) |
There was a problem hiding this comment.
This now invokes the underlying passes policy which previously was not the case. Does that change behavior anywhere we use WithMinOptLevel?
There was a problem hiding this comment.
AFAICT, the one place this does interact is that RemoveNoopLandingPads had an is_enabled of panic_strategy().unwinds() and is_required of true. Previously, this condition was ignored by the wrapper. Now it respects it
2a4626a to
a9f9503
Compare
a9f9503 to
2b080be
Compare
2b080be to
225fe83
Compare
…alfJung refactor(mir-transform): Calculate optimization status inside `run_passes_inner` The `Optimizations` enum represents whether `#[optimize(none)]` has been applied to a function. Currently, `run_passes` takes an `Optimizations` which is confusing (rust-lang#160015 (comment)). Calculate this in `run_passes_inner` instead (which also means `#[optimize(none)]` is applied more consistently. r? @RalfJung
This comment has been minimized.
This comment has been minimized.
Rollup merge of #160057 - clubby789:local-optimizations, r=RalfJung refactor(mir-transform): Calculate optimization status inside `run_passes_inner` The `Optimizations` enum represents whether `#[optimize(none)]` has been applied to a function. Currently, `run_passes` takes an `Optimizations` which is confusing (#160015 (comment)). Calculate this in `run_passes_inner` instead (which also means `#[optimize(none)]` is applied more consistently. r? @RalfJung
refactor(mir-transform): Calculate optimization status inside `run_passes_inner` The `Optimizations` enum represents whether `#[optimize(none)]` has been applied to a function. Currently, `run_passes` takes an `Optimizations` which is confusing (rust-lang/rust#160015 (comment)). Calculate this in `run_passes_inner` instead (which also means `#[optimize(none)]` is applied more consistently. r? @RalfJung
This comment was marked as outdated.
This comment was marked as outdated.
225fe83 to
9472a44
Compare
That's not a change? |
|
Indeed, I think I confused myself with the naming... I will see if it's possible to split the policy changes into a second commit |
8a2e5c8 to
750cb0d
Compare
|
This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed. Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers. |
|
Split into two commits, the first should be only refactoring and the second introduces changes to the policies and adding justifications from your commit |
There was a problem hiding this comment.
Yes I like it. :) Just some comment nits.
@rustbot author
We probably want to further tweak optimize(none) behavior and maybe have a mir-opt level that disables all optional passes but that's further refactoring which does not have to happen in this PR.
|
Reminder, once the PR becomes ready for a review, use |
750cb0d to
6ec44cd
Compare
|
r=me when CI is green. :) |
|
✌️ @clubby789, you can now approve this pull request! If @RalfJung told you to " |
|
I will probably investigate #160057 (comment) as a followup, but I think this is a good start to clarify and correct the policies for now. |
|
@bors r=RalfJung |
View all comments
#128657 and #134082 both merged at similar times, and added two similar flags to the
MirPasstraitcan_be_overridden: Controls if-Zmir-enable-passescan enable/disable a pass; only set tofalseforForceInlineis_required: Controls if#[optimize(none)]should suppress a pass; set to explicitlytrue/falseacross all passes based on which appeared to be unconditionally enabled at the timeThis adds some redundancy, so this PR merges both into `can_be_overridden`: - removes cases of `is_required(&self) -> bool { true }` - replaces `is_required(&self) -> bool { false }` with `can_be_overridden(&self) -> bool { true }`Also, previously,
-Zmir-enable-passestook precedence, but now#[optimize(none)]does, as the latter is more local.This merges both functions as well as
is_enabledinto a singlePassPolicyenumr? @RalfJung