diff --git a/src/librustc/mir/transform.rs b/src/librustc/mir/transform.rs index 14ad413c538..cfe8254d1bb 100644 --- a/src/librustc/mir/transform.rs +++ b/src/librustc/mir/transform.rs @@ -167,24 +167,46 @@ impl DefIdPass for T { /// A manager for MIR passes. #[derive(Clone)] pub struct Passes { - passes: Vec>, pass_hooks: Vec>, - plugin_passes: Vec> + sets: Vec, } +#[derive(Clone)] +struct PassSet { + passes: Vec>, +} + +/// 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); } @@ -198,8 +220,8 @@ impl<'a, 'tcx> Passes { } /// Pushes a built-in pass. - pub fn push_pass(&mut self, pass: T) { - self.passes.push(Rc::new(pass)); + pub fn push_pass(&mut self, set: usize, pass: T) { + self.sets[set].passes.push(Rc::new(pass)); } /// Pushes a pass hook. @@ -207,10 +229,3 @@ impl<'a, 'tcx> Passes { self.pass_hooks.push(Rc::new(hook)); } } - -/// Copies the plugin passes. -impl ::std::iter::Extend> for Passes { - fn extend>>(&mut self, it: I) { - self.plugin_passes.extend(it); - } -} diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 6de61013dfd..0c189853c61 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -25,6 +25,7 @@ use middle::region::{CodeExtent, CodeExtentData}; use middle::resolve_lifetime; use middle::stability; use mir::Mir; +use mir::transform::Passes; use ty::subst::{Kind, Substs}; use ty::ReprOptions; use traits; @@ -47,11 +48,12 @@ use arena::{TypedArena, DroplessArena}; 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; @@ -441,8 +443,11 @@ pub struct GlobalCtxt<'tcx> { pub named_region_map: resolve_lifetime::NamedRegionMap, pub hir: hir_map::Map<'tcx>, + pub maps: maps::Maps<'tcx>, + pub mir_passes: Rc, + // Records the free variables refrenced by every closure // expression. Do not track deps for this, just recompute it from // scratch every time. @@ -712,6 +717,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn create_and_enter(s: &'tcx Session, local_providers: ty::maps::Providers<'tcx>, extern_providers: ty::maps::Providers<'tcx>, + mir_passes: Rc, arenas: &'tcx GlobalArenas<'tcx>, arena: &'tcx DroplessArena, resolutions: ty::Resolutions, @@ -746,6 +752,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { 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()), diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index be344176fd2..89f01226113 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -20,6 +20,7 @@ use rustc::session::search_paths::PathKind; 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; @@ -903,9 +904,43 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, // 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, @@ -971,18 +1006,8 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, } 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, @@ -1040,30 +1065,7 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // 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 {