Skip to content

Commit c21644a

Browse files
committed
Auto merge of #31916 - nagisa:mir-passmgr-2, r=arielb1
Add Pass manager for MIR A new PR, since rebasing the original one (#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
2 parents db6dd8e + bdc176e commit c21644a

File tree

18 files changed

+246
-265
lines changed

18 files changed

+246
-265
lines changed

src/librustc/dep_graph/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
use self::thread::{DepGraphThreadData, DepMessage};
1212
use middle::def_id::DefId;
13+
use syntax::ast::NodeId;
1314
use middle::ty::TyCtxt;
1415
use rustc_front::hir;
1516
use rustc_front::intravisit::Visitor;
@@ -71,6 +72,7 @@ pub enum DepNode {
7172
IntrinsicCheck(DefId),
7273
MatchCheck(DefId),
7374
MirMapConstruction(DefId),
75+
MirTypeck(NodeId),
7476
BorrowCheck(DefId),
7577
RvalueCheck(DefId),
7678
Reachability,

src/librustc/mir/mir_map.rs

-22
Original file line numberDiff line numberDiff line change
@@ -8,31 +8,9 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
use dep_graph::DepNode;
1211
use util::nodemap::NodeMap;
1312
use mir::repr::Mir;
14-
use mir::transform::MirPass;
15-
use middle::ty::{self, TyCtxt};
16-
use middle::infer;
1713

1814
pub struct MirMap<'tcx> {
1915
pub map: NodeMap<Mir<'tcx>>,
2016
}
21-
22-
impl<'tcx> MirMap<'tcx> {
23-
pub fn run_passes(&mut self, passes: &mut [Box<MirPass>], tcx: &TyCtxt<'tcx>) {
24-
if passes.is_empty() { return; }
25-
26-
for (&id, mir) in &mut self.map {
27-
let did = tcx.map.local_def_id(id);
28-
let _task = tcx.dep_graph.in_task(DepNode::MirMapConstruction(did));
29-
30-
let param_env = ty::ParameterEnvironment::for_item(tcx, id);
31-
let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, Some(param_env));
32-
33-
for pass in &mut *passes {
34-
pass.run_on_mir(mir, &infcx)
35-
}
36-
}
37-
}
38-
}

src/librustc/mir/repr.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ impl Debug for BasicBlock {
207207
}
208208

209209
///////////////////////////////////////////////////////////////////////////
210-
// BasicBlock and Terminator
210+
// BasicBlockData and Terminator
211211

212212
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
213213
pub struct BasicBlockData<'tcx> {

src/librustc/mir/transform.rs

+62-3
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,68 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11+
use mir::mir_map::MirMap;
1112
use mir::repr::Mir;
12-
use middle::infer::InferCtxt;
13+
use middle::ty::TyCtxt;
14+
use syntax::ast::NodeId;
1315

14-
pub trait MirPass {
15-
fn run_on_mir<'a, 'tcx>(&mut self, mir: &mut Mir<'tcx>, infcx: &InferCtxt<'a, 'tcx>);
16+
/// Various information about pass.
17+
pub trait Pass {
18+
// fn name() for printouts of various sorts?
19+
// fn should_run(Session) to check if pass should run?
20+
}
21+
22+
/// A pass which inspects the whole MirMap.
23+
pub trait MirMapPass<'tcx>: Pass {
24+
fn run_pass(&mut self, cx: &TyCtxt<'tcx>, map: &mut MirMap<'tcx>);
25+
}
26+
27+
/// A pass which inspects Mir of functions in isolation.
28+
pub trait MirPass<'tcx>: Pass {
29+
fn run_pass(&mut self, cx: &TyCtxt<'tcx>, id: NodeId, mir: &mut Mir<'tcx>);
30+
}
31+
32+
impl<'tcx, T: MirPass<'tcx>> MirMapPass<'tcx> for T {
33+
fn run_pass(&mut self, tcx: &TyCtxt<'tcx>, map: &mut MirMap<'tcx>) {
34+
for (&id, mir) in &mut map.map {
35+
MirPass::run_pass(self, tcx, id, mir);
36+
}
37+
}
38+
}
39+
40+
/// A manager for MIR passes.
41+
pub struct Passes {
42+
passes: Vec<Box<for<'tcx> MirMapPass<'tcx>>>,
43+
plugin_passes: Vec<Box<for<'tcx> MirMapPass<'tcx>>>
44+
}
45+
46+
impl Passes {
47+
pub fn new() -> Passes {
48+
let passes = Passes {
49+
passes: Vec::new(),
50+
plugin_passes: Vec::new()
51+
};
52+
passes
53+
}
54+
55+
pub fn run_passes<'tcx>(&mut self, pcx: &TyCtxt<'tcx>, map: &mut MirMap<'tcx>) {
56+
for pass in &mut self.plugin_passes {
57+
pass.run_pass(pcx, map);
58+
}
59+
for pass in &mut self.passes {
60+
pass.run_pass(pcx, map);
61+
}
62+
}
63+
64+
/// Pushes a built-in pass.
65+
pub fn push_pass(&mut self, pass: Box<for<'a> MirMapPass<'a>>) {
66+
self.passes.push(pass);
67+
}
68+
}
69+
70+
/// Copies the plugin passes.
71+
impl ::std::iter::Extend<Box<for<'a> MirMapPass<'a>>> for Passes {
72+
fn extend<I: IntoIterator<Item=Box<for <'a> MirMapPass<'a>>>>(&mut self, it: I) {
73+
self.plugin_passes.extend(it);
74+
}
1675
}

