Skip to content

Commit bdaa901

Browse files
committed
Auto merge of rust-lang#91475 - ecstatic-morse:mir-pass-manager3, r=oli-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
2 parents 5e93f6e + 7bc5eca commit bdaa901

39 files changed

+447
-281
lines changed

compiler/rustc_const_eval/src/transform/promote_consts.rs

+4
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@ pub struct PromoteTemps<'tcx> {
4141
}
4242

4343
impl<'tcx> MirPass<'tcx> for PromoteTemps<'tcx> {
44+
fn phase_change(&self) -> Option<MirPhase> {
45+
Some(MirPhase::ConstPromotion)
46+
}
47+
4448
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
4549
// There's not really any point in promoting errorful MIR.
4650
//

compiler/rustc_middle/src/mir/mod.rs

+15
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use rustc_hir::def::{CtorKind, Namespace};
1616
use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX};
1717
use rustc_hir::{self, GeneratorKind};
1818
use rustc_hir::{self as hir, HirId};
19+
use rustc_session::Session;
1920
use rustc_target::abi::{Size, VariantIdx};
2021

2122
use polonius_engine::Atom;
@@ -99,7 +100,21 @@ pub trait MirPass<'tcx> {
99100
}
100101
}
101102

103+
/// Returns `true` if this pass is enabled with the current combination of compiler flags.
104+
fn is_enabled(&self, _sess: &Session) -> bool {
105+
true
106+
}
107+
102108
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>);
109+
110+
/// If this pass causes the MIR to enter a new phase, return that phase.
111+
fn phase_change(&self) -> Option<MirPhase> {
112+
None
113+
}
114+
115+
fn is_mir_dump_enabled(&self) -> bool {
116+
true
117+
}
103118
}
104119

105120
/// The various "big phases" that MIR goes through.

compiler/rustc_mir_dataflow/src/rustc_peek.rs

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use crate::{Analysis, JoinSemiLattice, Results, ResultsCursor};
2020

2121
pub struct SanityCheck;
2222

