about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/dep_graph/mod.rs2
-rw-r--r--src/librustc/mir/mir_map.rs22
-rw-r--r--src/librustc/mir/repr.rs2
-rw-r--r--src/librustc/mir/transform.rs65
-rw-r--r--src/librustc/session/mod.rs6
-rw-r--r--src/librustc_driver/driver.rs25
-rw-r--r--src/librustc_driver/pretty.rs57
-rw-r--r--src/librustc_mir/graphviz.rs45
-rw-r--r--src/librustc_mir/mir_map.rs61
-rw-r--r--src/librustc_mir/pretty.rs25
-rw-r--r--src/librustc_mir/transform/erase_regions.rs19
-rw-r--r--src/librustc_mir/transform/mod.rs2
-rw-r--r--src/librustc_mir/transform/no_landing_pads.rs14
-rw-r--r--src/librustc_mir/transform/remove_dead_blocks.rs (renamed from src/librustc_mir/transform/clear_dead_blocks.rs)66
-rw-r--r--src/librustc_mir/transform/simplify_cfg.rs57
-rw-r--r--src/librustc_mir/transform/type_check.rs26
-rw-r--r--src/librustc_plugin/registry.rs6
-rw-r--r--src/test/auxiliary/dummy_mir_pass.rs11
18 files changed, 246 insertions, 265 deletions
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<Mir<'tcx>>,
 }
-
-impl<'tcx> MirMap<'tcx> {
-    pub fn run_passes(&mut self, passes: &mut [Box<MirPass>], 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<Box<for<'tcx> MirMapPass<'tcx>>>,
+    plugin_passes: Vec<Box<for<'tcx> 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<for<'a> MirMapPass<'a>>) {
+        self.passes.push(pass);
+    }
+}
+
+/// Copies the plugin passes.
+impl ::std::iter::Extend<Box<for<'a> MirMapPass<'a>>> for Passes {
+    fn extend<I: IntoIterator<Item=Box<for <'a> 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<lint::LintStore>,
     pub lints: RefCell<NodeMap<Vec<(lint::LintId, Span, String)>>>,
     pub plugin_llvm_passes: RefCell<Vec<String>>,
-    pub plugin_mir_passes: RefCell<Vec<Box<MirPass>>>,
+    pub mir_passes: RefCell<mir_pass::Passes>,
     pub plugin_attributes: RefCell<Vec<(String, AttributeType)>>,
     pub crate_types: RefCell<Vec<config::CrateType>>,
     pub dependency_formats: RefCell<dependency_format::Dependencies>,
@@ -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<UserIdentifiedItem>) -> 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<W: Write>(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<Item=(&'a NodeId, &'a Mir<'a>)> {
+    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));
+        // Edges
+        for source in mir.all_basic_blocks() {
+            try!(write_edges(source, mir, w));
+        }
+        try!(writeln!(w, "}}"))
     }
-
-    writeln!(w, "}}")
+    Ok(())
 }
 
 /// Write a graphviz DOT node for the given basic block.
@@ -84,8 +88,9 @@ fn write_edges<W: Write>(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<W: Write>(mir: &Mir, w: &mut W) -> io::Result<()> {
-    try!(write!(w, "    label=<fn("));
+fn write_graph_label<W: Write>(tcx: &ty::TyCtxt, nid: NodeId, mir: &Mir, w: &mut W)
+-> io::Result<()> {
+    try!(write!(w, "    label=<fn {}(", dot::escape_html(&tcx.map.path_to_string(nid))));
 
     // fn argument types.
     for (i, arg) in mir.arg_decls.iter().enumerate() {
diff --git a/src/librustc_mir/mir_map.rs b/src/librustc_mir/mir_map.rs
index 398f38c5ba9..2e13e7b42bd 100644
--- a/src/librustc_mir/mir_map.rs
+++ b/src/librustc_mir/mir_map.rs
@@ -20,16 +20,10 @@ extern crate syntax;
 extern crate rustc_front;
 
 use build;
-use graphviz;
-use pretty;
-use transform::{clear_dead_blocks, simplify_cfg, type_check};
-use transform::{no_landing_pads};
 use rustc::dep_graph::DepNode;
 use rustc::mir::repr::Mir;
 use hair::cx::Cx;
-use std::fs::File;
 
-use rustc::mir::transform::MirPass;
 use rustc::mir::mir_map::MirMap;
 use rustc::middle::infer;
 use rustc::middle::region::CodeExtentData;
@@ -136,61 +130,16 @@ impl<'a, 'm, 'tcx> 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<W: Write>(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<Item=(&'a NodeId, &'a Mir<'a>)> {
+    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<W: Write>(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<W: Write>(mir: &Mir, w: &mut W) -> io::Result<()> {
-    try!(write!(w, "fn("));
+fn write_mir_intro<W: Write>(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
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);
 
-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);
+    for bb in mir.all_basic_blocks() {
+        for target in mir.basic_block_data_mut(bb).terminator_mut().successors_mut() {
+            *target = replacements[target.index()];
+        }
     }
 }
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<BasicBlock> {
             // 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<LateLintPassObject>,
 
     #[doc(hidden)]
-    pub mir_passes: Vec<Box<MirPass>>,
+    pub mir_passes: Vec<Box<for<'pcx> MirMapPass<'pcx>>>,
 
     #[doc(hidden)]
     pub lint_groups: HashMap<&'static str, Vec<LintId>>,
@@ -141,7 +141,7 @@ impl<'a> Registry<'a> {
     }
 
     /// Register a MIR pass
-    pub fn register_mir_pass(&mut self, pass: Box<MirPass>) {
+    pub fn register_mir_pass(&mut self, pass: Box<for<'pcx> 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)
     }
 }