From 386b1c5f5760ae35610598969d16382e67160ff2 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Sun, 28 Nov 2021 17:54:42 -0800 Subject: [PATCH 1/9] Move `mir_opt_level` getter into `Options` --- compiler/rustc_session/src/options.rs | 8 ++++++++ compiler/rustc_session/src/session.rs | 5 +---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 779f29e3dfedf..06120160c4249 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -101,6 +101,14 @@ macro_rules! top_level_options { ); } +impl Options { + pub fn mir_opt_level(&self) -> usize { + self.debugging_opts + .mir_opt_level + .unwrap_or_else(|| if self.optimize != OptLevel::No { 2 } else { 1 }) + } +} + top_level_options!( /// The top-level command-line options struct. /// diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 54109559a3bb2..72219bedb6112 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -562,10 +562,7 @@ impl Session { self.opts.debugging_opts.binary_dep_depinfo } pub fn mir_opt_level(&self) -> usize { - self.opts - .debugging_opts - .mir_opt_level - .unwrap_or_else(|| if self.opts.optimize != config::OptLevel::No { 2 } else { 1 }) + self.opts.mir_opt_level() } /// Gets the features enabled for the current compilation session. From a0de6346dec84ca663026e44ef102f4d229bfb38 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Mon, 29 Nov 2021 19:09:01 -0800 Subject: [PATCH 2/9] Move instrument coverage config getters to `Options` --- compiler/rustc_session/src/options.rs | 15 +++++++++++++++ compiler/rustc_session/src/session.rs | 9 +++------ 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 06120160c4249..20ef1afaab2be 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -107,6 +107,21 @@ impl Options { .mir_opt_level .unwrap_or_else(|| if self.optimize != OptLevel::No { 2 } else { 1 }) } + + pub fn instrument_coverage(&self) -> bool { + self.debugging_opts.instrument_coverage.unwrap_or(InstrumentCoverage::Off) + != InstrumentCoverage::Off + } + + pub fn instrument_coverage_except_unused_generics(&self) -> bool { + self.debugging_opts.instrument_coverage.unwrap_or(InstrumentCoverage::Off) + == InstrumentCoverage::ExceptUnusedGenerics + } + + pub fn instrument_coverage_except_unused_functions(&self) -> bool { + self.debugging_opts.instrument_coverage.unwrap_or(InstrumentCoverage::Off) + == InstrumentCoverage::ExceptUnusedFunctions + } } top_level_options!( diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 72219bedb6112..52a92de842f27 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -1044,18 +1044,15 @@ impl Session { } pub fn instrument_coverage(&self) -> bool { - self.opts.debugging_opts.instrument_coverage.unwrap_or(config::InstrumentCoverage::Off) - != config::InstrumentCoverage::Off + self.opts.instrument_coverage() } pub fn instrument_coverage_except_unused_generics(&self) -> bool { - self.opts.debugging_opts.instrument_coverage.unwrap_or(config::InstrumentCoverage::Off) - == config::InstrumentCoverage::ExceptUnusedGenerics + self.opts.instrument_coverage_except_unused_generics() } pub fn instrument_coverage_except_unused_functions(&self) -> bool { - self.opts.debugging_opts.instrument_coverage.unwrap_or(config::InstrumentCoverage::Off) - == config::InstrumentCoverage::ExceptUnusedFunctions + self.opts.instrument_coverage_except_unused_functions() } pub fn is_proc_macro_attr(&self, attr: &Attribute) -> bool { From c1a501b131ae99cb139b0843125f27d548b4cd1b Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Mon, 29 Nov 2021 22:46:32 -0800 Subject: [PATCH 3/9] Implement a pass manager --- compiler/rustc_middle/src/mir/mod.rs | 15 +++ compiler/rustc_mir_transform/src/lib.rs | 5 + .../rustc_mir_transform/src/pass_manager.rs | 121 ++++++++++++++++++ 3 files changed, 141 insertions(+) create mode 100644 compiler/rustc_mir_transform/src/pass_manager.rs diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index df36b2e4e0b3e..75edcaadfdff2 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -16,6 +16,7 @@ use rustc_hir::def::{CtorKind, Namespace}; use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc_hir::{self, GeneratorKind}; use rustc_hir::{self as hir, HirId}; +use rustc_session::Session; use rustc_target::abi::{Size, VariantIdx}; use polonius_engine::Atom; @@ -99,7 +100,21 @@ pub trait MirPass<'tcx> { } } + /// Returns `true` if this pass is enabled with the current combination of compiler flags. + fn is_enabled(&self, _sess: &Session) -> bool { + true + } + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>); + + /// If this pass causes the MIR to enter a new phase, return that phase. + fn phase_change(&self) -> Option { + None + } + + fn is_mir_dump_enabled(&self) -> bool { + true + } } /// The various "big phases" that MIR goes through. diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index acbea9bda11e4..0886e15d33020 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -32,6 +32,11 @@ use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, TyCtxt, TypeFoldable}; use rustc_span::{Span, Symbol}; +#[macro_use] +mod pass_manager; + +use pass_manager::{Lint, MirLint}; + mod abort_unwinding_calls; mod add_call_guards; mod add_moves_for_packed_drops; diff --git a/compiler/rustc_mir_transform/src/pass_manager.rs b/compiler/rustc_mir_transform/src/pass_manager.rs new file mode 100644 index 0000000000000..ea6f82dfc0610 --- /dev/null +++ b/compiler/rustc_mir_transform/src/pass_manager.rs @@ -0,0 +1,121 @@ +use std::borrow::Cow; + +use rustc_middle::mir::{self, Body, MirPhase}; +use rustc_middle::ty::TyCtxt; +use rustc_session::Session; + +use crate::{validate, MirPass}; + +/// Just like `MirPass`, except it cannot mutate `Body`. +pub trait MirLint<'tcx> { + fn name(&self) -> Cow<'_, str> { + let name = std::any::type_name::(); + if let Some(tail) = name.rfind(':') { + Cow::from(&name[tail + 1..]) + } else { + Cow::from(name) + } + } + + fn is_enabled(&self, _sess: &Session) -> bool { + true + } + + fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>); +} + +/// An adapter for `MirLint`s that implements `MirPass`. +#[derive(Debug, Clone)] +pub struct Lint(pub T); + +impl MirPass<'tcx> for Lint +where + T: MirLint<'tcx>, +{ + fn name(&self) -> Cow<'_, str> { + self.0.name() + } + + fn is_enabled(&self, sess: &Session) -> bool { + self.0.is_enabled(sess) + } + + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + self.0.run_lint(tcx, body) + } + + fn is_mir_dump_enabled(&self) -> bool { + false + } +} + +pub fn run_passes(tcx: TyCtxt<'tcx>, body: &'mir mut Body<'tcx>, passes: &[&dyn MirPass<'tcx>]) { + let start_phase = body.phase; + let mut cnt = 0; + + let validate = tcx.sess.opts.debugging_opts.validate_mir; + + if validate { + validate_body(tcx, body, format!("start of phase transition from {:?}", start_phase)); + } + + for pass in passes { + if !pass.is_enabled(&tcx.sess) { + continue; + } + + let name = pass.name(); + let dump_enabled = pass.is_mir_dump_enabled(); + + if dump_enabled { + dump_mir(tcx, body, start_phase, &name, cnt, false); + } + + pass.run_pass(tcx, body); + + if dump_enabled { + dump_mir(tcx, body, start_phase, &name, cnt, true); + cnt += 1; + } + + if let Some(new_phase) = pass.phase_change() { + if body.phase >= new_phase { + panic!("Invalid MIR phase transition from {:?} to {:?}", body.phase, new_phase); + } + + body.phase = new_phase; + } + + if validate { + validate_body(tcx, body, format!("after pass {}", pass.name())); + } + } + + if validate || body.phase == MirPhase::Optimization { + validate_body(tcx, body, format!("end of phase transition to {:?}", body.phase)); + } +} + +pub fn validate_body(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, when: String) { + validate::Validator { when, mir_phase: body.phase }.run_pass(tcx, body); +} + +pub fn dump_mir( + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, + phase: MirPhase, + pass_name: &str, + cnt: usize, + is_after: bool, +) { + let phase_index = phase as u32; + + mir::dump_mir( + tcx, + Some(&format_args!("{:03}-{:03}", phase_index, cnt)), + pass_name, + if is_after { &"after" } else { &"before" }, + body, + |_, _| Ok(()), + ); +} From fd18b45e112d07c20d12303aa5d7d7ffd28830b7 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Thu, 2 Dec 2021 09:17:32 -0800 Subject: [PATCH 4/9] Update passes with new interface --- .../src/transform/promote_consts.rs | 4 ++++ compiler/rustc_mir_dataflow/src/rustc_peek.rs | 1 + compiler/rustc_mir_transform/src/add_retag.rs | 8 ++++---- .../src/check_const_item_mutation.rs | 6 +++--- .../src/check_packed_ref.rs | 6 +++--- .../src/const_debuginfo.rs | 8 ++++---- .../rustc_mir_transform/src/const_goto.rs | 7 ++++--- .../rustc_mir_transform/src/const_prop.rs | 7 +++++++ .../rustc_mir_transform/src/coverage/mod.rs | 4 ++++ .../src/deduplicate_blocks.rs | 7 ++++--- compiler/rustc_mir_transform/src/dest_prop.rs | 15 ++++++--------- .../src/early_otherwise_branch.rs | 12 +++++------- .../src/elaborate_drops.rs | 4 ++++ .../src/function_item_references.rs | 6 +++--- compiler/rustc_mir_transform/src/generator.rs | 4 ++++ compiler/rustc_mir_transform/src/inline.rs | 19 +++++++------------ .../rustc_mir_transform/src/instcombine.rs | 4 ++++ compiler/rustc_mir_transform/src/lib.rs | 10 +++++----- .../src/lower_slice_len.rs | 4 ++++ .../rustc_mir_transform/src/match_branches.rs | 8 ++++---- .../src/multiple_return_terminators.rs | 8 ++++---- .../src/normalize_array_len.rs | 8 ++++---- compiler/rustc_mir_transform/src/nrvo.rs | 8 ++++---- .../src/remove_noop_landing_pads.rs | 16 ++++++---------- .../src/remove_storage_markers.rs | 4 ++++ .../rustc_mir_transform/src/remove_zsts.rs | 4 ++++ .../rustc_mir_transform/src/reveal_all.rs | 15 +++++++++------ .../src/separate_const_switch.rs | 8 ++++---- compiler/rustc_mir_transform/src/simplify.rs | 4 ++++ .../src/simplify_comparison_integral.rs | 4 ++++ .../src/uninhabited_enum_branching.rs | 4 ++++ .../src/unreachable_prop.rs | 12 ++++++------ 32 files changed, 141 insertions(+), 98 deletions(-) diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_const_eval/src/transform/promote_consts.rs index 464155db89f48..3c06074a1b33f 100644 --- a/compiler/rustc_const_eval/src/transform/promote_consts.rs +++ b/compiler/rustc_const_eval/src/transform/promote_consts.rs @@ -41,6 +41,10 @@ pub struct PromoteTemps<'tcx> { } impl<'tcx> MirPass<'tcx> for PromoteTemps<'tcx> { + fn phase_change(&self) -> Option { + Some(MirPhase::ConstPromotion) + } + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { // There's not really any point in promoting errorful MIR. // diff --git a/compiler/rustc_mir_dataflow/src/rustc_peek.rs b/compiler/rustc_mir_dataflow/src/rustc_peek.rs index 28e5d76783aa4..1746d5ee38b92 100644 --- a/compiler/rustc_mir_dataflow/src/rustc_peek.rs +++ b/compiler/rustc_mir_dataflow/src/rustc_peek.rs @@ -20,6 +20,7 @@ use crate::{Analysis, JoinSemiLattice, Results, ResultsCursor}; pub struct SanityCheck; +// FIXME: This should be a `MirLint`, but it needs to be moved back to `rustc_mir_transform` first. impl<'tcx> MirPass<'tcx> for SanityCheck { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { use crate::has_rustc_mir_with; diff --git a/compiler/rustc_mir_transform/src/add_retag.rs b/compiler/rustc_mir_transform/src/add_retag.rs index 7a8dee09c29f0..84ae2a2fbd094 100644 --- a/compiler/rustc_mir_transform/src/add_retag.rs +++ b/compiler/rustc_mir_transform/src/add_retag.rs @@ -58,11 +58,11 @@ fn may_be_reference(ty: Ty<'tcx>) -> bool { } impl<'tcx> MirPass<'tcx> for AddRetag { - fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - if !tcx.sess.opts.debugging_opts.mir_emit_retag { - return; - } + fn is_enabled(&self, sess: &rustc_session::Session) -> bool { + sess.opts.debugging_opts.mir_emit_retag + } + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { // We need an `AllCallEdges` pass before we can do any work. super::add_call_guards::AllCallEdges.run_pass(tcx, body); diff --git a/compiler/rustc_mir_transform/src/check_const_item_mutation.rs b/compiler/rustc_mir_transform/src/check_const_item_mutation.rs index 27fe80a456f7d..6f0d03068f566 100644 --- a/compiler/rustc_mir_transform/src/check_const_item_mutation.rs +++ b/compiler/rustc_mir_transform/src/check_const_item_mutation.rs @@ -6,12 +6,12 @@ use rustc_middle::ty::TyCtxt; use rustc_session::lint::builtin::CONST_ITEM_MUTATION; use rustc_span::def_id::DefId; -use crate::MirPass; +use crate::MirLint; pub struct CheckConstItemMutation; -impl<'tcx> MirPass<'tcx> for CheckConstItemMutation { - fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { +impl<'tcx> MirLint<'tcx> for CheckConstItemMutation { + fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { let mut checker = ConstMutationChecker { body, tcx, target_local: None }; checker.visit_body(&body); } diff --git a/compiler/rustc_mir_transform/src/check_packed_ref.rs b/compiler/rustc_mir_transform/src/check_packed_ref.rs index 49be34c7a2845..31d547103095f 100644 --- a/compiler/rustc_mir_transform/src/check_packed_ref.rs +++ b/compiler/rustc_mir_transform/src/check_packed_ref.rs @@ -7,7 +7,7 @@ use rustc_session::lint::builtin::UNALIGNED_REFERENCES; use rustc_span::symbol::sym; use crate::util; -use crate::MirPass; +use crate::MirLint; pub(crate) fn provide(providers: &mut Providers) { *providers = Providers { unsafe_derive_on_repr_packed, ..*providers }; @@ -15,8 +15,8 @@ pub(crate) fn provide(providers: &mut Providers) { pub struct CheckPackedRef; -impl<'tcx> MirPass<'tcx> for CheckPackedRef { - fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { +impl<'tcx> MirLint<'tcx> for CheckPackedRef { + fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { let param_env = tcx.param_env(body.source.def_id()); let source_info = SourceInfo::outermost(body.span); let mut checker = PackedRefChecker { body, tcx, param_env, source_info }; diff --git a/compiler/rustc_mir_transform/src/const_debuginfo.rs b/compiler/rustc_mir_transform/src/const_debuginfo.rs index b613634560fbd..3613fa4560d6c 100644 --- a/compiler/rustc_mir_transform/src/const_debuginfo.rs +++ b/compiler/rustc_mir_transform/src/const_debuginfo.rs @@ -15,11 +15,11 @@ use rustc_index::{bit_set::BitSet, vec::IndexVec}; pub struct ConstDebugInfo; impl<'tcx> MirPass<'tcx> for ConstDebugInfo { - fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - if !tcx.sess.opts.debugging_opts.unsound_mir_opts { - return; - } + fn is_enabled(&self, sess: &rustc_session::Session) -> bool { + sess.opts.debugging_opts.unsound_mir_opts && sess.mir_opt_level() > 0 + } + fn run_pass(&self, _: TyCtxt<'tcx>, body: &mut Body<'tcx>) { trace!("running ConstDebugInfo on {:?}", body.source); for (local, constant) in find_optimization_oportunities(body) { diff --git a/compiler/rustc_mir_transform/src/const_goto.rs b/compiler/rustc_mir_transform/src/const_goto.rs index d319fdcaa6b7e..beb158dd25828 100644 --- a/compiler/rustc_mir_transform/src/const_goto.rs +++ b/compiler/rustc_mir_transform/src/const_goto.rs @@ -27,10 +27,11 @@ use super::simplify::{simplify_cfg, simplify_locals}; pub struct ConstGoto; impl<'tcx> MirPass<'tcx> for ConstGoto { + fn is_enabled(&self, sess: &rustc_session::Session) -> bool { + sess.mir_opt_level() >= 4 + } + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - if tcx.sess.mir_opt_level() < 4 { - return; - } trace!("Running ConstGoto on {:?}", body.source); let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id()); let mut opt_finder = diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs index 63c637af5c21a..1fb69f081e5a8 100644 --- a/compiler/rustc_mir_transform/src/const_prop.rs +++ b/compiler/rustc_mir_transform/src/const_prop.rs @@ -62,6 +62,13 @@ macro_rules! throw_machine_stop_str { pub struct ConstProp; impl<'tcx> MirPass<'tcx> for ConstProp { + fn is_enabled(&self, _sess: &rustc_session::Session) -> bool { + // FIXME(#70073): Unlike the other passes in "optimizations", this one emits errors, so it + // runs even when MIR optimizations are disabled. We should separate the lint out from the + // transform and move the lint as early in the pipeline as possible. + true + } + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { // will be evaluated by miri and produce its errors there if body.source.promoted.is_some() { diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index 6807d02519e2b..bba188bd39350 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -49,6 +49,10 @@ impl Error { pub struct InstrumentCoverage; impl<'tcx> MirPass<'tcx> for InstrumentCoverage { + fn is_enabled(&self, sess: &rustc_session::Session) -> bool { + sess.instrument_coverage() + } + fn run_pass(&self, tcx: TyCtxt<'tcx>, mir_body: &mut mir::Body<'tcx>) { let mir_source = mir_body.source; diff --git a/compiler/rustc_mir_transform/src/deduplicate_blocks.rs b/compiler/rustc_mir_transform/src/deduplicate_blocks.rs index 8d2413433a92b..993c8eef711ce 100644 --- a/compiler/rustc_mir_transform/src/deduplicate_blocks.rs +++ b/compiler/rustc_mir_transform/src/deduplicate_blocks.rs @@ -15,10 +15,11 @@ use super::simplify::simplify_cfg; pub struct DeduplicateBlocks; impl<'tcx> MirPass<'tcx> for DeduplicateBlocks { + fn is_enabled(&self, sess: &rustc_session::Session) -> bool { + sess.mir_opt_level() >= 4 + } + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - if tcx.sess.mir_opt_level() < 4 { - return; - } debug!("Running DeduplicateBlocks on `{:?}`", body.source); let duplicates = find_duplicates(body); let has_opts_to_apply = !duplicates.is_empty(); diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs index c45946a9e2a98..bee15f8c98214 100644 --- a/compiler/rustc_mir_transform/src/dest_prop.rs +++ b/compiler/rustc_mir_transform/src/dest_prop.rs @@ -124,18 +124,15 @@ const MAX_BLOCKS: usize = 250; pub struct DestinationPropagation; impl<'tcx> MirPass<'tcx> for DestinationPropagation { - fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - // FIXME(#79191, #82678) - if !tcx.sess.opts.debugging_opts.unsound_mir_opts { - return; - } - + fn is_enabled(&self, sess: &rustc_session::Session) -> bool { + // FIXME(#79191, #82678): This is unsound. + // // Only run at mir-opt-level=3 or higher for now (we don't fix up debuginfo and remove // storage statements at the moment). - if tcx.sess.mir_opt_level() < 3 { - return; - } + sess.opts.debugging_opts.unsound_mir_opts && sess.mir_opt_level() >= 3 + } + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { let def_id = body.source.def_id(); let candidates = find_candidates(tcx, body); diff --git a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs index f191911a6c7c1..62e82aca26207 100644 --- a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs +++ b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs @@ -25,16 +25,14 @@ use super::simplify::simplify_cfg; pub struct EarlyOtherwiseBranch; impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch { - fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + fn is_enabled(&self, sess: &rustc_session::Session) -> bool { // FIXME(#78496) - if !tcx.sess.opts.debugging_opts.unsound_mir_opts { - return; - } + sess.opts.debugging_opts.unsound_mir_opts && sess.mir_opt_level() >= 3 + } - if tcx.sess.mir_opt_level() < 3 { - return; - } + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { trace!("running EarlyOtherwiseBranch on {:?}", body.source); + // we are only interested in this bb if the terminator is a switchInt let bbs_with_switch = body.basic_blocks().iter_enumerated().filter(|(_, bb)| is_switch(bb.terminator())); diff --git a/compiler/rustc_mir_transform/src/elaborate_drops.rs b/compiler/rustc_mir_transform/src/elaborate_drops.rs index b9a48197a351a..af13c734e5b9a 100644 --- a/compiler/rustc_mir_transform/src/elaborate_drops.rs +++ b/compiler/rustc_mir_transform/src/elaborate_drops.rs @@ -19,6 +19,10 @@ use std::fmt; pub struct ElaborateDrops; impl<'tcx> MirPass<'tcx> for ElaborateDrops { + fn phase_change(&self) -> Option { + Some(MirPhase::DropLowering) + } + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { debug!("elaborate_drops({:?} @ {:?})", body.source, body.span); diff --git a/compiler/rustc_mir_transform/src/function_item_references.rs b/compiler/rustc_mir_transform/src/function_item_references.rs index 996c158c062fb..c05dc39afc47e 100644 --- a/compiler/rustc_mir_transform/src/function_item_references.rs +++ b/compiler/rustc_mir_transform/src/function_item_references.rs @@ -11,12 +11,12 @@ use rustc_session::lint::builtin::FUNCTION_ITEM_REFERENCES; use rustc_span::{symbol::sym, Span}; use rustc_target::spec::abi::Abi; -use crate::MirPass; +use crate::MirLint; pub struct FunctionItemReferences; -impl<'tcx> MirPass<'tcx> for FunctionItemReferences { - fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { +impl<'tcx> MirLint<'tcx> for FunctionItemReferences { + fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { let mut checker = FunctionItemRefChecker { tcx, body }; checker.visit_body(&body); } diff --git a/compiler/rustc_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs index bc72e9d94a953..5376855035e71 100644 --- a/compiler/rustc_mir_transform/src/generator.rs +++ b/compiler/rustc_mir_transform/src/generator.rs @@ -1232,6 +1232,10 @@ fn create_cases<'tcx>( } impl<'tcx> MirPass<'tcx> for StateTransform { + fn phase_change(&self) -> Option { + Some(MirPhase::GeneratorLowering) + } + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { let yield_ty = if let Some(yield_ty) = body.yield_ty() { yield_ty diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index 84a1e3fb600fd..62686b0b71854 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -37,21 +37,16 @@ struct CallSite<'tcx> { source_info: SourceInfo, } -/// Returns true if MIR inlining is enabled in the current compilation session. -crate fn is_enabled(tcx: TyCtxt<'_>) -> bool { - if let Some(enabled) = tcx.sess.opts.debugging_opts.inline_mir { - return enabled; - } - - tcx.sess.mir_opt_level() >= 3 -} - impl<'tcx> MirPass<'tcx> for Inline { - fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - if !is_enabled(tcx) { - return; + fn is_enabled(&self, sess: &rustc_session::Session) -> bool { + if let Some(enabled) = sess.opts.debugging_opts.inline_mir { + return enabled; } + sess.opts.mir_opt_level() >= 3 + } + + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { let span = trace_span!("inline", body = %tcx.def_path_str(body.source.def_id())); let _guard = span.enter(); if inline(tcx, body) { diff --git a/compiler/rustc_mir_transform/src/instcombine.rs b/compiler/rustc_mir_transform/src/instcombine.rs index e15a69c95ae9c..c5adc241664d2 100644 --- a/compiler/rustc_mir_transform/src/instcombine.rs +++ b/compiler/rustc_mir_transform/src/instcombine.rs @@ -11,6 +11,10 @@ use rustc_middle::ty::{self, TyCtxt}; pub struct InstCombine; impl<'tcx> MirPass<'tcx> for InstCombine { + fn is_enabled(&self, sess: &rustc_session::Session) -> bool { + sess.mir_opt_level() > 0 + } + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut(); let ctx = InstCombineContext { tcx, local_decls }; diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 0886e15d33020..4ef35a0cd36ce 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -290,12 +290,12 @@ fn mir_const<'tcx>( MirPhase::Const, &[&[ // MIR-level lints. - &check_packed_ref::CheckPackedRef, - &check_const_item_mutation::CheckConstItemMutation, - &function_item_references::FunctionItemReferences, + &Lint(check_packed_ref::CheckPackedRef), + &Lint(check_const_item_mutation::CheckConstItemMutation), + &Lint(function_item_references::FunctionItemReferences), // What we need to do constant evaluation. &simplify::SimplifyCfg::new("initial"), - &rustc_peek::SanityCheck, + &rustc_peek::SanityCheck, // Just a lint ]], ); tcx.alloc_steal_mir(body) @@ -443,7 +443,7 @@ fn mir_drops_elaborated_and_const_checked<'tcx>( let def = ty::WithOptConstParam::unknown(did); // Do not compute the mir call graph without said call graph actually being used. - if inline::is_enabled(tcx) { + if inline::Inline.is_enabled(&tcx.sess) { let _ = tcx.mir_inliner_callees(ty::InstanceDef::Item(def)); } } diff --git a/compiler/rustc_mir_transform/src/lower_slice_len.rs b/compiler/rustc_mir_transform/src/lower_slice_len.rs index 822a372d8ce90..c829774487308 100644 --- a/compiler/rustc_mir_transform/src/lower_slice_len.rs +++ b/compiler/rustc_mir_transform/src/lower_slice_len.rs @@ -10,6 +10,10 @@ use rustc_middle::ty::{self, TyCtxt}; pub struct LowerSliceLenCalls; impl<'tcx> MirPass<'tcx> for LowerSliceLenCalls { + fn is_enabled(&self, sess: &rustc_session::Session) -> bool { + sess.opts.mir_opt_level() > 0 + } + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { lower_slice_len_calls(tcx, body) } diff --git a/compiler/rustc_mir_transform/src/match_branches.rs b/compiler/rustc_mir_transform/src/match_branches.rs index c618abe9d0599..3c14a324c36ff 100644 --- a/compiler/rustc_mir_transform/src/match_branches.rs +++ b/compiler/rustc_mir_transform/src/match_branches.rs @@ -40,11 +40,11 @@ pub struct MatchBranchSimplification; /// ``` impl<'tcx> MirPass<'tcx> for MatchBranchSimplification { - fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - if tcx.sess.mir_opt_level() < 3 { - return; - } + fn is_enabled(&self, sess: &rustc_session::Session) -> bool { + sess.mir_opt_level() >= 3 + } + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { let def_id = body.source.def_id(); let param_env = tcx.param_env(def_id); diff --git a/compiler/rustc_mir_transform/src/multiple_return_terminators.rs b/compiler/rustc_mir_transform/src/multiple_return_terminators.rs index b614917a88369..22b6dead99c50 100644 --- a/compiler/rustc_mir_transform/src/multiple_return_terminators.rs +++ b/compiler/rustc_mir_transform/src/multiple_return_terminators.rs @@ -9,11 +9,11 @@ use rustc_middle::ty::TyCtxt; pub struct MultipleReturnTerminators; impl<'tcx> MirPass<'tcx> for MultipleReturnTerminators { - fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - if tcx.sess.mir_opt_level() < 4 { - return; - } + fn is_enabled(&self, sess: &rustc_session::Session) -> bool { + sess.mir_opt_level() >= 4 + } + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { // find basic blocks with no statement and a return terminator let mut bbs_simple_returns = BitSet::new_empty(body.basic_blocks().len()); let def_id = body.source.def_id(); diff --git a/compiler/rustc_mir_transform/src/normalize_array_len.rs b/compiler/rustc_mir_transform/src/normalize_array_len.rs index a04a0b5153150..0fd9e0352a249 100644 --- a/compiler/rustc_mir_transform/src/normalize_array_len.rs +++ b/compiler/rustc_mir_transform/src/normalize_array_len.rs @@ -14,11 +14,11 @@ const MAX_NUM_LOCALS: usize = 3000; pub struct NormalizeArrayLen; impl<'tcx> MirPass<'tcx> for NormalizeArrayLen { - fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - if tcx.sess.mir_opt_level() < 4 { - return; - } + fn is_enabled(&self, sess: &rustc_session::Session) -> bool { + sess.mir_opt_level() >= 4 + } + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { // early returns for edge cases of highly unrolled functions if body.basic_blocks().len() > MAX_NUM_BLOCKS { return; diff --git a/compiler/rustc_mir_transform/src/nrvo.rs b/compiler/rustc_mir_transform/src/nrvo.rs index 3ac4e77cf9a75..88ec34b73ec40 100644 --- a/compiler/rustc_mir_transform/src/nrvo.rs +++ b/compiler/rustc_mir_transform/src/nrvo.rs @@ -33,11 +33,11 @@ use crate::MirPass; pub struct RenameReturnPlace; impl<'tcx> MirPass<'tcx> for RenameReturnPlace { - fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut mir::Body<'tcx>) { - if tcx.sess.mir_opt_level() == 0 { - return; - } + fn is_enabled(&self, sess: &rustc_session::Session) -> bool { + sess.mir_opt_level() > 0 + } + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut mir::Body<'tcx>) { let def_id = body.source.def_id(); let returned_local = match local_eligible_for_nrvo(body) { Some(l) => l, diff --git a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs index 298bcd9dc24f9..2a73e341f1653 100644 --- a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs +++ b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs @@ -10,18 +10,14 @@ use rustc_target::spec::PanicStrategy; /// code for these. pub struct RemoveNoopLandingPads; -pub fn remove_noop_landing_pads<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - if tcx.sess.panic_strategy() == PanicStrategy::Abort { - return; +impl<'tcx> MirPass<'tcx> for RemoveNoopLandingPads { + fn is_enabled(&self, sess: &rustc_session::Session) -> bool { + sess.panic_strategy() != PanicStrategy::Abort } - debug!("remove_noop_landing_pads({:?})", body); - - RemoveNoopLandingPads.remove_nop_landing_pads(body) -} -impl<'tcx> MirPass<'tcx> for RemoveNoopLandingPads { - fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - remove_noop_landing_pads(tcx, body); + fn run_pass(&self, _: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + debug!("remove_noop_landing_pads({:?})", body); + self.remove_nop_landing_pads(body) } } diff --git a/compiler/rustc_mir_transform/src/remove_storage_markers.rs b/compiler/rustc_mir_transform/src/remove_storage_markers.rs index 0c7323cbac5b1..c9b6e1459d323 100644 --- a/compiler/rustc_mir_transform/src/remove_storage_markers.rs +++ b/compiler/rustc_mir_transform/src/remove_storage_markers.rs @@ -7,6 +7,10 @@ use rustc_middle::ty::TyCtxt; pub struct RemoveStorageMarkers; impl<'tcx> MirPass<'tcx> for RemoveStorageMarkers { + fn is_enabled(&self, sess: &rustc_session::Session) -> bool { + sess.mir_opt_level() > 0 + } + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { if tcx.sess.emit_lifetime_markers() { return; diff --git a/compiler/rustc_mir_transform/src/remove_zsts.rs b/compiler/rustc_mir_transform/src/remove_zsts.rs index d93ffa38c6906..1d912e6140989 100644 --- a/compiler/rustc_mir_transform/src/remove_zsts.rs +++ b/compiler/rustc_mir_transform/src/remove_zsts.rs @@ -8,6 +8,10 @@ use rustc_middle::ty::{self, Ty, TyCtxt}; pub struct RemoveZsts; impl<'tcx> MirPass<'tcx> for RemoveZsts { + fn is_enabled(&self, sess: &rustc_session::Session) -> bool { + sess.mir_opt_level() > 0 + } + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { // Avoid query cycles (generators require optimized MIR for layout). if tcx.type_of(body.source.def_id()).is_generator() { diff --git a/compiler/rustc_mir_transform/src/reveal_all.rs b/compiler/rustc_mir_transform/src/reveal_all.rs index 3bcb71b64f455..a717dd3e0cd8a 100644 --- a/compiler/rustc_mir_transform/src/reveal_all.rs +++ b/compiler/rustc_mir_transform/src/reveal_all.rs @@ -8,15 +8,18 @@ use rustc_middle::ty::{self, Ty, TyCtxt}; pub struct RevealAll; impl<'tcx> MirPass<'tcx> for RevealAll { + fn is_enabled(&self, sess: &rustc_session::Session) -> bool { + sess.opts.mir_opt_level() >= 3 || super::inline::Inline.is_enabled(sess) + } + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - // This pass must run before inlining, since we insert callee bodies in RevealAll mode. // Do not apply this transformation to generators. - if (tcx.sess.mir_opt_level() >= 3 || super::inline::is_enabled(tcx)) - && body.generator.is_none() - { - let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id()); - RevealAllVisitor { tcx, param_env }.visit_body(body); + if body.generator.is_some() { + return; } + + let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id()); + RevealAllVisitor { tcx, param_env }.visit_body(body); } } diff --git a/compiler/rustc_mir_transform/src/separate_const_switch.rs b/compiler/rustc_mir_transform/src/separate_const_switch.rs index 3002e7041b024..7450d53ba717e 100644 --- a/compiler/rustc_mir_transform/src/separate_const_switch.rs +++ b/compiler/rustc_mir_transform/src/separate_const_switch.rs @@ -45,11 +45,11 @@ use smallvec::SmallVec; pub struct SeparateConstSwitch; impl<'tcx> MirPass<'tcx> for SeparateConstSwitch { - fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - if tcx.sess.mir_opt_level() < 4 { - return; - } + fn is_enabled(&self, sess: &rustc_session::Session) -> bool { + sess.mir_opt_level() >= 4 + } + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { // If execution did something, applying a simplification layer // helps later passes optimize the copy away. if separate_const_switch(body) > 0 { diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs index d6cd505cbb569..677869a0bdb6a 100644 --- a/compiler/rustc_mir_transform/src/simplify.rs +++ b/compiler/rustc_mir_transform/src/simplify.rs @@ -368,6 +368,10 @@ fn save_unreachable_coverage( pub struct SimplifyLocals; impl<'tcx> MirPass<'tcx> for SimplifyLocals { + fn is_enabled(&self, sess: &rustc_session::Session) -> bool { + sess.mir_opt_level() > 0 + } + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { trace!("running SimplifyLocals on {:?}", body.source); simplify_locals(body, tcx); diff --git a/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs b/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs index 948fcd9f4550f..3bd68e8210d5b 100644 --- a/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs +++ b/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs @@ -26,6 +26,10 @@ use rustc_middle::{ pub struct SimplifyComparisonIntegral; impl<'tcx> MirPass<'tcx> for SimplifyComparisonIntegral { + fn is_enabled(&self, sess: &rustc_session::Session) -> bool { + sess.mir_opt_level() > 0 + } + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { trace!("Running SimplifyComparisonIntegral on {:?}", body.source); diff --git a/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs b/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs index 2aa506112909d..77bc209539b34 100644 --- a/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs +++ b/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs @@ -70,6 +70,10 @@ fn variant_discriminants<'tcx>( } impl<'tcx> MirPass<'tcx> for UninhabitedEnumBranching { + fn is_enabled(&self, sess: &rustc_session::Session) -> bool { + sess.mir_opt_level() > 0 + } + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { if body.source.promoted.is_some() { return; diff --git a/compiler/rustc_mir_transform/src/unreachable_prop.rs b/compiler/rustc_mir_transform/src/unreachable_prop.rs index 64cd6f56a9ffa..37071ba611708 100644 --- a/compiler/rustc_mir_transform/src/unreachable_prop.rs +++ b/compiler/rustc_mir_transform/src/unreachable_prop.rs @@ -11,13 +11,13 @@ use rustc_middle::ty::TyCtxt; pub struct UnreachablePropagation; impl MirPass<'_> for UnreachablePropagation { - fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - if tcx.sess.mir_opt_level() < 4 { - // Enable only under -Zmir-opt-level=4 as in some cases (check the deeply-nested-opt - // perf benchmark) LLVM may spend quite a lot of time optimizing the generated code. - return; - } + fn is_enabled(&self, sess: &rustc_session::Session) -> bool { + // Enable only under -Zmir-opt-level=4 as in some cases (check the deeply-nested-opt + // perf benchmark) LLVM may spend quite a lot of time optimizing the generated code. + sess.mir_opt_level() >= 4 + } + fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { let mut unreachable_blocks = FxHashSet::default(); let mut replacements = FxHashMap::default(); From fca642c1c38b53db368114efe617378fd8229532 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Thu, 2 Dec 2021 12:04:32 -0800 Subject: [PATCH 5/9] Add pass for simple phase change --- compiler/rustc_mir_transform/src/lib.rs | 1 + compiler/rustc_mir_transform/src/marker.rs | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+) create mode 100644 compiler/rustc_mir_transform/src/marker.rs diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 4ef35a0cd36ce..f28f567985517 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -61,6 +61,7 @@ mod inline; mod instcombine; mod lower_intrinsics; mod lower_slice_len; +mod marker; mod match_branches; mod multiple_return_terminators; mod normalize_array_len; diff --git a/compiler/rustc_mir_transform/src/marker.rs b/compiler/rustc_mir_transform/src/marker.rs new file mode 100644 index 0000000000000..06819fc1d37d4 --- /dev/null +++ b/compiler/rustc_mir_transform/src/marker.rs @@ -0,0 +1,20 @@ +use std::borrow::Cow; + +use crate::MirPass; +use rustc_middle::mir::{Body, MirPhase}; +use rustc_middle::ty::TyCtxt; + +/// Changes the MIR phase without changing the MIR itself. +pub struct PhaseChange(pub MirPhase); + +impl<'tcx> MirPass<'tcx> for PhaseChange { + fn phase_change(&self) -> Option { + Some(self.0) + } + + fn name(&self) -> Cow<'_, str> { + Cow::from(format!("PhaseChange-{:?}", self.0)) + } + + fn run_pass(&self, _: TyCtxt<'tcx>, _body: &mut Body<'tcx>) {} +} From 71dd5422acd06a9cab95c6f202dbb5c577f91ef9 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Thu, 2 Dec 2021 14:20:03 -0800 Subject: [PATCH 6/9] Use new MIR pass manager --- compiler/rustc_mir_transform/src/lib.rs | 241 +++++++---------------- compiler/rustc_mir_transform/src/shim.rs | 12 +- 2 files changed, 79 insertions(+), 174 deletions(-) diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index f28f567985517..793e46687d2f1 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -27,7 +27,7 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_index::vec::IndexVec; use rustc_middle::mir::visit::Visitor as _; -use rustc_middle::mir::{dump_mir, traversal, Body, ConstQualifs, MirPass, MirPhase, Promoted}; +use rustc_middle::mir::{traversal, Body, ConstQualifs, MirPass, MirPhase, Promoted}; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, TyCtxt, TypeFoldable}; use rustc_span::{Span, Symbol}; @@ -35,7 +35,7 @@ use rustc_span::{Span, Symbol}; #[macro_use] mod pass_manager; -use pass_manager::{Lint, MirLint}; +use pass_manager::{self as pm, Lint, MirLint}; mod abort_unwinding_calls; mod add_call_guards; @@ -174,66 +174,6 @@ fn mir_keys(tcx: TyCtxt<'_>, (): ()) -> FxHashSet { set } -fn run_passes( - tcx: TyCtxt<'tcx>, - body: &mut Body<'tcx>, - mir_phase: MirPhase, - passes: &[&[&dyn MirPass<'tcx>]], -) { - let phase_index = mir_phase.phase_index(); - let validate = tcx.sess.opts.debugging_opts.validate_mir; - - if body.phase >= mir_phase { - return; - } - - if validate { - validate::Validator { when: format!("input to phase {:?}", mir_phase), mir_phase } - .run_pass(tcx, body); - } - - let mut index = 0; - let mut run_pass = |pass: &dyn MirPass<'tcx>| { - let run_hooks = |body: &_, index, is_after| { - let disambiguator = if is_after { "after" } else { "before" }; - dump_mir( - tcx, - Some(&format_args!("{:03}-{:03}", phase_index, index)), - &pass.name(), - &disambiguator, - body, - |_, _| Ok(()), - ); - }; - run_hooks(body, index, false); - pass.run_pass(tcx, body); - run_hooks(body, index, true); - - if validate { - validate::Validator { - when: format!("after {} in phase {:?}", pass.name(), mir_phase), - mir_phase, - } - .run_pass(tcx, body); - } - - index += 1; - }; - - for pass_group in passes { - for pass in *pass_group { - run_pass(*pass); - } - } - - body.phase = mir_phase; - - if mir_phase == MirPhase::Optimization { - validate::Validator { when: format!("end of phase {:?}", mir_phase), mir_phase } - .run_pass(tcx, body); - } -} - fn mir_const_qualif(tcx: TyCtxt<'_>, def: ty::WithOptConstParam) -> ConstQualifs { let const_kind = tcx.hir().body_const_context(def.did); @@ -285,11 +225,10 @@ fn mir_const<'tcx>( rustc_middle::mir::dump_mir(tcx, None, "mir_map", &0, &body, |_, _| Ok(())); - run_passes( + pm::run_passes( tcx, &mut body, - MirPhase::Const, - &[&[ + &[ // MIR-level lints. &Lint(check_packed_ref::CheckPackedRef), &Lint(check_const_item_mutation::CheckConstItemMutation), @@ -297,7 +236,8 @@ fn mir_const<'tcx>( // What we need to do constant evaluation. &simplify::SimplifyCfg::new("initial"), &rustc_peek::SanityCheck, // Just a lint - ]], + &marker::PhaseChange(MirPhase::Const), + ], ); tcx.alloc_steal_mir(body) } @@ -324,17 +264,17 @@ fn mir_promoted( } body.required_consts = required_consts; + // What we need to run borrowck etc. let promote_pass = promote_consts::PromoteTemps::default(); - let promote: &[&dyn MirPass<'tcx>] = &[ - // What we need to run borrowck etc. - &promote_pass, - &simplify::SimplifyCfg::new("promote-consts"), - ]; - - let opt_coverage: &[&dyn MirPass<'tcx>] = - if tcx.sess.instrument_coverage() { &[&coverage::InstrumentCoverage] } else { &[] }; - - run_passes(tcx, &mut body, MirPhase::ConstPromotion, &[promote, opt_coverage]); + pm::run_passes( + tcx, + &mut body, + &[ + &promote_pass, + &simplify::SimplifyCfg::new("promote-consts"), + &coverage::InstrumentCoverage, + ], + ); let promoted = promote_pass.promoted_fragments.into_inner(); (tcx.alloc_steal_mir(body), tcx.alloc_steal_promoted(promoted)) @@ -396,19 +336,10 @@ fn inner_mir_for_ctfe(tcx: TyCtxt<'_>, def: ty::WithOptConstParam) - // Technically we want to not run on regular const items, but oli-obk doesn't know how to // conveniently detect that at this point without looking at the HIR. hir::ConstContext::Const => { - #[rustfmt::skip] - let optimizations: &[&dyn MirPass<'_>] = &[ - &const_prop::ConstProp, - ]; - - #[rustfmt::skip] - run_passes( + pm::run_passes( tcx, &mut body, - MirPhase::Optimization, - &[ - optimizations, - ], + &[&const_prop::ConstProp, &marker::PhaseChange(MirPhase::Optimization)], ); } } @@ -453,19 +384,23 @@ fn mir_drops_elaborated_and_const_checked<'tcx>( let mut body = body.steal(); // IMPORTANT - remove_false_edges::RemoveFalseEdges.run_pass(tcx, &mut body); + pm::run_passes(tcx, &mut body, &[&remove_false_edges::RemoveFalseEdges]); // Do a little drop elaboration before const-checking if `const_precise_live_drops` is enabled. - // - // FIXME: Can't use `run_passes` for these, since `run_passes` SILENTLY DOES NOTHING IF THE MIR - // PHASE DOESN'T CHANGE. if check_consts::post_drop_elaboration::checking_enabled(&ConstCx::new(tcx, &body)) { - simplify::SimplifyCfg::new("remove-false-edges").run_pass(tcx, &mut body); - remove_uninit_drops::RemoveUninitDrops.run_pass(tcx, &mut body); - check_consts::post_drop_elaboration::check_live_drops(tcx, &body); + pm::run_passes( + tcx, + &mut body, + &[ + &simplify::SimplifyCfg::new("remove-false-edges"), + &remove_uninit_drops::RemoveUninitDrops, + ], + ); + check_consts::post_drop_elaboration::check_live_drops(tcx, &body); // FIXME: make this a MIR lint } run_post_borrowck_cleanup_passes(tcx, &mut body); + assert!(body.phase == MirPhase::DropLowering); tcx.alloc_steal_mir(body) } @@ -499,95 +434,65 @@ fn run_post_borrowck_cleanup_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tc &deaggregator::Deaggregator, ]; - run_passes(tcx, body, MirPhase::DropLowering, &[post_borrowck_cleanup]); + pm::run_passes(tcx, body, post_borrowck_cleanup); } fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - let mir_opt_level = tcx.sess.mir_opt_level(); - // Lowering generator control-flow and variables has to happen before we do anything else // to them. We run some optimizations before that, because they may be harder to do on the state // machine than on MIR with async primitives. - let optimizations_with_generators: &[&dyn MirPass<'tcx>] = &[ - &reveal_all::RevealAll, // has to be done before inlining, since inlined code is in RevealAll mode. - &lower_slice_len::LowerSliceLenCalls, // has to be done before inlining, otherwise actual call will be almost always inlined. Also simple, so can just do first - &normalize_array_len::NormalizeArrayLen, // has to run after `slice::len` lowering - &unreachable_prop::UnreachablePropagation, - &uninhabited_enum_branching::UninhabitedEnumBranching, - &simplify::SimplifyCfg::new("after-uninhabited-enum-branching"), - &inline::Inline, - &generator::StateTransform, - ]; - - // Even if we don't do optimizations, we still have to lower generators for codegen. - let no_optimizations_with_generators: &[&dyn MirPass<'tcx>] = &[&generator::StateTransform]; - - // The main optimizations that we do on MIR. - let optimizations: &[&dyn MirPass<'tcx>] = &[ - &remove_storage_markers::RemoveStorageMarkers, - &remove_zsts::RemoveZsts, - &const_goto::ConstGoto, - &remove_unneeded_drops::RemoveUnneededDrops, - &match_branches::MatchBranchSimplification, - // inst combine is after MatchBranchSimplification to clean up Ne(_1, false) - &multiple_return_terminators::MultipleReturnTerminators, - &instcombine::InstCombine, - &separate_const_switch::SeparateConstSwitch, - &const_prop::ConstProp, - &simplify_branches::SimplifyConstCondition::new("after-const-prop"), - &early_otherwise_branch::EarlyOtherwiseBranch, - &simplify_comparison_integral::SimplifyComparisonIntegral, - &simplify_try::SimplifyArmIdentity, - &simplify_try::SimplifyBranchSame, - &dest_prop::DestinationPropagation, - &simplify_branches::SimplifyConstCondition::new("final"), - &remove_noop_landing_pads::RemoveNoopLandingPads, - &simplify::SimplifyCfg::new("final"), - &nrvo::RenameReturnPlace, - &const_debuginfo::ConstDebugInfo, - &simplify::SimplifyLocals, - &multiple_return_terminators::MultipleReturnTerminators, - &deduplicate_blocks::DeduplicateBlocks, - ]; - - // Optimizations to run even if mir optimizations have been disabled. - let no_optimizations: &[&dyn MirPass<'tcx>] = &[ - // FIXME(#70073): This pass is responsible for both optimization as well as some lints. - &const_prop::ConstProp, - ]; - - // Some cleanup necessary at least for LLVM and potentially other codegen backends. - let pre_codegen_cleanup: &[&dyn MirPass<'tcx>] = &[ - &add_call_guards::CriticalCallEdges, - // Dump the end result for testing and debugging purposes. - &dump_mir::Marker("PreCodegen"), - ]; - - // End of pass declarations, now actually run the passes. - // Generator Lowering - #[rustfmt::skip] - run_passes( + pm::run_passes( tcx, body, - MirPhase::GeneratorLowering, &[ - if mir_opt_level > 0 { - optimizations_with_generators - } else { - no_optimizations_with_generators - } + &reveal_all::RevealAll, // has to be done before inlining, since inlined code is in RevealAll mode. + &lower_slice_len::LowerSliceLenCalls, // has to be done before inlining, otherwise actual call will be almost always inlined. Also simple, so can just do first + &normalize_array_len::NormalizeArrayLen, // has to run after `slice::len` lowering + &unreachable_prop::UnreachablePropagation, + &uninhabited_enum_branching::UninhabitedEnumBranching, + &simplify::SimplifyCfg::new("after-uninhabited-enum-branching"), + &inline::Inline, + &generator::StateTransform, ], ); - // Main optimization passes - #[rustfmt::skip] - run_passes( + assert!(body.phase == MirPhase::GeneratorLowering); + + // The main optimizations that we do on MIR. + pm::run_passes( tcx, body, - MirPhase::Optimization, &[ - if mir_opt_level > 0 { optimizations } else { no_optimizations }, - pre_codegen_cleanup, + &remove_storage_markers::RemoveStorageMarkers, + &remove_zsts::RemoveZsts, + &const_goto::ConstGoto, + &remove_unneeded_drops::RemoveUnneededDrops, + &match_branches::MatchBranchSimplification, + // inst combine is after MatchBranchSimplification to clean up Ne(_1, false) + &multiple_return_terminators::MultipleReturnTerminators, + &instcombine::InstCombine, + &separate_const_switch::SeparateConstSwitch, + // FIXME(#70073): This pass is responsible for both optimization as well as some lints. + &const_prop::ConstProp, + &simplify_branches::SimplifyBranches::new("after-const-prop"), + &early_otherwise_branch::EarlyOtherwiseBranch, + &simplify_comparison_integral::SimplifyComparisonIntegral, + &simplify_try::SimplifyArmIdentity, + &simplify_try::SimplifyBranchSame, + &dest_prop::DestinationPropagation, + &simplify_branches::SimplifyBranches::new("final"), + &remove_noop_landing_pads::RemoveNoopLandingPads, + &simplify::SimplifyCfg::new("final"), + &nrvo::RenameReturnPlace, + &const_debuginfo::ConstDebugInfo, + &simplify::SimplifyLocals, + &multiple_return_terminators::MultipleReturnTerminators, + &deduplicate_blocks::DeduplicateBlocks, + // Some cleanup necessary at least for LLVM and potentially other codegen backends. + &add_call_guards::CriticalCallEdges, + &marker::PhaseChange(MirPhase::Optimization), + // Dump the end result for testing and debugging purposes. + &dump_mir::Marker("PreCodegen"), ], ); } diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index f59aaa664f3ad..b4a92064377a5 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -17,8 +17,8 @@ use std::iter; use crate::util::expand_aggregate; use crate::{ - abort_unwinding_calls, add_call_guards, add_moves_for_packed_drops, remove_noop_landing_pads, - run_passes, simplify, + abort_unwinding_calls, add_call_guards, add_moves_for_packed_drops, marker, pass_manager as pm, + remove_noop_landing_pads, simplify, }; use rustc_middle::mir::patch::MirPatch; use rustc_mir_dataflow::elaborate_drops::{self, DropElaborator, DropFlagMode, DropStyle}; @@ -75,17 +75,17 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<' }; debug!("make_shim({:?}) = untransformed {:?}", instance, result); - run_passes( + pm::run_passes( tcx, &mut result, - MirPhase::Const, - &[&[ + &[ &add_moves_for_packed_drops::AddMovesForPackedDrops, &remove_noop_landing_pads::RemoveNoopLandingPads, &simplify::SimplifyCfg::new("make_shim"), &add_call_guards::CriticalCallEdges, &abort_unwinding_calls::AbortUnwindingCalls, - ]], + &marker::PhaseChange(MirPhase::Const), + ], ); debug!("make_shim({:?}) = {:?}", instance, result); From 42e31fffc40342fa269214e0dbc3550f4b64f3d3 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Thu, 2 Dec 2021 14:14:38 -0800 Subject: [PATCH 7/9] Skip shim passes if they've already been run Looks like Generator drop shims already have `post_borrowck_cleanup` run on them. That's a bit surprising, since it means they're getting const- and maybe borrow-checked? This merits further investigation, but for now just preserve the status quo. --- compiler/rustc_mir_transform/src/shim.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index b4a92064377a5..193a9e6ad291f 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -75,6 +75,14 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<' }; debug!("make_shim({:?}) = untransformed {:?}", instance, result); + // In some of the above cases, we seem to be invoking the passes for non-shim MIR bodies. + // If that happens, there's no need to run them again. + // + // FIXME: Is this intentional? + if result.phase >= MirPhase::Const { + return result; + } + pm::run_passes( tcx, &mut result, From dc5feeb1fa2aa45b5a879feff526aad736a63b74 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Thu, 2 Dec 2021 14:38:04 -0800 Subject: [PATCH 8/9] Don't "simplify" during optimizations if optimizations are disabled --- compiler/rustc_mir_transform/src/lib.rs | 20 +++++++++++----- .../rustc_mir_transform/src/pass_manager.rs | 23 +++++++++++++++++++ 2 files changed, 37 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 793e46687d2f1..a7e003a55b400 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -35,7 +35,7 @@ use rustc_span::{Span, Symbol}; #[macro_use] mod pass_manager; -use pass_manager::{self as pm, Lint, MirLint}; +use pass_manager::{self as pm, Lint, MirLint, WithMinOptLevel}; mod abort_unwinding_calls; mod add_call_guards; @@ -438,6 +438,10 @@ fn run_post_borrowck_cleanup_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tc } fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + fn o1(x: T) -> WithMinOptLevel { + WithMinOptLevel(1, x) + } + // Lowering generator control-flow and variables has to happen before we do anything else // to them. We run some optimizations before that, because they may be harder to do on the state // machine than on MIR with async primitives. @@ -450,7 +454,7 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { &normalize_array_len::NormalizeArrayLen, // has to run after `slice::len` lowering &unreachable_prop::UnreachablePropagation, &uninhabited_enum_branching::UninhabitedEnumBranching, - &simplify::SimplifyCfg::new("after-uninhabited-enum-branching"), + &o1(simplify::SimplifyCfg::new("after-uninhabited-enum-branching")), &inline::Inline, &generator::StateTransform, ], @@ -472,17 +476,21 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { &multiple_return_terminators::MultipleReturnTerminators, &instcombine::InstCombine, &separate_const_switch::SeparateConstSwitch, + // // FIXME(#70073): This pass is responsible for both optimization as well as some lints. &const_prop::ConstProp, - &simplify_branches::SimplifyBranches::new("after-const-prop"), + // + // FIXME: The old pass manager ran this only at mir-opt-level >= 1, but + // const-prop runs unconditionally. Should this run unconditionally as well? + &o1(simplify_branches::SimplifyConstCondition::new("after-const-prop")), &early_otherwise_branch::EarlyOtherwiseBranch, &simplify_comparison_integral::SimplifyComparisonIntegral, &simplify_try::SimplifyArmIdentity, &simplify_try::SimplifyBranchSame, &dest_prop::DestinationPropagation, - &simplify_branches::SimplifyBranches::new("final"), - &remove_noop_landing_pads::RemoveNoopLandingPads, - &simplify::SimplifyCfg::new("final"), + &o1(simplify_branches::SimplifyConstCondition::new("final")), + &o1(remove_noop_landing_pads::RemoveNoopLandingPads), + &o1(simplify::SimplifyCfg::new("final")), &nrvo::RenameReturnPlace, &const_debuginfo::ConstDebugInfo, &simplify::SimplifyLocals, diff --git a/compiler/rustc_mir_transform/src/pass_manager.rs b/compiler/rustc_mir_transform/src/pass_manager.rs index ea6f82dfc0610..729b8cae5e47a 100644 --- a/compiler/rustc_mir_transform/src/pass_manager.rs +++ b/compiler/rustc_mir_transform/src/pass_manager.rs @@ -49,6 +49,29 @@ where } } +pub struct WithMinOptLevel(pub u32, pub T); + +impl MirPass<'tcx> for WithMinOptLevel +where + T: MirPass<'tcx>, +{ + fn name(&self) -> Cow<'_, str> { + self.1.name() + } + + fn is_enabled(&self, sess: &Session) -> bool { + sess.mir_opt_level() >= self.0 as usize + } + + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + self.1.run_pass(tcx, body) + } + + fn phase_change(&self) -> Option { + self.1.phase_change() + } +} + pub fn run_passes(tcx: TyCtxt<'tcx>, body: &'mir mut Body<'tcx>, passes: &[&dyn MirPass<'tcx>]) { let start_phase = body.phase; let mut cnt = 0; From 7bc5eca93a585651607d58b3034071c8e9cd6166 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Thu, 2 Dec 2021 16:00:25 -0800 Subject: [PATCH 9/9] `EarlyOtherwiseBranch` requires `-Zunsound-mir-opts` The noopt test never actually ran the pass --- src/test/mir-opt/early_otherwise_branch_noopt.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/mir-opt/early_otherwise_branch_noopt.rs b/src/test/mir-opt/early_otherwise_branch_noopt.rs index aa9ddf485b5aa..d04e2a0429d5c 100644 --- a/src/test/mir-opt/early_otherwise_branch_noopt.rs +++ b/src/test/mir-opt/early_otherwise_branch_noopt.rs @@ -1,4 +1,4 @@ -// compile-flags: -Z mir-opt-level=4 +// compile-flags: -Z mir-opt-level=4 -Zunsound-mir-opts // must not optimize as it does not follow the pattern of // left and right hand side being the same variant