src/librustc/session/mod.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use middle::cstore::CrateStore;
1313
use middle::dependency_format;
1414
use session::search_paths::PathKind;
1515
use util::nodemap::{NodeMap, FnvHashMap};
16-
use mir::transform::MirPass;
16+
use mir::transform as mir_pass;
1717

1818
use syntax::ast::{NodeId, NodeIdAssigner, Name};
1919
use syntax::codemap::{Span, MultiSpan};
@@ -60,7 +60,7 @@ pub struct Session {
6060
pub lint_store: RefCell<lint::LintStore>,
6161
pub lints: RefCell<NodeMap<Vec<(lint::LintId, Span, String)>>>,
6262
pub plugin_llvm_passes: RefCell<Vec<String>>,
63-
pub plugin_mir_passes: RefCell<Vec<Box<MirPass>>>,
63+
pub mir_passes: RefCell<mir_pass::Passes>,
6464
pub plugin_attributes: RefCell<Vec<(String, AttributeType)>>,
6565
pub crate_types: RefCell<Vec<config::CrateType>>,
6666
pub dependency_formats: RefCell<dependency_format::Dependencies>,
@@ -477,7 +477,7 @@ pub fn build_session_(sopts: config::Options,
477477
lint_store: RefCell::new(lint::LintStore::new()),
478478
lints: RefCell::new(NodeMap()),
479479
plugin_llvm_passes: RefCell::new(Vec::new()),
480-
plugin_mir_passes: RefCell::new(Vec::new()),
480+
mir_passes: RefCell::new(mir_pass::Passes::new()),
481481
plugin_attributes: RefCell::new(Vec::new()),
482482
crate_types: RefCell::new(Vec::new()),
483483
dependency_formats: RefCell::new(FnvHashMap()),

src/librustc_driver/driver.rs

+15-10
Original file line numberDiff line numberDiff line change
@@ -568,7 +568,7 @@ pub fn phase_2_configure_and_expand(sess: &Session,
568568
}
569569

570570
*sess.plugin_llvm_passes.borrow_mut() = llvm_passes;
571-
*sess.plugin_mir_passes.borrow_mut() = mir_passes;
571+
sess.mir_passes.borrow_mut().extend(mir_passes);
572572
*sess.plugin_attributes.borrow_mut() = attributes.clone();
573573
}));
574574

@@ -865,9 +865,19 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
865865
"MIR dump",
866866
|| mir::mir_map::build_mir_for_crate(tcx));
867867

868-
time(time_passes,
869-
"MIR passes",
870-
|| mir_map.run_passes(&mut sess.plugin_mir_passes.borrow_mut(), tcx));
868+
time(time_passes, "MIR passes", || {
869+
let mut passes = sess.mir_passes.borrow_mut();
870+
// Push all the built-in passes.
871+
passes.push_pass(box mir::transform::remove_dead_blocks::RemoveDeadBlocks);
872+
passes.push_pass(box mir::transform::type_check::TypeckMir);
873+
passes.push_pass(box mir::transform::simplify_cfg::SimplifyCfg);
874+
// Late passes
875+
passes.push_pass(box mir::transform::no_landing_pads::NoLandingPads);
876+
passes.push_pass(box mir::transform::remove_dead_blocks::RemoveDeadBlocks);
877+
passes.push_pass(box mir::transform::erase_regions::EraseRegions);
878+
// And run everything.
879+
passes.run_passes(tcx, &mut mir_map);
880+
});
871881

872882
time(time_passes,
873883
"borrow checking",
@@ -916,9 +926,8 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
916926
}
917927

918928
/// Run the translation phase to LLVM, after which the AST and analysis can
919-
/// be discarded.
920929
pub fn phase_4_translate_to_llvm<'tcx>(tcx: &TyCtxt<'tcx>,
921-
mut mir_map: MirMap<'tcx>,
930+
mir_map: MirMap<'tcx>,
922931
analysis: ty::CrateAnalysis)
923932
-> trans::CrateTranslation {
924933
let time_passes = tcx.sess.time_passes();
@@ -927,10 +936,6 @@ pub fn phase_4_translate_to_llvm<'tcx>(tcx: &TyCtxt<'tcx>,
927936
"resolving dependency formats",
928937
|| dependency_format::calculate(&tcx.sess));
929938

