Auto merge of #31916 - nagisa:mir-passmgr-2, r=arielb1

Add Pass manager for MIR

A new PR, since rebasing the original one (https://github.com/rust-lang/rust/pull/31448) properly was a pain. Since then there has been several changes most notable of which:

1. Removed the pretty-printing with `#[rustc_mir(graphviz/pretty)]`, mostly because we now have `--unpretty=mir`, IMHO that’s the direction we should expand this functionality into;
2. Reverted the infercx change done for typeck, because typeck can make an infercx for itself by being a `MirMapPass`

r? @nikomatsakis
This commit is contained in:
bors 2016-03-13 05:33:28 -07:00
commit c21644ad16
18 changed files with 249 additions and 268 deletions

View File

@ -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,

View File

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

View File

@ -207,7 +207,7 @@ impl Debug for BasicBlock {
}
///////////////////////////////////////////////////////////////////////////
// BasicBlock and Terminator
// BasicBlockData and Terminator
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
pub struct BasicBlockData<'tcx> {

View File

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

View File

@ -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()),

View File

@ -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",

View File

@ -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(|| {

View File

@ -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));
}
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<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() {

View File

@ -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) => {}
}

View File

@ -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() {

View File

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

View File

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

View File

@ -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 {}

View File

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

View File

@ -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 {}

View File

@ -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 {}

View File

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

View File

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