Skip to content

Commit c7286d9

Browse files
committed
Add MIR pass manager and tier-ed passes.
Tiered passes allow to avoid some of the introspection of MIR map for passes which do not need it and perhaps improve performance of the more-restricted passes (i.e. BlockPasses could be run in parallel regardless of function for which the block belongs). It also could allow to e.g. run dead block removal only after passes which modify the CFG graph and not after those which only change blocks.
1 parent da8a388 commit c7286d9

File tree

9 files changed

+133
-59
lines changed

9 files changed

+133
-59
lines changed

src/librustc/mir/mir_map.rs

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,7 @@
1010

1111
use util::nodemap::NodeMap;
1212
use mir::repr::Mir;
13-
use mir::transform::MirPass;
14-
use middle::ty;
1513

1614
pub struct MirMap<'tcx> {
1715
pub map: NodeMap<Mir<'tcx>>,
1816
}
19-
20-
impl<'tcx> MirMap<'tcx> {
21-
pub fn run_passes(&mut self, passes: &mut [Box<MirPass>], tcx: &ty::ctxt<'tcx>) {
22-
for (_, ref mut mir) in &mut self.map {
23-
for pass in &mut *passes {
24-
pass.run_on_mir(mir, tcx)
25-
}
26-
}
27-
}
28-
}

src/librustc/mir/transform.rs

Lines changed: 73 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,79 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
use mir::repr::Mir;
11+
use mir::repr::{Mir, BasicBlockData, BasicBlock};
12+
use mir::mir_map::MirMap;
1213
use middle::ty::ctxt;
1314

14-
pub trait MirPass {
15-
fn run_on_mir<'tcx>(&mut self, mir: &mut Mir<'tcx>, tcx: &ctxt<'tcx>);
15+
/// Contains various metadata about the pass.
16+
pub trait Pass {
17+
/// Ordering of the pass. Lower value runs the pass earlier.
18+
fn priority(&self) -> usize;
19+
// Possibly also `fn name()` and `fn should_run(Session)` etc.
20+
}
21+
22+
/// Pass which inspects the whole MirMap.
23+
pub trait MirMapPass: Pass {
24+
fn run_pass<'tcx>(&mut self, tcx: &ctxt<'tcx>, map: &mut MirMap<'tcx>);
25+
}
26+
27+
/// Pass which only inspects MIR of distinct functions.
28+
pub trait MirPass: Pass {
29+
fn run_pass<'tcx>(&mut self, tcx: &ctxt<'tcx>, mir: &mut Mir<'tcx>);
30+
}
31+
32+
/// Pass which only inspects basic blocks in MIR.
33+
///
34+
/// Invariant: The blocks are considered to be fully self-contained for the purposes of this pass –
35+
/// the pass may not change the list of successors of the block or apply any transformations to
36+
/// blocks based on the information collected during earlier runs of the pass.
37+
pub trait MirBlockPass: Pass {
38+
fn run_pass<'tcx>(&mut self, tcx: &ctxt<'tcx>, bb: BasicBlock, data: &mut BasicBlockData<'tcx>);
39+
}
40+
41+
impl<T: MirBlockPass> MirPass for T {
42+
fn run_pass<'tcx>(&mut self, tcx: &ctxt<'tcx>, mir: &mut Mir<'tcx>) {
43+
for (i, basic_block) in mir.basic_blocks.iter_mut().enumerate() {
44+
MirBlockPass::run_pass(self, tcx, BasicBlock::new(i), basic_block);
45+
}
46+
}
47+
}
48+
49+
impl<T: MirPass> MirMapPass for T {
50+
fn run_pass<'tcx>(&mut self, tcx: &ctxt<'tcx>, map: &mut MirMap<'tcx>) {
51+
for (_, mir) in &mut map.map {
52+
MirPass::run_pass(self, tcx, mir);
53+
}
54+
}
55+
}
56+
57+
/// A manager for MIR passes.
58+
pub struct Passes {
59+
passes: Vec<Box<MirMapPass>>
60+
}
61+
62+
impl Passes {
63+
pub fn new() -> Passes {
64+
let passes = Passes {
65+
passes: Vec::new()
66+
};
67+
passes
68+
}
69+
70+
pub fn run_passes<'tcx>(&mut self, tcx: &ctxt<'tcx>, map: &mut MirMap<'tcx>) {
71+
self.passes.sort_by_key(|e| e.priority());
72+
for pass in &mut self.passes {
73+
pass.run_pass(tcx, map);
74+
}
75+
}
76+
77+
pub fn push_pass(&mut self, pass: Box<MirMapPass>) {
78+
self.passes.push(pass);
79+
}
80+
}
81+
82+
impl ::std::iter::Extend<Box<MirMapPass>> for Passes {
83+
fn extend<I: IntoIterator<Item=Box<MirMapPass>>>(&mut self, it: I) {
84+
self.passes.extend(it);
85+
}
1686
}

