Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Pass manager for MIR #31916

Merged
merged 4 commits into from
Mar 13, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/librustc/dep_graph/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -70,6 +71,7 @@ pub enum DepNode {
IntrinsicCheck(DefId),
MatchCheck(DefId),
MirMapConstruction(DefId),
MirTypeck(NodeId),
BorrowCheck(DefId),
RvalueCheck(DefId),
Reachability,
Expand Down
22 changes: 0 additions & 22 deletions src/librustc/mir/mir_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}
}
}
2 changes: 1 addition & 1 deletion src/librustc/mir/repr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ impl Debug for BasicBlock {
}

///////////////////////////////////////////////////////////////////////////
// BasicBlock and Terminator
// BasicBlockData and Terminator

#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
pub struct BasicBlockData<'tcx> {
Expand Down
65 changes: 62 additions & 3 deletions src/librustc/mir/transform.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
6 changes: 3 additions & 3 deletions src/librustc/session/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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>,
Expand Down Expand Up @@ -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()),
Expand Down
25 changes: 15 additions & 10 deletions src/librustc_driver/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -561,7 +561,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();
}));

Expand Down Expand Up @@ -861,9 +861,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",
Expand Down Expand Up @@ -912,9 +922,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();
Expand All @@ -923,10 +932,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",
Expand Down
57 changes: 28 additions & 29 deletions src/librustc_driver/pretty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -80,6 +82,7 @@ pub enum PpMode {
PpmHir(PpSourceMode),
PpmFlowGraph(PpFlowGraphMode),
PpmMir,
PpmMirCFG,
}

pub fn parse_pretty(sess: &Session,
Expand All @@ -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),
_ => {
Expand Down Expand Up @@ -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"),
}
Expand All @@ -590,6 +595,7 @@ fn needs_expansion(ppm: &PpMode) -> bool {
PpmSource(PpmExpandedHygiene) |
PpmHir(_) |
PpmMir |
PpmMirCFG |
PpmFlowGraph(_) => true,
PpmSource(PpmTyped) => panic!("invalid state"),
}
Expand Down Expand Up @@ -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,
Expand All @@ -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(|| {
Expand Down
45 changes: 25 additions & 20 deletions src/librustc_mir/graphviz.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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() {
Expand Down
Loading