Skip to content

Commit af69f95

Browse files
committed
Split SimplifyCfg pass into smaller passes
Previously SimplifyCfg pass was unecessarily interleaving many different functions – actual simplification, dead block removal and compaction. This patch splits off dead block removal and compaction into their own passes.
1 parent c7286d9 commit af69f95

File tree

3 files changed

+101
-28
lines changed

3 files changed

+101
-28
lines changed

src/librustc/mir/repr.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ impl Debug for BasicBlock {
204204
}
205205

206206
///////////////////////////////////////////////////////////////////////////
207-
// BasicBlock and Terminator
207+
// BasicBlockData and Terminator
208208

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

src/librustc_driver/driver.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -856,6 +856,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
856856
// Push all the built-in passes.
857857
passes.push_pass(box transform::simplify_cfg::SimplifyCfg);
858858
passes.push_pass(box transform::erase_regions::EraseRegions);
859+
passes.push_pass(box transform::simplify_cfg::CompactMir);
859860
// And run everything.
860861
passes.run_passes(tcx, &mut mir_map);
861862
});

src/librustc_mir/transform/simplify_cfg.rs

Lines changed: 99 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -11,32 +11,31 @@
1111
use rustc::middle::const_eval::ConstVal;
1212
use rustc::middle::ty;
1313
use rustc::mir::repr::*;
14+
use rustc::mir::visit::MutVisitor;
1415
use transform::util;
1516
use rustc::mir::transform::{MirPass, Pass};
1617

1718
pub struct SimplifyCfg;
1819

19-
impl SimplifyCfg {
20-
fn remove_dead_blocks(&self, mir: &mut Mir) {
21-
let mut seen = vec![false; mir.basic_blocks.len()];
22-
23-
// These blocks are always required.
24-
seen[START_BLOCK.index()] = true;
25-
seen[END_BLOCK.index()] = true;
20+
impl Pass for SimplifyCfg {
21+
fn priority(&self) -> usize {
22+
50
23+
}
24+
}
2625

27-
let mut worklist = vec![START_BLOCK];
28-
while let Some(bb) = worklist.pop() {
29-
for succ in mir.basic_block_data(bb).terminator().successors().iter() {
30-
if !seen[succ.index()] {
31-
seen[succ.index()] = true;
32-
worklist.push(*succ);
33-
}
34-
}
26+
impl MirPass for SimplifyCfg {
27+
fn run_pass<'tcx>(&mut self, tcx: &ty::ctxt<'tcx>, mir: &mut Mir<'tcx>) {
28+
let mut dbr_pass = DeadBlockRemoval::new(self);
29+
let mut changed = true;
30+
while changed {
31+
changed = self.simplify_branches(mir);
32+
changed |= self.remove_goto_chains(mir);
33+
dbr_pass.run_pass(tcx, mir);
3534
}
36-
37-
util::retain_basic_blocks(mir, &seen);
3835
}
36+
}
3937

38+
impl SimplifyCfg {
4039
fn remove_goto_chains(&self, mir: &mut Mir) -> bool {
4140

4241
// Find the target at the end of the jump chain, return None if there is a loop
@@ -116,21 +115,94 @@ impl SimplifyCfg {
116115
}
117116
}
118117

119-
impl MirPass for SimplifyCfg {
118+
/// Remove all the unreachable blocks.
119+
///
120+
/// You want to schedule this pass just after any pass which might introduce unreachable blocks.
121+
/// This pass is very cheap and might improve the run-time of other not-so-cheap passes.
122+
pub struct DeadBlockRemoval(usize);
123+
124+
impl DeadBlockRemoval {
125+
fn new(run_after: &Pass) -> DeadBlockRemoval {
126+
DeadBlockRemoval(run_after.priority() + 1)
127+
}
128+
}
129+
130+
impl Pass for DeadBlockRemoval {
131+
fn priority(&self) -> usize {
132+
self.0
133+
}
134+
}
135+
136+
impl MirPass for DeadBlockRemoval {
120137
fn run_pass<'tcx>(&mut self, _: &ty::ctxt<'tcx>, mir: &mut Mir<'tcx>) {
121-
let mut changed = true;
122-
while changed {
123-
changed = self.simplify_branches(mir);
124-
changed |= self.remove_goto_chains(mir);
125-
self.remove_dead_blocks(mir);
138+
let mut seen = vec![false; mir.basic_blocks.len()];
139+
140+
// These blocks are always required.
141+
seen[START_BLOCK.index()] = true;
142+
seen[END_BLOCK.index()] = true;
143+
144+
let mut worklist = vec![START_BLOCK];
145+
while let Some(bb) = worklist.pop() {
146+
for succ in mir.basic_block_data(bb).terminator().successors().iter() {
147+
if !seen[succ.index()] {
148+
seen[succ.index()] = true;
149+
worklist.push(*succ);
150+
}
151+
}
126152
}
127-
// FIXME: Should probably be moved into some kind of pass manager
128-
mir.basic_blocks.shrink_to_fit();
153+
154+
util::retain_basic_blocks(mir, &seen);
129155
}
130156
}
131157

132-
impl Pass for SimplifyCfg {
158+
/// Reduce the memory allocated by a MIR graph.
159+
pub struct CompactMir;
160+
161+
impl Pass for CompactMir {
133162
fn priority(&self) -> usize {
134-
50
163+
// We want this pass to run very late, so we give it a very high priority number.
164+
!10
165+
}
166+
}
167+
168+
impl MirPass for CompactMir {
169+
fn run_pass<'tcx>(&mut self, _: &ty::ctxt<'tcx>, mir: &mut Mir<'tcx>) {
170+
self.visit_mir(mir);
171+
}
172+
}
173+
174+
impl<'tcx> MutVisitor<'tcx> for CompactMir {
175+
fn visit_mir(&mut self, mir: &mut Mir<'tcx>) {
176+
mir.basic_blocks.shrink_to_fit();
177+
mir.var_decls.shrink_to_fit();
178+
mir.arg_decls.shrink_to_fit();
179+
mir.temp_decls.shrink_to_fit();
180+
self.super_mir(mir);
181+
}
182+
183+
fn visit_basic_block_data(&mut self, b: BasicBlock, data: &mut BasicBlockData) {
184+
data.statements.shrink_to_fit();
185+
self.super_basic_block_data(b, data);
186+
}
187+
188+
fn visit_terminator(&mut self, b: BasicBlock, terminator: &mut Terminator) {
189+
match *terminator {
190+
Terminator::Switch { ref mut targets, .. } => targets.shrink_to_fit(),
191+
Terminator::SwitchInt { ref mut values, ref mut targets, .. } => {
192+
values.shrink_to_fit();
193+
targets.shrink_to_fit();
194+
},
195+
Terminator::Call { ref mut args, .. } => args.shrink_to_fit(),
196+
_ => {/* nothing to do */}
197+
}
198+
self.super_terminator(b, terminator);
199+
}
200+
201+
fn visit_rvalue(&mut self, rvalue: &mut Rvalue) {
202+
match *rvalue {
203+
Rvalue::Aggregate(_, ref mut operands) => operands.shrink_to_fit(),
204+
_ => { /* nothing to do */ }
205+
}
206+
self.super_rvalue(rvalue);
135207
}
136208
}

0 commit comments

Comments
 (0)