src/librustc/session/mod.rs

Lines changed: 3 additions & 3 deletions
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;
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::transform::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::transform::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

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ use rustc::middle;
2323
use rustc::util::common::time;
2424
use rustc::util::nodemap::NodeSet;
2525
use rustc_borrowck as borrowck;
26+
use rustc_mir::transform;
2627
use rustc_resolve as resolve;
2728
use rustc_metadata::macro_import;
2829
use rustc_metadata::creader::LocalCrateReader;
@@ -561,8 +562,8 @@ pub fn phase_2_configure_and_expand(sess: &Session,
561562
}
562563

563564
*sess.plugin_llvm_passes.borrow_mut() = llvm_passes;
564-
*sess.plugin_mir_passes.borrow_mut() = mir_passes;
565565
*sess.plugin_attributes.borrow_mut() = attributes.clone();
566+
sess.mir_passes.borrow_mut().extend(mir_passes);
566567
}));
567568

568569
// Lint plugins are registered; now we can process command line flags.
@@ -846,12 +847,18 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
846847

847848
let mut mir_map =
848849
time(time_passes,
849-
"MIR dump",
850+
"MIR build",
850851
|| mir::mir_map::build_mir_for_crate(tcx));
851852

852-
time(time_passes,
853-
"MIR passes",
854-
|| mir_map.run_passes(&mut sess.plugin_mir_passes.borrow_mut(), tcx));
853+
854+
time(time_passes, "MIR passes", || {
855+
let mut passes = sess.mir_passes.borrow_mut();
856+
// Push all the built-in passes.
857+
passes.push_pass(box transform::simplify_cfg::SimplifyCfg);
858+
passes.push_pass(box transform::erase_regions::EraseRegions);
859+
// And run everything.
860+
passes.run_passes(tcx, &mut mir_map);
861+
});
855862

856863
time(time_passes,
857864
"liveness checking",
@@ -907,10 +914,9 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
907914
})
908915
}
909916

910-
/// Run the translation phase to LLVM, after which the AST and analysis can
911-
/// be discarded.
917+
/// Run the translation phase to LLVM, after which the MIR and analysis can be discarded.
912918
pub fn phase_4_translate_to_llvm<'tcx>(tcx: &ty::ctxt<'tcx>,
913-
mut mir_map: MirMap<'tcx>,
919+
mir_map: MirMap<'tcx>,
914920
analysis: ty::CrateAnalysis)
915921
-> trans::CrateTranslation {
916922
let time_passes = tcx.sess.time_passes();
@@ -919,11 +925,6 @@ pub fn phase_4_translate_to_llvm<'tcx>(tcx: &ty::ctxt<'tcx>,
919925
"resolving dependency formats",
920926
|| dependency_format::calculate(&tcx.sess));
921927

922-
time(time_passes,
923-
"erasing regions from MIR",
924-
|| mir::transform::erase_regions::erase_regions(tcx, &mut mir_map));
925-
926-
// Option dance to work around the lack of stack once closures.
927928
time(time_passes,
928929
"translation",
929930
move || trans::trans_crate(tcx, &mir_map, analysis))

