diff --git a/src/librustc/dep_graph/mod.rs b/src/librustc/dep_graph/mod.rs index f4df6994e04..821217d7582 100644 --- a/src/librustc/dep_graph/mod.rs +++ b/src/librustc/dep_graph/mod.rs @@ -10,6 +10,7 @@ use self::thread::{DepGraphThreadData, DepMessage}; use middle::def_id::DefId; +use syntax::ast::NodeId; use middle::ty::TyCtxt; use rustc_front::hir; use rustc_front::intravisit::Visitor; @@ -71,6 +72,7 @@ pub enum DepNode { IntrinsicCheck(DefId), MatchCheck(DefId), MirMapConstruction(DefId), + MirTypeck(NodeId), BorrowCheck(DefId), RvalueCheck(DefId), Reachability, diff --git a/src/librustc/mir/mir_map.rs b/src/librustc/mir/mir_map.rs index 933621b765f..1a34699aff4 100644 --- a/src/librustc/mir/mir_map.rs +++ b/src/librustc/mir/mir_map.rs @@ -8,31 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use dep_graph::DepNode; use util::nodemap::NodeMap; use mir::repr::Mir; -use mir::transform::MirPass; -use middle::ty::{self, TyCtxt}; -use middle::infer; pub struct MirMap<'tcx> { pub map: NodeMap>, } - -impl<'tcx> MirMap<'tcx> { - pub fn run_passes(&mut self, passes: &mut [Box], tcx: &TyCtxt<'tcx>) { - if passes.is_empty() { return; } - - for (&id, mir) in &mut self.map { - let did = tcx.map.local_def_id(id); - let _task = tcx.dep_graph.in_task(DepNode::MirMapConstruction(did)); - - let param_env = ty::ParameterEnvironment::for_item(tcx, id); - let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, Some(param_env)); - - for pass in &mut *passes { - pass.run_on_mir(mir, &infcx) - } - } - } -} diff --git a/src/librustc/mir/repr.rs b/src/librustc/mir/repr.rs index 4556611df59..127cc96859a 100644 --- a/src/librustc/mir/repr.rs +++ b/src/librustc/mir/repr.rs @@ -207,7 +207,7 @@ impl Debug for BasicBlock { } /////////////////////////////////////////////////////////////////////////// -// BasicBlock and Terminator +// BasicBlockData and Terminator #[derive(Clone, Debug, RustcEncodable, RustcDecodable)] pub struct BasicBlockData<'tcx> { diff --git a/src/librustc/mir/transform.rs b/src/librustc/mir/transform.rs index cc417f5a99e..afcb5b95631 100644 --- a/src/librustc/mir/transform.rs +++ b/src/librustc/mir/transform.rs @@ -8,9 +8,68 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use mir::mir_map::MirMap; use mir::repr::Mir; -use middle::infer::InferCtxt; +use middle::ty::TyCtxt; +use syntax::ast::NodeId; -pub trait MirPass { - fn run_on_mir<'a, 'tcx>(&mut self, mir: &mut Mir<'tcx>, infcx: &InferCtxt<'a, 'tcx>); +/// Various information about pass. +pub trait Pass { + // fn name() for printouts of various sorts? + // fn should_run(Session) to check if pass should run? +} + +/// A pass which inspects the whole MirMap. +pub trait MirMapPass<'tcx>: Pass { + fn run_pass(&mut self, cx: &TyCtxt<'tcx>, map: &mut MirMap<'tcx>); +} + +/// A pass which inspects Mir of functions in isolation. +pub trait MirPass<'tcx>: Pass { + fn run_pass(&mut self, cx: &TyCtxt<'tcx>, id: NodeId, mir: &mut Mir<'tcx>); +} + +impl<'tcx, T: MirPass<'tcx>> MirMapPass<'tcx> for T { + fn run_pass(&mut self, tcx: &TyCtxt<'tcx>, map: &mut MirMap<'tcx>) { + for (&id, mir) in &mut map.map { + MirPass::run_pass(self, tcx, id, mir); + } + } +} + +/// A manager for MIR passes. +pub struct Passes { + passes: Vec MirMapPass<'tcx>>>, + plugin_passes: Vec MirMapPass<'tcx>>> +} + +impl Passes { + pub fn new() -> Passes { + let passes = Passes { + passes: Vec::new(), + plugin_passes: Vec::new() + }; + passes + } + + pub fn run_passes<'tcx>(&mut self, pcx: &TyCtxt<'tcx>, map: &mut MirMap<'tcx>) { + for pass in &mut self.plugin_passes { + pass.run_pass(pcx, map); + } + for pass in &mut self.passes { + pass.run_pass(pcx, map); + } + } + + /// Pushes a built-in pass. + pub fn push_pass(&mut self, pass: Box MirMapPass<'a>>) { + self.passes.push(pass); + } +} + +/// Copies the plugin passes. +impl ::std::iter::Extend MirMapPass<'a>>> for Passes { + fn extend MirMapPass<'a>>>>(&mut self, it: I) { + self.plugin_passes.extend(it); + } } diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index d2f8d3f09fd..b198eda1812 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -13,7 +13,7 @@ use middle::cstore::CrateStore; use middle::dependency_format; use session::search_paths::PathKind; use util::nodemap::{NodeMap, FnvHashMap}; -use mir::transform::MirPass; +use mir::transform as mir_pass; use syntax::ast::{NodeId, NodeIdAssigner, Name}; use syntax::codemap::{Span, MultiSpan}; @@ -60,7 +60,7 @@ pub struct Session { pub lint_store: RefCell, pub lints: RefCell>>, pub plugin_llvm_passes: RefCell>, - pub plugin_mir_passes: RefCell>>, + pub mir_passes: RefCell, pub plugin_attributes: RefCell>, pub crate_types: RefCell>, pub dependency_formats: RefCell, @@ -477,7 +477,7 @@ pub fn build_session_(sopts: config::Options, lint_store: RefCell::new(lint::LintStore::new()), lints: RefCell::new(NodeMap()), plugin_llvm_passes: RefCell::new(Vec::new()), - plugin_mir_passes: RefCell::new(Vec::new()), + mir_passes: RefCell::new(mir_pass::Passes::new()), plugin_attributes: RefCell::new(Vec::new()), crate_types: RefCell::new(Vec::new()), dependency_formats: RefCell::new(FnvHashMap()), diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 55ec9d82a2e..46e06d21c7c 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -568,7 +568,7 @@ pub fn phase_2_configure_and_expand(sess: &Session, } *sess.plugin_llvm_passes.borrow_mut() = llvm_passes; - *sess.plugin_mir_passes.borrow_mut() = mir_passes; + sess.mir_passes.borrow_mut().extend(mir_passes); *sess.plugin_attributes.borrow_mut() = attributes.clone(); })); @@ -865,9 +865,19 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, "MIR dump", || mir::mir_map::build_mir_for_crate(tcx)); - time(time_passes, - "MIR passes", - || mir_map.run_passes(&mut sess.plugin_mir_passes.borrow_mut(), tcx)); + time(time_passes, "MIR passes", || { + let mut passes = sess.mir_passes.borrow_mut(); + // Push all the built-in passes. + passes.push_pass(box mir::transform::remove_dead_blocks::RemoveDeadBlocks); + passes.push_pass(box mir::transform::type_check::TypeckMir); + passes.push_pass(box mir::transform::simplify_cfg::SimplifyCfg); + // Late passes + passes.push_pass(box mir::transform::no_landing_pads::NoLandingPads); + passes.push_pass(box mir::transform::remove_dead_blocks::RemoveDeadBlocks); + passes.push_pass(box mir::transform::erase_regions::EraseRegions); + // And run everything. + passes.run_passes(tcx, &mut mir_map); + }); time(time_passes, "borrow checking", @@ -916,9 +926,8 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, } /// Run the translation phase to LLVM, after which the AST and analysis can -/// be discarded. pub fn phase_4_translate_to_llvm<'tcx>(tcx: &TyCtxt<'tcx>, - mut mir_map: MirMap<'tcx>, + mir_map: MirMap<'tcx>, analysis: ty::CrateAnalysis) -> trans::CrateTranslation { let time_passes = tcx.sess.time_passes(); @@ -927,10 +936,6 @@ pub fn phase_4_translate_to_llvm<'tcx>(tcx: &TyCtxt<'tcx>, "resolving dependency formats", || dependency_format::calculate(&tcx.sess)); - time(time_passes, - "erasing regions from MIR", - || mir::transform::erase_regions::erase_regions(tcx, &mut mir_map)); - // Option dance to work around the lack of stack once closures. time(time_passes, "translation", diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index 9f9824eae35..4792fa72831 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -31,6 +31,7 @@ use rustc_resolve as resolve; use rustc_metadata::cstore::CStore; use rustc_mir::pretty::write_mir_pretty; +use rustc_mir::graphviz::write_mir_graphviz; use syntax::ast::{self, BlockCheckMode}; use syntax::codemap; @@ -44,6 +45,7 @@ use graphviz as dot; use std::fs::File; use std::io::{self, Write}; +use std::iter; use std::option; use std::path::PathBuf; use std::str::FromStr; @@ -80,6 +82,7 @@ pub enum PpMode { PpmHir(PpSourceMode), PpmFlowGraph(PpFlowGraphMode), PpmMir, + PpmMirCFG, } pub fn parse_pretty(sess: &Session, @@ -100,6 +103,7 @@ pub fn parse_pretty(sess: &Session, ("hir,identified", true) => PpmHir(PpmIdentified), ("hir,typed", true) => PpmHir(PpmTyped), ("mir", true) => PpmMir, + ("mir-cfg", true) => PpmMirCFG, ("flowgraph", true) => PpmFlowGraph(PpFlowGraphMode::Default), ("flowgraph,unlabelled", true) => PpmFlowGraph(PpFlowGraphMode::UnlabelledEdges), _ => { @@ -574,6 +578,7 @@ fn needs_ast_map(ppm: &PpMode, opt_uii: &Option) -> bool { PpmSource(PpmExpandedHygiene) | PpmHir(_) | PpmMir | + PpmMirCFG | PpmFlowGraph(_) => true, PpmSource(PpmTyped) => panic!("invalid state"), } @@ -590,6 +595,7 @@ fn needs_expansion(ppm: &PpMode) -> bool { PpmSource(PpmExpandedHygiene) | PpmHir(_) | PpmMir | + PpmMirCFG | PpmFlowGraph(_) => true, PpmSource(PpmTyped) => panic!("invalid state"), } @@ -807,9 +813,15 @@ pub fn pretty_print_input(sess: Session, }) } - (PpmMir, None) => { - debug!("pretty printing MIR for whole crate"); - let ast_map = ast_map.expect("--unpretty mir missing ast_map"); + (pp_type@PpmMir, uii) | (pp_type@PpmMirCFG, uii) => { + let ast_map = ast_map.expect("--unpretty missing ast_map"); + let nodeid = if let Some(uii) = uii { + debug!("pretty printing MIR for {:?}", uii); + Some(uii.to_one_node_id("--unpretty", &sess, &ast_map)) + } else { + debug!("pretty printing MIR for whole crate"); + None + }; abort_on_err(driver::phase_3_run_analysis_passes(&sess, &cstore, ast_map, @@ -818,38 +830,25 @@ pub fn pretty_print_input(sess: Session, resolve::MakeGlobMap::No, |tcx, mir_map, _, _| { if let Some(mir_map) = mir_map { - for (nodeid, mir) in &mir_map.map { - try!(writeln!(out, "MIR for {}", tcx.map.node_to_string(*nodeid))); - try!(write_mir_pretty(mir, &mut out)); + if let Some(nodeid) = nodeid { + let mir = mir_map.map.get(&nodeid).unwrap_or_else(|| { + sess.fatal(&format!("no MIR map entry for node {}", nodeid)) + }); + try!(match pp_type { + PpmMir => write_mir_pretty(tcx, iter::once((&nodeid, mir)), &mut out), + _ => write_mir_graphviz(tcx, iter::once((&nodeid, mir)), &mut out) + }); + } else { + try!(match pp_type { + PpmMir => write_mir_pretty(tcx, mir_map.map.iter(), &mut out), + _ => write_mir_graphviz(tcx, mir_map.map.iter(), &mut out) + }); } } Ok(()) }), &sess) } - (PpmMir, Some(uii)) => { - debug!("pretty printing MIR for {:?}", uii); - let ast_map = ast_map.expect("--unpretty mir missing ast_map"); - let nodeid = uii.to_one_node_id("--unpretty", &sess, &ast_map); - - abort_on_err(driver::phase_3_run_analysis_passes(&sess, - &cstore, - ast_map, - &arenas, - &id, - resolve::MakeGlobMap::No, - |tcx, mir_map, _, _| { - if let Some(mir_map) = mir_map { - try!(writeln!(out, "MIR for {}", tcx.map.node_to_string(nodeid))); - let mir = mir_map.map.get(&nodeid).unwrap_or_else(|| { - sess.fatal(&format!("no MIR map entry for node {}", nodeid)) - }); - try!(write_mir_pretty(mir, &mut out)); - } - Ok(()) - }), &sess) - } - (PpmFlowGraph(mode), opt_uii) => { debug!("pretty printing flow graph for {:?}", opt_uii); let uii = opt_uii.unwrap_or_else(|| { diff --git a/src/librustc_mir/graphviz.rs b/src/librustc_mir/graphviz.rs index 1b8fe650558..f705c0591b5 100644 --- a/src/librustc_mir/graphviz.rs +++ b/src/librustc_mir/graphviz.rs @@ -13,30 +13,34 @@ use rustc::mir::repr::*; use rustc::middle::ty; use std::fmt::Debug; use std::io::{self, Write}; +use syntax::ast::NodeId; -/// Write a graphviz DOT graph for the given MIR. -pub fn write_mir_graphviz(mir: &Mir, w: &mut W) -> io::Result<()> { - try!(writeln!(w, "digraph Mir {{")); +/// Write a graphviz DOT graph of a list of MIRs. +pub fn write_mir_graphviz<'a, 't, W, I>(tcx: &ty::TyCtxt<'t>, iter: I, w: &mut W) -> io::Result<()> +where W: Write, I: Iterator)> { + for (&nodeid, mir) in iter { + try!(writeln!(w, "digraph Mir_{} {{", nodeid)); - // Global graph properties - try!(writeln!(w, r#" graph [fontname="monospace"];"#)); - try!(writeln!(w, r#" node [fontname="monospace"];"#)); - try!(writeln!(w, r#" edge [fontname="monospace"];"#)); + // Global graph properties + try!(writeln!(w, r#" graph [fontname="monospace"];"#)); + try!(writeln!(w, r#" node [fontname="monospace"];"#)); + try!(writeln!(w, r#" edge [fontname="monospace"];"#)); - // Graph label - try!(write_graph_label(mir, w)); + // Graph label + try!(write_graph_label(tcx, nodeid, mir, w)); - // Nodes - for block in mir.all_basic_blocks() { - try!(write_node(block, mir, w)); + // Nodes + for block in mir.all_basic_blocks() { + try!(write_node(block, mir, w)); + } + + // Edges + for source in mir.all_basic_blocks() { + try!(write_edges(source, mir, w)); + } + try!(writeln!(w, "}}")) } - - // Edges - for source in mir.all_basic_blocks() { - try!(write_edges(source, mir, w)); - } - - writeln!(w, "}}") + Ok(()) } /// Write a graphviz DOT node for the given basic block. @@ -84,8 +88,9 @@ fn write_edges(source: BasicBlock, mir: &Mir, w: &mut W) -> io::Result /// Write the graphviz DOT label for the overall graph. This is essentially a block of text that /// will appear below the graph, showing the type of the `fn` this MIR represents and the types of /// all the variables and temporaries. -fn write_graph_label(mir: &Mir, w: &mut W) -> io::Result<()> { - try!(write!(w, " label=(tcx: &ty::TyCtxt, nid: NodeId, mir: &Mir, w: &mut W) +-> io::Result<()> { + try!(write!(w, " label= Visitor<'tcx> for InnerDump<'a,'m,'tcx> { body: &'tcx hir::Block, span: Span, id: ast::NodeId) { - let (prefix, implicit_arg_tys) = match fk { - intravisit::FnKind::Closure => - (format!("{}-", id), vec![closure_self_ty(&self.tcx, id, body.id)]), - _ => - (format!(""), vec![]), + let implicit_arg_tys = if let intravisit::FnKind::Closure = fk { + vec![closure_self_ty(&self.tcx, id, body.id)] + } else { + vec![] }; let param_env = ty::ParameterEnvironment::for_item(self.tcx, id); - let infcx = infer::new_infer_ctxt(self.tcx, &self.tcx.tables, Some(param_env)); - match build_mir(Cx::new(&infcx), implicit_arg_tys, id, span, decl, body) { - Ok(mut mir) => { - clear_dead_blocks::ClearDeadBlocks::new().run_on_mir(&mut mir, &infcx); - type_check::TypeckMir::new().run_on_mir(&mut mir, &infcx); - no_landing_pads::NoLandingPads.run_on_mir(&mut mir, &infcx); - if self.tcx.sess.opts.mir_opt_level > 0 { - simplify_cfg::SimplifyCfg::new().run_on_mir(&mut mir, &infcx); - } - let meta_item_list = self.attr - .iter() - .flat_map(|a| a.meta_item_list()) - .flat_map(|l| l.iter()); - for item in meta_item_list { - if item.check_name("graphviz") || item.check_name("pretty") { - match item.value_str() { - Some(s) => { - let filename = format!("{}{}", prefix, s); - let result = File::create(&filename).and_then(|ref mut output| { - if item.check_name("graphviz") { - graphviz::write_mir_graphviz(&mir, output) - } else { - pretty::write_mir_pretty(&mir, output) - } - }); - - if let Err(e) = result { - self.tcx.sess.span_fatal( - item.span, - &format!("Error writing MIR {} results to `{}`: {}", - item.name(), filename, e)); - } - } - None => { - self.tcx.sess.span_err( - item.span, - &format!("{} attribute requires a path", item.name())); - } - } - } - } - - let previous = self.map.map.insert(id, mir); - assert!(previous.is_none()); - } + Ok(mir) => assert!(self.map.map.insert(id, mir).is_none()), Err(ErrorReported) => {} } diff --git a/src/librustc_mir/pretty.rs b/src/librustc_mir/pretty.rs index ea4036a4d37..c3fe4df40b5 100644 --- a/src/librustc_mir/pretty.rs +++ b/src/librustc_mir/pretty.rs @@ -11,19 +11,22 @@ use rustc::mir::repr::*; use rustc::middle::ty; use std::io::{self, Write}; +use syntax::ast::NodeId; const INDENT: &'static str = " "; /// Write out a human-readable textual representation for the given MIR. -pub fn write_mir_pretty(mir: &Mir, w: &mut W) -> io::Result<()> { - try!(write_mir_intro(mir, w)); - - // Nodes - for block in mir.all_basic_blocks() { - try!(write_basic_block(block, mir, w)); +pub fn write_mir_pretty<'a, 't, W, I>(tcx: &ty::TyCtxt<'t>, iter: I, w: &mut W) -> io::Result<()> +where W: Write, I: Iterator)> { + for (&nodeid, mir) in iter { + try!(write_mir_intro(tcx, nodeid, mir, w)); + // Nodes + for block in mir.all_basic_blocks() { + try!(write_basic_block(block, mir, w)); + } + try!(writeln!(w, "}}")) } - - writeln!(w, "}}") + Ok(()) } /// Write out a human-readable textual representation for the given basic block. @@ -46,8 +49,10 @@ fn write_basic_block(block: BasicBlock, mir: &Mir, w: &mut W) -> io::R /// Write out a human-readable textual representation of the MIR's `fn` type and the types of its /// local variables (both user-defined bindings and compiler temporaries). -fn write_mir_intro(mir: &Mir, w: &mut W) -> io::Result<()> { - try!(write!(w, "fn(")); +fn write_mir_intro(tcx: &ty::TyCtxt, nid: NodeId, mir: &Mir, w: &mut W) +-> io::Result<()> { + + try!(write!(w, "fn {}(", tcx.map.path_to_string(nid))); // fn argument types. for (i, arg) in mir.arg_decls.iter().enumerate() { diff --git a/src/librustc_mir/transform/erase_regions.rs b/src/librustc_mir/transform/erase_regions.rs index 53d88709add..1920bd552ec 100644 --- a/src/librustc_mir/transform/erase_regions.rs +++ b/src/librustc_mir/transform/erase_regions.rs @@ -15,13 +15,8 @@ use rustc::middle::ty::{self, TyCtxt}; use rustc::mir::repr::*; use rustc::mir::visit::MutVisitor; -use rustc::mir::mir_map::MirMap; - -pub fn erase_regions<'tcx>(tcx: &TyCtxt<'tcx>, mir_map: &mut MirMap<'tcx>) { - for (_, mir) in &mut mir_map.map { - EraseRegionsVisitor::new(tcx).visit_mir(mir); - } -} +use rustc::mir::transform::{MirPass, Pass}; +use syntax::ast::NodeId; struct EraseRegionsVisitor<'a, 'tcx: 'a> { tcx: &'a TyCtxt<'tcx>, @@ -123,3 +118,13 @@ impl<'a, 'tcx> MutVisitor<'tcx> for EraseRegionsVisitor<'a, 'tcx> { self.super_constant(constant); } } + +pub struct EraseRegions; + +impl Pass for EraseRegions {} + +impl<'tcx> MirPass<'tcx> for EraseRegions { + fn run_pass(&mut self, tcx: &TyCtxt<'tcx>, _: NodeId, mir: &mut Mir<'tcx>) { + EraseRegionsVisitor::new(tcx).visit_mir(mir); + } +} diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs index adca68114fd..57690caeccb 100644 --- a/src/librustc_mir/transform/mod.rs +++ b/src/librustc_mir/transform/mod.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -pub mod clear_dead_blocks; +pub mod remove_dead_blocks; pub mod simplify_cfg; pub mod erase_regions; pub mod no_landing_pads; diff --git a/src/librustc_mir/transform/no_landing_pads.rs b/src/librustc_mir/transform/no_landing_pads.rs index e2c93bd4e87..9caee36e44a 100644 --- a/src/librustc_mir/transform/no_landing_pads.rs +++ b/src/librustc_mir/transform/no_landing_pads.rs @@ -11,10 +11,11 @@ //! This pass removes the unwind branch of all the terminators when the no-landing-pads option is //! specified. -use rustc::middle::infer; +use rustc::middle::ty::TyCtxt; use rustc::mir::repr::*; use rustc::mir::visit::MutVisitor; -use rustc::mir::transform::MirPass; +use rustc::mir::transform::{Pass, MirPass}; +use syntax::ast::NodeId; pub struct NoLandingPads; @@ -40,11 +41,12 @@ impl<'tcx> MutVisitor<'tcx> for NoLandingPads { } } -impl MirPass for NoLandingPads { - fn run_on_mir<'a, 'tcx>(&mut self, mir: &mut Mir<'tcx>, - infcx: &infer::InferCtxt<'a, 'tcx>) { - if infcx.tcx.sess.no_landing_pads() { +impl<'tcx> MirPass<'tcx> for NoLandingPads { + fn run_pass(&mut self, tcx: &TyCtxt<'tcx>, _: NodeId, mir: &mut Mir<'tcx>) { + if tcx.sess.no_landing_pads() { self.visit_mir(mir); } } } + +impl Pass for NoLandingPads {} diff --git a/src/librustc_mir/transform/clear_dead_blocks.rs b/src/librustc_mir/transform/remove_dead_blocks.rs similarity index 52% rename from src/librustc_mir/transform/clear_dead_blocks.rs rename to src/librustc_mir/transform/remove_dead_blocks.rs index b35d8c08f5d..4513aeef86d 100644 --- a/src/librustc_mir/transform/clear_dead_blocks.rs +++ b/src/librustc_mir/transform/remove_dead_blocks.rs @@ -32,50 +32,56 @@ //! this pass just replaces the blocks with empty "return" blocks //! and does not renumber anything. -use rustc::middle::infer; +use rustc_data_structures::bitvec::BitVector; +use rustc::middle::ty::TyCtxt; use rustc::mir::repr::*; -use rustc::mir::transform::MirPass; +use rustc::mir::transform::{Pass, MirPass}; +use syntax::ast::NodeId; -pub struct ClearDeadBlocks; - -impl ClearDeadBlocks { - pub fn new() -> ClearDeadBlocks { - ClearDeadBlocks - } - - fn clear_dead_blocks(&self, mir: &mut Mir) { - let mut seen = vec![false; mir.basic_blocks.len()]; +pub struct RemoveDeadBlocks; +impl<'tcx> MirPass<'tcx> for RemoveDeadBlocks { + fn run_pass(&mut self, _: &TyCtxt<'tcx>, _: NodeId, mir: &mut Mir<'tcx>) { + let mut seen = BitVector::new(mir.basic_blocks.len()); // These blocks are always required. - seen[START_BLOCK.index()] = true; - seen[END_BLOCK.index()] = true; + seen.insert(START_BLOCK.index()); + seen.insert(END_BLOCK.index()); - let mut worklist = vec![START_BLOCK]; + let mut worklist = Vec::with_capacity(4); + worklist.push(START_BLOCK); while let Some(bb) = worklist.pop() { for succ in mir.basic_block_data(bb).terminator().successors().iter() { - if !seen[succ.index()] { - seen[succ.index()] = true; + if seen.insert(succ.index()) { worklist.push(*succ); } } } + retain_basic_blocks(mir, &seen); + } +} - for (n, (block, seen)) in mir.basic_blocks.iter_mut().zip(seen).enumerate() { - if !seen { - info!("clearing block #{}: {:?}", n, block); - *block = BasicBlockData { - statements: vec![], - terminator: Some(Terminator::Return), - is_cleanup: false - }; - } +impl Pass for RemoveDeadBlocks {} + +/// Mass removal of basic blocks to keep the ID-remapping cheap. +fn retain_basic_blocks(mir: &mut Mir, keep: &BitVector) { + let num_blocks = mir.basic_blocks.len(); + + let mut replacements: Vec<_> = (0..num_blocks).map(BasicBlock::new).collect(); + let mut used_blocks = 0; + for alive_index in keep.iter() { + replacements[alive_index] = BasicBlock::new(used_blocks); + if alive_index != used_blocks { + // Swap the next alive block data with the current available slot. Since alive_index is + // non-decreasing this is a valid operation. + mir.basic_blocks.swap(alive_index, used_blocks); + } + used_blocks += 1; + } + mir.basic_blocks.truncate(used_blocks); + + for bb in mir.all_basic_blocks() { + for target in mir.basic_block_data_mut(bb).terminator_mut().successors_mut() { + *target = replacements[target.index()]; } } } - -impl MirPass for ClearDeadBlocks { - fn run_on_mir<'a, 'tcx>(&mut self, mir: &mut Mir<'tcx>, _: &infer::InferCtxt<'a, 'tcx>) - { - self.clear_dead_blocks(mir); - } -} diff --git a/src/librustc_mir/transform/simplify_cfg.rs b/src/librustc_mir/transform/simplify_cfg.rs index 785e6db57a5..84410bdc57c 100644 --- a/src/librustc_mir/transform/simplify_cfg.rs +++ b/src/librustc_mir/transform/simplify_cfg.rs @@ -8,11 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use rustc_data_structures::bitvec::BitVector; use rustc::middle::const_eval::ConstVal; -use rustc::middle::infer; +use rustc::middle::ty::TyCtxt; use rustc::mir::repr::*; -use rustc::mir::transform::MirPass; +use rustc::mir::transform::{MirPass, Pass}; +use syntax::ast::NodeId; + +use super::remove_dead_blocks::RemoveDeadBlocks; pub struct SimplifyCfg; @@ -21,26 +23,7 @@ impl SimplifyCfg { SimplifyCfg } - fn remove_dead_blocks(&self, mir: &mut Mir) { - let mut seen = BitVector::new(mir.basic_blocks.len()); - // These blocks are always required. - seen.insert(START_BLOCK.index()); - seen.insert(END_BLOCK.index()); - - let mut worklist = Vec::with_capacity(4); - worklist.push(START_BLOCK); - while let Some(bb) = worklist.pop() { - for succ in mir.basic_block_data(bb).terminator().successors().iter() { - if seen.insert(succ.index()) { - worklist.push(*succ); - } - } - } - retain_basic_blocks(mir, &seen); - } - fn remove_goto_chains(&self, mir: &mut Mir) -> bool { - // Find the target at the end of the jump chain, return None if there is a loop fn final_target(mir: &Mir, mut target: BasicBlock) -> Option { // Keep track of already seen blocks to detect loops @@ -118,39 +101,17 @@ impl SimplifyCfg { } } -impl MirPass for SimplifyCfg { - fn run_on_mir<'a, 'tcx>(&mut self, mir: &mut Mir<'tcx>, _: &infer::InferCtxt<'a, 'tcx>) { +impl<'tcx> MirPass<'tcx> for SimplifyCfg { + fn run_pass(&mut self, tcx: &TyCtxt<'tcx>, id: NodeId, mir: &mut Mir<'tcx>) { let mut changed = true; while changed { changed = self.simplify_branches(mir); changed |= self.remove_goto_chains(mir); - self.remove_dead_blocks(mir); + RemoveDeadBlocks.run_pass(tcx, id, mir); } // FIXME: Should probably be moved into some kind of pass manager mir.basic_blocks.shrink_to_fit(); } } -/// Mass removal of basic blocks to keep the ID-remapping cheap. -fn retain_basic_blocks(mir: &mut Mir, keep: &BitVector) { - let num_blocks = mir.basic_blocks.len(); - - let mut replacements: Vec<_> = (0..num_blocks).map(BasicBlock::new).collect(); - let mut used_blocks = 0; - for alive_index in keep.iter() { - replacements[alive_index] = BasicBlock::new(used_blocks); - if alive_index != used_blocks { - // Swap the next alive block data with the current available slot. Since alive_index is - // non-decreasing this is a valid operation. - mir.basic_blocks.swap(alive_index, used_blocks); - } - used_blocks += 1; - } - mir.basic_blocks.truncate(used_blocks); - - for bb in mir.all_basic_blocks() { - for target in mir.basic_block_data_mut(bb).terminator_mut().successors_mut() { - *target = replacements[target.index()]; - } - } -} +impl Pass for SimplifyCfg {} diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs index e021300f1b3..45393d57101 100644 --- a/src/librustc_mir/transform/type_check.rs +++ b/src/librustc_mir/transform/type_check.rs @@ -11,17 +11,18 @@ //! This pass type-checks the MIR to ensure it is not broken. #![allow(unreachable_code)] +use rustc::dep_graph::DepNode; use rustc::middle::infer::{self, InferCtxt}; use rustc::middle::traits; -use rustc::middle::ty::{self, Ty, TyCtxt}; use rustc::middle::ty::fold::TypeFoldable; +use rustc::middle::ty::{self, Ty, TyCtxt}; use rustc::mir::repr::*; use rustc::mir::tcx::LvalueTy; -use rustc::mir::transform::MirPass; +use rustc::mir::transform::{MirPass, Pass}; use rustc::mir::visit::{self, Visitor}; - -use syntax::codemap::{Span, DUMMY_SP}; use std::fmt; +use syntax::ast::NodeId; +use syntax::codemap::{Span, DUMMY_SP}; macro_rules! span_mirbug { ($context:expr, $elem:expr, $($message:tt)*) => ({ @@ -572,17 +573,17 @@ impl TypeckMir { } } -impl MirPass for TypeckMir { - fn run_on_mir<'a, 'tcx>(&mut self, mir: &mut Mir<'tcx>, infcx: &InferCtxt<'a, 'tcx>) - { - if infcx.tcx.sess.err_count() > 0 { +impl<'tcx> MirPass<'tcx> for TypeckMir { + fn run_pass(&mut self, tcx: &TyCtxt<'tcx>, id: NodeId, mir: &mut Mir<'tcx>) { + if tcx.sess.err_count() > 0 { // compiling a broken program can obviously result in a // broken MIR, so try not to report duplicate errors. return; } - - let mut checker = TypeChecker::new(infcx); - + let _task = tcx.dep_graph.in_task(DepNode::MirTypeck(id)); + let param_env = ty::ParameterEnvironment::for_item(tcx, id); + let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, Some(param_env)); + let mut checker = TypeChecker::new(&infcx); { let mut verifier = TypeVerifier::new(&mut checker, mir); verifier.visit_mir(mir); @@ -591,8 +592,9 @@ impl MirPass for TypeckMir { return; } } - checker.typeck_mir(mir); checker.verify_obligations(mir); } } + +impl Pass for TypeckMir {} diff --git a/src/librustc_plugin/registry.rs b/src/librustc_plugin/registry.rs index a51fd58db88..3cfd6a76dda 100644 --- a/src/librustc_plugin/registry.rs +++ b/src/librustc_plugin/registry.rs @@ -13,7 +13,7 @@ use rustc::lint::{EarlyLintPassObject, LateLintPassObject, LintId, Lint}; use rustc::session::Session; -use rustc::mir::transform::MirPass; +use rustc::mir::transform::MirMapPass; use syntax::ext::base::{SyntaxExtension, NamedSyntaxExtension, NormalTT}; use syntax::ext::base::{IdentTT, MultiModifier, MultiDecorator}; @@ -56,7 +56,7 @@ pub struct Registry<'a> { pub late_lint_passes: Vec, #[doc(hidden)] - pub mir_passes: Vec>, + pub mir_passes: Vec MirMapPass<'pcx>>>, #[doc(hidden)] pub lint_groups: HashMap<&'static str, Vec>, @@ -141,7 +141,7 @@ impl<'a> Registry<'a> { } /// Register a MIR pass - pub fn register_mir_pass(&mut self, pass: Box) { + pub fn register_mir_pass(&mut self, pass: Box MirMapPass<'pcx>>) { self.mir_passes.push(pass); } diff --git a/src/test/auxiliary/dummy_mir_pass.rs b/src/test/auxiliary/dummy_mir_pass.rs index 16ef965e0db..89101fe709d 100644 --- a/src/test/auxiliary/dummy_mir_pass.rs +++ b/src/test/auxiliary/dummy_mir_pass.rs @@ -18,17 +18,20 @@ extern crate rustc_front; extern crate rustc_plugin; extern crate syntax; -use rustc::mir::transform::MirPass; +use rustc::mir::transform::{self, MirPass}; use rustc::mir::repr::{Mir, Literal}; use rustc::mir::visit::MutVisitor; -use rustc::middle::infer::InferCtxt; +use rustc::middle::ty; use rustc::middle::const_eval::ConstVal; use rustc_plugin::Registry; +use syntax::ast::NodeId; + struct Pass; -impl MirPass for Pass { - fn run_on_mir<'a, 'tcx>(&mut self, mir: &mut Mir<'tcx>, _: &InferCtxt<'a, 'tcx>) { +impl transform::Pass for Pass {} +impl<'tcx> MirPass<'tcx> for Pass { + fn run_pass(&mut self, _: &ty::TyCtxt<'tcx>, _: NodeId, mir: &mut Mir<'tcx>) { Visitor.visit_mir(mir) } }