/// A manager for MIR passes.
#[derive(Clone)]
pub struct Passes {
- passes: Vec<Rc<Pass>>,
pass_hooks: Vec<Rc<PassHook>>,
- plugin_passes: Vec<Rc<Pass>>
+ sets: Vec<PassSet>,
+}
+
+#[derive(Clone)]
+struct PassSet {
+ passes: Vec<Rc<Pass>>,
}
+/// The number of "pass sets" that we have:
+///
+/// - ready for constant evaluation
+/// - unopt
+/// - optimized
+pub const MIR_PASS_SETS: usize = 3;
+
+/// Run the passes we need to do constant qualification and evaluation.
+pub const MIR_CONST: usize = 0;
+
+/// Run the passes we need to consider the MIR validated and ready for borrowck etc.
+pub const MIR_VALIDATED: usize = 1;
+
+/// Run the passes we need to consider the MIR *optimized*.
+pub const MIR_OPTIMIZED: usize = 2;
+
impl<'a, 'tcx> Passes {
pub fn new() -> Passes {
- let passes = Passes {
- passes: Vec::new(),
+ Passes {
pass_hooks: Vec::new(),
- plugin_passes: Vec::new()
- };
- passes
+ sets: (0..MIR_PASS_SETS).map(|_| PassSet { passes: Vec::new() }).collect(),
+ }
}
- pub fn run_passes(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>) {
+ pub fn run_passes(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, set_index: usize) {
+ let set = &self.sets[set_index];
+
+ let start_num: usize = self.sets[..set_index].iter().map(|s| s.passes.len()).sum();
+
// NB: passes are numbered from 1, since "construction" is zero.
- for (pass, pass_num) in self.plugin_passes.iter().chain(&self.passes).zip(1..) {
+ for (pass, pass_num) in set.passes.iter().zip(start_num + 1..) {
for hook in &self.pass_hooks {
hook.on_mir_pass(tcx, &**pass, pass_num, false);
}
}
/// Pushes a built-in pass.
- pub fn push_pass<T: Pass + 'static>(&mut self, pass: T) {
- self.passes.push(Rc::new(pass));
+ pub fn push_pass<T: Pass + 'static>(&mut self, set: usize, pass: T) {
+ self.sets[set].passes.push(Rc::new(pass));
}
/// Pushes a pass hook.
self.pass_hooks.push(Rc::new(hook));
}
}
-
-/// Copies the plugin passes.
-impl ::std::iter::Extend<Rc<Pass>> for Passes {
- fn extend<I: IntoIterator<Item=Rc<Pass>>>(&mut self, it: I) {
- self.plugin_passes.extend(it);
- }
-}
use middle::resolve_lifetime;
use middle::stability;
use mir::Mir;
+use mir::transform::Passes;
use ty::subst::{Kind, Substs};
use ty::ReprOptions;
use traits;
use rustc_data_structures::indexed_vec::IndexVec;
use std::borrow::Borrow;
use std::cell::{Cell, RefCell};
+use std::cmp::Ordering;
use std::hash::{Hash, Hasher};
use std::mem;
use std::ops::Deref;
use std::iter;
-use std::cmp::Ordering;
+use std::rc::Rc;
use syntax::abi;
use syntax::ast::{self, Name, NodeId};
use syntax::attr;
pub named_region_map: resolve_lifetime::NamedRegionMap,
pub hir: hir_map::Map<'tcx>,
+
pub maps: maps::Maps<'tcx>,
+ pub mir_passes: Rc<Passes>,
+
// Records the free variables refrenced by every closure
// expression. Do not track deps for this, just recompute it from
// scratch every time.
pub fn create_and_enter<F, R>(s: &'tcx Session,
local_providers: ty::maps::Providers<'tcx>,
extern_providers: ty::maps::Providers<'tcx>,
+ mir_passes: Rc<Passes>,
arenas: &'tcx GlobalArenas<'tcx>,
arena: &'tcx DroplessArena,
resolutions: ty::Resolutions,
fulfilled_predicates: RefCell::new(fulfilled_predicates),
hir: hir,
maps: maps::Maps::new(dep_graph, providers),
+ mir_passes,
freevars: RefCell::new(resolutions.freevars),
maybe_unused_trait_imports: resolutions.maybe_unused_trait_imports,
rcache: RefCell::new(FxHashMap()),
use rustc::lint;
use rustc::middle::{self, dependency_format, stability, reachable};
use rustc::middle::privacy::AccessLevels;
+use rustc::mir::transform::{MIR_CONST, MIR_VALIDATED, MIR_OPTIMIZED};
use rustc::ty::{self, TyCtxt, Resolutions, GlobalArenas};
use rustc::util::common::time;
use rustc::util::nodemap::NodeSet;
// FIXME(eddyb) get rid of this once we replace const_eval with miri.
rustc_const_eval::provide(&mut extern_providers);
+ // Setup the MIR passes that we want to run.
+ let mut passes = sess.mir_passes.borrow().clone();
+ passes.push_hook(mir::transform::dump_mir::DumpMir);
+
+ // What we need to do constant evaluation.
+ passes.push_pass(MIR_CONST, mir::transform::simplify::SimplifyCfg::new("initial"));
+ passes.push_pass(MIR_CONST, mir::transform::type_check::TypeckMir);
+
+ // What we need to run borrowck etc.
+ passes.push_pass(MIR_VALIDATED, mir::transform::qualify_consts::QualifyAndPromoteConstants);
+ passes.push_pass(MIR_VALIDATED, mir::transform::simplify_branches::SimplifyBranches::new("initial"));
+ passes.push_pass(MIR_VALIDATED, mir::transform::simplify::SimplifyCfg::new("qualify-consts"));
+
+ // Optimizations begin.
+ passes.push_pass(MIR_OPTIMIZED, mir::transform::no_landing_pads::NoLandingPads);
+ passes.push_pass(MIR_OPTIMIZED, mir::transform::simplify::SimplifyCfg::new("no-landing-pads"));
+
+ // From here on out, regions are gone.
+ passes.push_pass(MIR_OPTIMIZED, mir::transform::erase_regions::EraseRegions);
+ passes.push_pass(MIR_OPTIMIZED, mir::transform::add_call_guards::AddCallGuards);
+ passes.push_pass(MIR_OPTIMIZED, borrowck::ElaborateDrops);
+ passes.push_pass(MIR_OPTIMIZED, mir::transform::no_landing_pads::NoLandingPads);
+ passes.push_pass(MIR_OPTIMIZED, mir::transform::simplify::SimplifyCfg::new("elaborate-drops"));
+
+ // No lifetime analysis based on borrowing can be done from here on out.
+ passes.push_pass(MIR_OPTIMIZED, mir::transform::inline::Inline);
+ passes.push_pass(MIR_OPTIMIZED, mir::transform::instcombine::InstCombine);
+ passes.push_pass(MIR_OPTIMIZED, mir::transform::deaggregator::Deaggregator);
+ passes.push_pass(MIR_OPTIMIZED, mir::transform::copy_prop::CopyPropagation);
+ passes.push_pass(MIR_OPTIMIZED, mir::transform::simplify::SimplifyLocals);
+ passes.push_pass(MIR_OPTIMIZED, mir::transform::add_call_guards::AddCallGuards);
+ passes.push_pass(MIR_OPTIMIZED, mir::transform::dump_mir::Marker("PreTrans"));
+
TyCtxt::create_and_enter(sess,
local_providers,
extern_providers,
+ Rc::new(passes),
arenas,
arena,
resolutions,
}
time(time_passes, "MIR cleanup and validation", || {
- let mut passes = sess.mir_passes.borrow_mut();
- // Push all the built-in validation passes.
- // NB: if you’re adding an *optimisation* it ought to go to another set of passes
- // in stage 4 below.
- passes.push_hook(mir::transform::dump_mir::DumpMir);
- passes.push_pass(mir::transform::simplify::SimplifyCfg::new("initial"));
- passes.push_pass(mir::transform::type_check::TypeckMir);
- passes.push_pass(mir::transform::qualify_consts::QualifyAndPromoteConstants);
- passes.push_pass(mir::transform::simplify_branches::SimplifyBranches::new("initial"));
- passes.push_pass(mir::transform::simplify::SimplifyCfg::new("qualify-consts"));
- // And run everything.
- passes.run_passes(tcx);
+ tcx.mir_passes.run_passes(tcx, MIR_CONST);
+ tcx.mir_passes.run_passes(tcx, MIR_VALIDATED);
});
time(time_passes,
// Run the passes that transform the MIR into a more suitable form for translation to LLVM
// code.
time(time_passes, "MIR optimisations", || {
- let mut passes = ::rustc::mir::transform::Passes::new();
- passes.push_hook(mir::transform::dump_mir::DumpMir);
- passes.push_pass(mir::transform::no_landing_pads::NoLandingPads);
- passes.push_pass(mir::transform::simplify::SimplifyCfg::new("no-landing-pads"));
-
- // From here on out, regions are gone.
- passes.push_pass(mir::transform::erase_regions::EraseRegions);
-
- passes.push_pass(mir::transform::add_call_guards::AddCallGuards);
- passes.push_pass(borrowck::ElaborateDrops);
- passes.push_pass(mir::transform::no_landing_pads::NoLandingPads);
- passes.push_pass(mir::transform::simplify::SimplifyCfg::new("elaborate-drops"));
-
- // No lifetime analysis based on borrowing can be done from here on out.
- passes.push_pass(mir::transform::inline::Inline);
- passes.push_pass(mir::transform::instcombine::InstCombine);
- passes.push_pass(mir::transform::deaggregator::Deaggregator);
- passes.push_pass(mir::transform::copy_prop::CopyPropagation);
-
- passes.push_pass(mir::transform::simplify::SimplifyLocals);
- passes.push_pass(mir::transform::add_call_guards::AddCallGuards);
- passes.push_pass(mir::transform::dump_mir::Marker("PreTrans"));
-
- passes.run_passes(tcx);
+ tcx.mir_passes.run_passes(tcx, MIR_OPTIMIZED);
});
if tcx.sess.opts.debugging_opts.mir_stats {