23+
// FIXME: This should be a `MirLint`, but it needs to be moved back to `rustc_mir_transform` first.
2324
impl<'tcx> MirPass<'tcx> for SanityCheck {
2425
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
2526
use crate::has_rustc_mir_with;

compiler/rustc_mir_transform/src/add_retag.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,11 @@ fn may_be_reference(ty: Ty<'tcx>) -> bool {
5858
}
5959

6060
impl<'tcx> MirPass<'tcx> for AddRetag {
61-
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
62-
if !tcx.sess.opts.debugging_opts.mir_emit_retag {
63-
return;
64-
}
61+
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
62+
sess.opts.debugging_opts.mir_emit_retag
63+
}
6564

65+
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
6666
// We need an `AllCallEdges` pass before we can do any work.
6767
super::add_call_guards::AllCallEdges.run_pass(tcx, body);
6868

compiler/rustc_mir_transform/src/check_const_item_mutation.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@ use rustc_middle::ty::TyCtxt;
66
use rustc_session::lint::builtin::CONST_ITEM_MUTATION;
77
use rustc_span::def_id::DefId;
88

9-
use crate::MirPass;
9+
use crate::MirLint;
1010

1111
pub struct CheckConstItemMutation;
1212

13-
impl<'tcx> MirPass<'tcx> for CheckConstItemMutation {
14-
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
13+
impl<'tcx> MirLint<'tcx> for CheckConstItemMutation {
14+
fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
1515
let mut checker = ConstMutationChecker { body, tcx, target_local: None };
1616
checker.visit_body(&body);
1717
}

compiler/rustc_mir_transform/src/check_packed_ref.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,16 @@ use rustc_session::lint::builtin::UNALIGNED_REFERENCES;
77
use rustc_span::symbol::sym;
88

99
use crate::util;
10-
use crate::MirPass;
10+
use crate::MirLint;
1111

1212
pub(crate) fn provide(providers: &mut Providers) {
1313
*providers = Providers { unsafe_derive_on_repr_packed, ..*providers };
1414
}
1515

1616
pub struct CheckPackedRef;
1717

18-
impl<'tcx> MirPass<'tcx> for CheckPackedRef {
19-
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
18+
impl<'tcx> MirLint<'tcx> for CheckPackedRef {
19+
fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
2020
let param_env = tcx.param_env(body.source.def_id());
2121
let source_info = SourceInfo::outermost(body.span);
2222
let mut checker = PackedRefChecker { body, tcx, param_env, source_info };

compiler/rustc_mir_transform/src/const_debuginfo.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,11 @@ use rustc_index::{bit_set::BitSet, vec::IndexVec};
1515
pub struct ConstDebugInfo;
1616

1717
impl<'tcx> MirPass<'tcx> for ConstDebugInfo {
18-
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
19-
if !tcx.sess.opts.debugging_opts.unsound_mir_opts {
20-
return;
21-
}
18+
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
19+
sess.opts.debugging_opts.unsound_mir_opts && sess.mir_opt_level() > 0
20+
}
2221

22+
fn run_pass(&self, _: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
2323
trace!("running ConstDebugInfo on {:?}", body.source);
2424

2525
for (local, constant) in find_optimization_oportunities(body) {

compiler/rustc_mir_transform/src/const_goto.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,11 @@ use super::simplify::{simplify_cfg, simplify_locals};
2727
pub struct ConstGoto;
2828

2929
impl<'tcx> MirPass<'tcx> for ConstGoto {
30+
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
31+
sess.mir_opt_level() >= 4
32+
}
33+
3034
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
31-
if tcx.sess.mir_opt_level() < 4 {
32-
return;
33-
}
3435
trace!("Running ConstGoto on {:?}", body.source);
3536
let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
3637
let mut opt_finder =

compiler/rustc_mir_transform/src/const_prop.rs

+7
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,13 @@ macro_rules! throw_machine_stop_str {
6262
pub struct ConstProp;
6363

6464
impl<'tcx> MirPass<'tcx> for ConstProp {
65+
fn is_enabled(&self, _sess: &rustc_session::Session) -> bool {
66+
// FIXME(#70073): Unlike the other passes in "optimizations", this one emits errors, so it
67+
// runs even when MIR optimizations are disabled. We should separate the lint out from the
68+
// transform and move the lint as early in the pipeline as possible.
69+
true
70+
}
71+
6572
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
6673
// will be evaluated by miri and produce its errors there
6774
if body.source.promoted.is_some() {

compiler/rustc_mir_transform/src/coverage/mod.rs

+4
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@ impl Error {
4949
pub struct InstrumentCoverage;
5050

5151
impl<'tcx> MirPass<'tcx> for InstrumentCoverage {
52+
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
53+
sess.instrument_coverage()
54+
}
55+
5256
fn run_pass(&self, tcx: TyCtxt<'tcx>, mir_body: &mut mir::Body<'tcx>) {
5357
let mir_source = mir_body.source;
5458

compiler/rustc_mir_transform/src/deduplicate_blocks.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,11 @@ use super::simplify::simplify_cfg;
1515
pub struct DeduplicateBlocks;
1616

1717
impl<'tcx> MirPass<'tcx> for DeduplicateBlocks {
18+
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
19+
sess.mir_opt_level() >= 4
20+
}
21+
1822
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
19-
if tcx.sess.mir_opt_level() < 4 {
20-
return;
21-
}
2223
debug!("Running DeduplicateBlocks on `{:?}`", body.source);
2324
let duplicates = find_duplicates(body);
2425
let has_opts_to_apply = !duplicates.is_empty();

compiler/rustc_mir_transform/src/dest_prop.rs

+6-9
Original file line numberDiff line numberDiff line change
@@ -124,18 +124,15 @@ const MAX_BLOCKS: usize = 250;
124124
pub struct DestinationPropagation;
125125

126126
impl<'tcx> MirPass<'tcx> for DestinationPropagation {
127-
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
128-
// FIXME(#79191, #82678)
129-
if !tcx.sess.opts.debugging_opts.unsound_mir_opts {
130-
return;
131-
}
132-
127+
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
128+
// FIXME(#79191, #82678): This is unsound.
129+
//
133130
// Only run at mir-opt-level=3 or higher for now (we don't fix up debuginfo and remove
134131
// storage statements at the moment).
135-
if tcx.sess.mir_opt_level() < 3 {
136-
return;
137-
}
132+
sess.opts.debugging_opts.unsound_mir_opts && sess.mir_opt_level() >= 3
133+
}
138134

135+
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
139136
let def_id = body.source.def_id();
140137

141138
let candidates = find_candidates(tcx, body);

compiler/rustc_mir_transform/src/early_otherwise_branch.rs

+5-7
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,14 @@ use super::simplify::simplify_cfg;
2525
pub struct EarlyOtherwiseBranch;
2626

2727
impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch {
28-
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
28+
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
2929
// FIXME(#78496)
30-
if !tcx.sess.opts.debugging_opts.unsound_mir_opts {
31-
return;
32-
}
30+
sess.opts.debugging_opts.unsound_mir_opts && sess.mir_opt_level() >= 3
31+
}
3332

34-
if tcx.sess.mir_opt_level() < 3 {
35-
return;
36-
}
33+
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
3734
trace!("running EarlyOtherwiseBranch on {:?}", body.source);
35+
3836
// we are only interested in this bb if the terminator is a switchInt
3937
let bbs_with_switch =
4038
body.basic_blocks().iter_enumerated().filter(|(_, bb)| is_switch(bb.terminator()));

compiler/rustc_mir_transform/src/elaborate_drops.rs

+4
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ use std::fmt;
1919
pub struct ElaborateDrops;
2020

2121
impl<'tcx> MirPass<'tcx> for ElaborateDrops {
22+
fn phase_change(&self) -> Option<MirPhase> {
23+
Some(MirPhase::DropLowering)
24+
}
25+
2226
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
2327
debug!("elaborate_drops({:?} @ {:?})", body.source, body.span);
2428

compiler/rustc_mir_transform/src/function_item_references.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,12 @@ use rustc_session::lint::builtin::FUNCTION_ITEM_REFERENCES;
1111
use rustc_span::{symbol::sym, Span};
1212
use rustc_target::spec::abi::Abi;
1313

14-
use crate::MirPass;
14+
use crate::MirLint;
1515

1616
pub struct FunctionItemReferences;
1717

18-
impl<'tcx> MirPass<'tcx> for FunctionItemReferences {
19-
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
18+
impl<'tcx> MirLint<'tcx> for FunctionItemReferences {
19+
fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
2020
let mut checker = FunctionItemRefChecker { tcx, body };
2121
checker.visit_body(&body);
2222
}

compiler/rustc_mir_transform/src/generator.rs

+4
Original file line numberDiff line numberDiff line change
@@ -1232,6 +1232,10 @@ fn create_cases<'tcx>(
12321232
}
12331233

12341234
impl<'tcx> MirPass<'tcx> for StateTransform {
1235+
fn phase_change(&self) -> Option<MirPhase> {
1236+
Some(MirPhase::GeneratorLowering)
1237+
}
1238+
12351239
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
12361240
let yield_ty = if let Some(yield_ty) = body.yield_ty() {
12371241
yield_ty

compiler/rustc_mir_transform/src/inline.rs

+7-12
Original file line numberDiff line numberDiff line change
@@ -37,21 +37,16 @@ struct CallSite<'tcx> {
3737
source_info: SourceInfo,
3838
}
3939

40-
/// Returns true if MIR inlining is enabled in the current compilation session.
41-
crate fn is_enabled(tcx: TyCtxt<'_>) -> bool {
42-
if let Some(enabled) = tcx.sess.opts.debugging_opts.inline_mir {
43-
return enabled;
44-
}
45-
46-
tcx.sess.mir_opt_level() >= 3
47-
}
48-
4940
impl<'tcx> MirPass<'tcx> for Inline {
50-
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
51-
if !is_enabled(tcx) {
52-
return;
41+
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
42+
if let Some(enabled) = sess.opts.debugging_opts.inline_mir {
43+
return enabled;
5344
}
5445

46+
sess.opts.mir_opt_level() >= 3
47+
}
48+
49+
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
5550
let span = trace_span!("inline", body = %tcx.def_path_str(body.source.def_id()));
5651
let _guard = span.enter();
5752
if inline(tcx, body) {

compiler/rustc_mir_transform/src/instcombine.rs

+4
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ use rustc_middle::ty::{self, TyCtxt};
1111
pub struct InstCombine;
1212

1313
impl<'tcx> MirPass<'tcx> for InstCombine {
14+
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
15+
sess.mir_opt_level() > 0
16+
}
17+
1418
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
1519
let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut();
1620
let ctx = InstCombineContext { tcx, local_decls };

0 commit comments

Comments
 (0)