src/librustc_mir/mir_map.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,11 @@ extern crate rustc_front;
2222
use build;
2323
use graphviz;
2424
use pretty;
25-
use transform::{simplify_cfg, MirPass};
2625
use rustc::dep_graph::DepNode;
2726
use rustc::mir::repr::Mir;
2827
use hair::cx::Cx;
2928
use std::fs::File;
3029

31-
use rustc::mir::transform::MirPass;
3230
use rustc::mir::mir_map::MirMap;
3331
use rustc::middle::infer;
3432
use rustc::middle::region::CodeExtentData;
@@ -147,9 +145,7 @@ impl<'a, 'm, 'tcx> Visitor<'tcx> for InnerDump<'a,'m,'tcx> {
147145
let infcx = infer::new_infer_ctxt(self.tcx, &self.tcx.tables, Some(param_env));
148146

149147
match build_mir(Cx::new(&infcx), implicit_arg_tys, id, span, decl, body) {
150-
Ok(mut mir) => {
151-
simplify_cfg::SimplifyCfg::new().run_on_mir(&mut mir, self.tcx);
152-
148+
Ok(mir) => {
153149
let meta_item_list = self.attr
154150
.iter()
155151
.flat_map(|a| a.meta_item_list())

src/librustc_mir/transform/erase_regions.rs

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,33 @@ use rustc::middle::ty;
1616
use rustc::mir::repr::*;
1717
use rustc::mir::visit::MutVisitor;
1818
use rustc::mir::mir_map::MirMap;
19-
use rustc::mir::transform::MirPass;
19+
use rustc::mir::transform::{MirPass, Pass};
2020

2121
pub fn erase_regions<'tcx>(tcx: &ty::ctxt<'tcx>, mir_map: &mut MirMap<'tcx>) {
2222
let mut eraser = EraseRegions;
2323

2424
for (_, mir) in &mut mir_map.map {
25-
eraser.run_on_mir(mir, tcx);
25+
eraser.run_pass(tcx, mir);
2626
}
2727
}
2828

2929
pub struct EraseRegions;
3030

31+
impl MirPass for EraseRegions {
32+
fn run_pass<'tcx>(&mut self, tcx: &ty::ctxt<'tcx>, mir: &mut Mir<'tcx>) {
33+
EraseRegionsVisitor::new(tcx).visit_mir(mir);
34+
}
35+
36+
}
37+
38+
impl Pass for EraseRegions {
39+
fn priority(&self) -> usize {
40+
// We want this pass to run as late as possible in transformation chain, so we give it a
41+
// very high priority number.
42+
!50
43+
}
44+
}
45+
3146
struct EraseRegionsVisitor<'a, 'tcx: 'a> {
3247
tcx: &'a ty::ctxt<'tcx>,
3348
}
@@ -58,13 +73,7 @@ impl<'a, 'tcx> EraseRegionsVisitor<'a, 'tcx> {
5873
}
5974
}
6075

