Skip to content

Commit

Permalink
Auto merge of #91475 - ecstatic-morse:mir-pass-manager3, r=oli-obk
Browse files Browse the repository at this point in the history
Add a MIR pass manager (Taylor's Version)

The final draft of #91386 and #77665.

While the compile-time constraints in #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
  • Loading branch information
bors committed Dec 5, 2021
2 parents 5e93f6e + 7bc5eca commit bdaa901
Show file tree
Hide file tree
Showing 39 changed files with 447 additions and 281 deletions.
4 changes: 4 additions & 0 deletions compiler/rustc_const_eval/src/transform/promote_consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ pub struct PromoteTemps<'tcx> {
}

impl<'tcx> MirPass<'tcx> for PromoteTemps<'tcx> {
fn phase_change(&self) -> Option<MirPhase> {
Some(MirPhase::ConstPromotion)
}

fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
// There's not really any point in promoting errorful MIR.
//
Expand Down
15 changes: 15 additions & 0 deletions compiler/rustc_middle/src/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<MirPhase> {
None
}

fn is_mir_dump_enabled(&self) -> bool {
true
}
}

/// The various "big phases" that MIR goes through.
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_mir_dataflow/src/rustc_peek.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
8 changes: 4 additions & 4 deletions compiler/rustc_mir_transform/src/add_retag.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_mir_transform/src/check_const_item_mutation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_mir_transform/src/check_packed_ref.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,16 @@ 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 };
}

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 };
Expand Down
8 changes: 4 additions & 4 deletions compiler/rustc_mir_transform/src/const_debuginfo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
7 changes: 4 additions & 3 deletions compiler/rustc_mir_transform/src/const_goto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand Down
7 changes: 7 additions & 0 deletions compiler/rustc_mir_transform/src/const_prop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_mir_transform/src/coverage/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
7 changes: 4 additions & 3 deletions compiler/rustc_mir_transform/src/deduplicate_blocks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
15 changes: 6 additions & 9 deletions compiler/rustc_mir_transform/src/dest_prop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
12 changes: 5 additions & 7 deletions compiler/rustc_mir_transform/src/early_otherwise_branch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()));
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_mir_transform/src/elaborate_drops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ use std::fmt;
pub struct ElaborateDrops;

impl<'tcx> MirPass<'tcx> for ElaborateDrops {
fn phase_change(&self) -> Option<MirPhase> {
Some(MirPhase::DropLowering)
}

fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
debug!("elaborate_drops({:?} @ {:?})", body.source, body.span);

Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_mir_transform/src/function_item_references.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_mir_transform/src/generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1232,6 +1232,10 @@ fn create_cases<'tcx>(
}

impl<'tcx> MirPass<'tcx> for StateTransform {
fn phase_change(&self) -> Option<MirPhase> {
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
Expand Down
19 changes: 7 additions & 12 deletions compiler/rustc_mir_transform/src/inline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_mir_transform/src/instcombine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 };
Expand Down
Loading

0 comments on commit bdaa901

Please sign in to comment.