Use new MIR pass manager

This commit is contained in:
Dylan MacKenzie 2021-12-02 14:20:03 -08:00
parent fca642c1c3
commit 71dd5422ac
2 changed files with 79 additions and 174 deletions

View File

@ -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<LocalDefId> {
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<LocalDefId>) -> 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<LocalDefId>) -
// 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"),
],
);
}

View File

@ -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);