930-
time(time_passes,
931-
"erasing regions from MIR",
932-
|| mir::transform::erase_regions::erase_regions(tcx, &mut mir_map));
933-
934939
// Option dance to work around the lack of stack once closures.
935940
time(time_passes,
936941
"translation",

src/librustc_driver/pretty.rs

+28-29
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ use rustc_resolve as resolve;
3131
use rustc_metadata::cstore::CStore;
3232

3333
use rustc_mir::pretty::write_mir_pretty;
34+
use rustc_mir::graphviz::write_mir_graphviz;
3435

3536
use syntax::ast::{self, BlockCheckMode};
3637
use syntax::codemap;
@@ -44,6 +45,7 @@ use graphviz as dot;
4445

4546
use std::fs::File;
4647
use std::io::{self, Write};
48+
use std::iter;
4749
use std::option;
4850
use std::path::PathBuf;
4951
use std::str::FromStr;
@@ -80,6 +82,7 @@ pub enum PpMode {
8082
PpmHir(PpSourceMode),
8183
PpmFlowGraph(PpFlowGraphMode),
8284
PpmMir,
85+
PpmMirCFG,
8386
}
8487

8588
pub fn parse_pretty(sess: &Session,
@@ -100,6 +103,7 @@ pub fn parse_pretty(sess: &Session,
100103
("hir,identified", true) => PpmHir(PpmIdentified),
101104
("hir,typed", true) => PpmHir(PpmTyped),
102105
("mir", true) => PpmMir,
106+
("mir-cfg", true) => PpmMirCFG,
103107
("flowgraph", true) => PpmFlowGraph(PpFlowGraphMode::Default),
104108
("flowgraph,unlabelled", true) => PpmFlowGraph(PpFlowGraphMode::UnlabelledEdges),
105109
_ => {
@@ -574,6 +578,7 @@ fn needs_ast_map(ppm: &PpMode, opt_uii: &Option<UserIdentifiedItem>) -> bool {
574578
PpmSource(PpmExpandedHygiene) |
575579
PpmHir(_) |
576580
PpmMir |
581+
PpmMirCFG |
577582
PpmFlowGraph(_) => true,
578583
PpmSource(PpmTyped) => panic!("invalid state"),
579584
}
@@ -590,6 +595,7 @@ fn needs_expansion(ppm: &PpMode) -> bool {
590595
PpmSource(PpmExpandedHygiene) |
591596
PpmHir(_) |
592597
PpmMir |
598+
PpmMirCFG |
593599
PpmFlowGraph(_) => true,
594600
PpmSource(PpmTyped) => panic!("invalid state"),
595601
}
@@ -807,9 +813,15 @@ pub fn pretty_print_input(sess: Session,
807813
})
808814
}
809815

810-
(PpmMir, None) => {
811-
debug!("pretty printing MIR for whole crate");
812-
let ast_map = ast_map.expect("--unpretty mir missing ast_map");
816+
(pp_type@PpmMir, uii) | (pp_type@PpmMirCFG, uii) => {
817+
let ast_map = ast_map.expect("--unpretty missing ast_map");
818+
let nodeid = if let Some(uii) = uii {
819+
debug!("pretty printing MIR for {:?}", uii);
820+
Some(uii.to_one_node_id("--unpretty", &sess, &ast_map))
821+
} else {
822+
debug!("pretty printing MIR for whole crate");
823+
None
824+
};
813825
abort_on_err(driver::phase_3_run_analysis_passes(&sess,
814826
&cstore,
815827
ast_map,
@@ -818,38 +830,25 @@ pub fn pretty_print_input(sess: Session,
818830
resolve::MakeGlobMap::No,
819831
|tcx, mir_map, _, _| {
820832
if let Some(mir_map) = mir_map {
821-
for (nodeid, mir) in &mir_map.map {
822-
try!(writeln!(out, "MIR for {}", tcx.map.node_to_string(*nodeid)));
823-
try!(write_mir_pretty(mir, &mut out));
833+
if let Some(nodeid) = nodeid {
834+
let mir = mir_map.map.get(&nodeid).unwrap_or_else(|| {
835+
sess.fatal(&format!("no MIR map entry for node {}", nodeid))
836+
});
837+
try!(match pp_type {
838+
PpmMir => write_mir_pretty(tcx, iter::once((&nodeid, mir)), &mut out),
839+
_ => write_mir_graphviz(tcx, iter::once((&nodeid, mir)), &mut out)
840+
});
841+
} else {
842+
try!(match pp_type {
843+
PpmMir => write_mir_pretty(tcx, mir_map.map.iter(), &mut out),
844+
_ => write_mir_graphviz(tcx, mir_map.map.iter(), &mut out)
845+
});
824846
}
825847
}
826848
Ok(())
827849
}), &sess)
828850
}
829851

830-
(PpmMir, Some(uii)) => {
831-
debug!("pretty printing MIR for {:?}", uii);
832-
let ast_map = ast_map.expect("--unpretty mir missing ast_map");
833-
let nodeid = uii.to_one_node_id("--unpretty", &sess, &ast_map);
834-
835-
abort_on_err(driver::phase_3_run_analysis_passes(&sess,
836-
&cstore,
837-
ast_map,
838-
&arenas,
839-
&id,
840-
resolve::MakeGlobMap::No,
841-
|tcx, mir_map, _, _| {
842-
if let Some(mir_map) = mir_map {
843-
try!(writeln!(out, "MIR for {}", tcx.map.node_to_string(nodeid)));
844-
let mir = mir_map.map.get(&nodeid).unwrap_or_else(|| {
845-
sess.fatal(&format!("no MIR map entry for node {}", nodeid))
846-
});
847-
try!(write_mir_pretty(mir, &mut out));
848-
}
849-
Ok(())
850-
}), &sess)
851-
}
852-
853852
(PpmFlowGraph(mode), opt_uii) => {
854853
debug!("pretty printing flow graph for {:?}", opt_uii);
855854
let uii = opt_uii.unwrap_or_else(|| {

src/librustc_mir/graphviz.rs

+25-20
Original file line numberDiff line numberDiff line change
@@ -13,30 +13,34 @@ use rustc::mir::repr::*;
1313
use rustc::middle::ty;
1414
use std::fmt::Debug;
1515
use std::io::{self, Write};
16+
use syntax::ast::NodeId;
1617

17-
/// Write a graphviz DOT graph for the given MIR.
18-
pub fn write_mir_graphviz<W: Write>(mir: &Mir, w: &mut W) -> io::Result<()> {
19-
try!(writeln!(w, "digraph Mir {{"));
18+
/// Write a graphviz DOT graph of a list of MIRs.
19+
pub fn write_mir_graphviz<'a, 't, W, I>(tcx: &ty::TyCtxt<'t>, iter: I, w: &mut W) -> io::Result<()>
20+
where W: Write, I: Iterator<Item=(&'a NodeId, &'a Mir<'a>)> {
21+
for (&nodeid, mir) in iter {
22+
try!(writeln!(w, "digraph Mir_{} {{", nodeid));
2023

21-
// Global graph properties
22-
try!(writeln!(w, r#" graph [fontname="monospace"];"#));
23-
try!(writeln!(w, r#" node [fontname="monospace"];"#));
24-
try!(writeln!(w, r#" edge [fontname="monospace"];"#));
24+
// Global graph properties
25+
try!(writeln!(w, r#" graph [fontname="monospace"];"#));
26+
try!(writeln!(w, r#" node [fontname="monospace"];"#));
27+
try!(writeln!(w, r#" edge [fontname="monospace"];"#));
2528

26-
// Graph label
27-
try!(write_graph_label(mir, w));
29+
// Graph label
30+
try!(write_graph_label(tcx, nodeid, mir, w));
2831

29-
// Nodes
30-
for block in mir.all_basic_blocks() {
31-
try!(write_node(block, mir, w));
32-
}
32+
// Nodes
33+
for block in mir.all_basic_blocks() {
34+
try!(write_node(block, mir, w));
35+
}
3336

34-
// Edges
35-
for source in mir.all_basic_blocks() {
36-
try!(write_edges(source, mir, w));
37+
// Edges
38+
for source in mir.all_basic_blocks() {
39+
try!(write_edges(source, mir, w));
40+
}
41+
try!(writeln!(w, "}}"))
3742
}
38-
39-
writeln!(w, "}}")
43+
Ok(())
4044
}
4145

4246
/// 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
8488
/// Write the graphviz DOT label for the overall graph. This is essentially a block of text that
8589
/// will appear below the graph, showing the type of the `fn` this MIR represents and the types of
8690
/// all the variables and temporaries.
87-
fn write_graph_label<W: Write>(mir: &Mir, w: &mut W) -> io::Result<()> {
88-
try!(write!(w, " label=<fn("));
91+
fn write_graph_label<W: Write>(tcx: &ty::TyCtxt, nid: NodeId, mir: &Mir, w: &mut W)
92+
-> io::Result<()> {
93+
try!(write!(w, " label=<fn {}(", dot::escape_html(&tcx.map.path_to_string(nid))));
8994

9095
// fn argument types.
9196
for (i, arg) in mir.arg_decls.iter().enumerate() {

0 commit comments

Comments
 (0)