61-
impl<'a, 'tcx> MirPass<'tcx> for EraseRegions<'a, 'tcx> {
62-
fn run_on_mir(&mut self, mir: &mut Mir<'tcx>) {
63-
self.visit_mir(mir);
64-
}
65-
}
66-
67-
impl<'a, 'tcx> MutVisitor<'tcx> for EraseRegions<'a, 'tcx> {
76+
impl<'a, 'tcx> MutVisitor<'tcx> for EraseRegionsVisitor<'a, 'tcx> {
6877
fn visit_mir(&mut self, mir: &mut Mir<'tcx>) {
6978
self.erase_regions_return_ty(&mut mir.return_ty);
7079
self.erase_regions_tys(mir.var_decls.iter_mut().map(|d| &mut d.ty));

src/librustc_mir/transform/simplify_cfg.rs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,14 @@
99
// except according to those terms.
1010

1111
use rustc::middle::const_eval::ConstVal;
12+
use rustc::middle::ty;
1213
use rustc::mir::repr::*;
1314
use transform::util;
14-
use rustc::mir::transform::MirPass;
15+
use rustc::mir::transform::{MirPass, Pass};
1516

1617
pub struct SimplifyCfg;
1718

1819
impl SimplifyCfg {
19-
pub fn new() -> SimplifyCfg {
20-
SimplifyCfg
21-
}
22-
2320
fn remove_dead_blocks(&self, mir: &mut Mir) {
2421
let mut seen = vec![false; mir.basic_blocks.len()];
2522

@@ -83,6 +80,7 @@ impl SimplifyCfg {
8380
changed
8481
}
8582

83+
// FIXME: This transformation should be interleaved with the constant-propagation pass.
8684
fn simplify_branches(&self, mir: &mut Mir) -> bool {
8785
let mut changed = false;
8886

@@ -119,7 +117,7 @@ impl SimplifyCfg {
119117
}
120118

121119
impl MirPass for SimplifyCfg {
122-
fn run_on_mir<'tcx>(&mut self, mir: &mut Mir<'tcx>, _: &::rustc::middle::ty::ctxt<'tcx>) {
120+
fn run_pass<'tcx>(&mut self, _: &ty::ctxt<'tcx>, mir: &mut Mir<'tcx>) {
123121
let mut changed = true;
124122
while changed {
125123
changed = self.simplify_branches(mir);
@@ -130,3 +128,9 @@ impl MirPass for SimplifyCfg {
130128
mir.basic_blocks.shrink_to_fit();
131129
}
132130
}
131+
132+
impl Pass for SimplifyCfg {
133+
fn priority(&self) -> usize {
134+
50
135+
}
136+
}

src/librustc_plugin/registry.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
use rustc::lint::{EarlyLintPassObject, LateLintPassObject, LintId, Lint};
1414
use rustc::session::Session;
1515

16-
use rustc::mir::transform::MirPass;
16+
use rustc::mir;
1717

1818
use syntax::ext::base::{SyntaxExtension, NamedSyntaxExtension, NormalTT};
1919
use syntax::ext::base::{IdentTT, MultiModifier, MultiDecorator};
@@ -56,7 +56,7 @@ pub struct Registry<'a> {
5656
pub late_lint_passes: Vec<LateLintPassObject>,
5757

5858
#[doc(hidden)]
59-
pub mir_passes: Vec<Box<MirPass>>,
59+
pub mir_passes: Vec<Box<mir::transform::MirMapPass>>,
6060

6161
#[doc(hidden)]
6262
pub lint_groups: HashMap<&'static str, Vec<LintId>>,
@@ -141,7 +141,7 @@ impl<'a> Registry<'a> {
141141
}
142142

143143
/// Register a MIR pass
144-
pub fn register_mir_pass(&mut self, pass: Box<MirPass>) {
144+
pub fn register_mir_pass(&mut self, pass: Box<mir::transform::MirMapPass>) {
145145
self.mir_passes.push(pass);
146146
}
147147

src/test/auxiliary/dummy_mir_pass.rs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ extern crate rustc_front;
1818
extern crate rustc_plugin;
1919
extern crate syntax;
2020

21-
use rustc::mir::transform::MirPass;
22-
use rustc::mir::repr::{Mir, Literal};
21+
use rustc::mir::transform::{self, MirBlockPass};
22+
use rustc::mir::repr::{BasicBlock, BasicBlockData, Literal};
2323
use rustc::mir::visit::MutVisitor;
2424
use rustc::middle::ty;
2525
use rustc::middle::const_eval::ConstVal;
@@ -30,9 +30,15 @@ use syntax::attr;
3030

3131
struct Pass;
3232

33-
impl MirPass for Pass {
34-
fn run_on_mir<'tcx>(&mut self, mir: &mut Mir<'tcx>, tcx: &ty::ctxt<'tcx>) {
35-
Visitor.visit_mir(mir)
33+
impl transform::Pass for Pass {
34+
fn priority(&self) -> usize {
35+
1000
36+
}
37+
}
38+
39+
impl MirBlockPass for Pass {
40+
fn run_pass<'tcx>(&mut self, tcx: &ty::ctxt<'tcx>, bb: BasicBlock, bbd: &mut BasicBlockData) {
41+
Visitor.visit_basic_block_data(bb, bbd)
3642
}
3743
}
3844

0 commit comments

Comments
 (0)