Skip to content
Closed
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
30 changes: 4 additions & 26 deletions src/librustc_mir/transform/simplify_cfg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,27 +21,6 @@ impl SimplifyCfg {
SimplifyCfg
}

fn remove_dead_blocks(&self, mir: &mut Mir) {
let mut seen = vec![false; mir.basic_blocks.len()];

// These blocks are always required.
seen[START_BLOCK.index()] = true;
seen[END_BLOCK.index()] = true;
seen[DIVERGE_BLOCK.index()] = true;

let mut worklist = vec![START_BLOCK];
while let Some(bb) = worklist.pop() {
for succ in mir.basic_block_data(bb).terminator.successors() {
if !seen[succ.index()] {
seen[succ.index()] = true;
worklist.push(*succ);
}
}
}

util::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
Expand All @@ -66,7 +45,7 @@ impl SimplifyCfg {
}

let mut changed = false;
for bb in mir.all_basic_blocks() {
util::adjust_reachable_basic_blocks(mir, |mir, bb| {
// Temporarily swap out the terminator we're modifying to keep borrowck happy
let mut terminator = Terminator::Diverge;
mem::swap(&mut terminator, &mut mir.basic_block_data_mut(bb).terminator);
Expand All @@ -82,15 +61,15 @@ impl SimplifyCfg {
}

mir.basic_block_data_mut(bb).terminator = terminator;
}
});

changed
}

fn simplify_branches(&self, mir: &mut Mir) -> bool {
let mut changed = false;

for bb in mir.all_basic_blocks() {
util::adjust_reachable_basic_blocks(mir, |mir, bb| {
// Temporarily swap out the terminator we're modifying to keep borrowck happy
let mut terminator = Terminator::Diverge;
mem::swap(&mut terminator, &mut mir.basic_block_data_mut(bb).terminator);
Expand All @@ -114,7 +93,7 @@ impl SimplifyCfg {
}
_ => terminator
}
}
});

changed
}
Expand All @@ -126,7 +105,6 @@ impl<'tcx> MirPass<'tcx> for SimplifyCfg {
while changed {
changed = self.simplify_branches(mir);
changed |= self.remove_goto_chains(mir);
self.remove_dead_blocks(mir);
}

// FIXME: Should probably be moved into some kind of pass manager
Expand Down
25 changes: 25 additions & 0 deletions src/librustc_mir/transform/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,31 @@ pub fn update_basic_block_ids(mir: &mut Mir, replacements: &[BasicBlock]) {
}
}

/// Run a function on every reachable basic block, then delete any unreachable blocks.
/// The function given should not add or remove any blocks from the control flow graph.
pub fn adjust_reachable_basic_blocks<F: FnMut(&mut Mir, BasicBlock)>(mir: &mut Mir, mut func: F) {
let mut seen = vec![false; mir.basic_blocks.len()];

let mut worklist = vec![START_BLOCK];
while let Some(bb) = worklist.pop() {
func(mir, bb);

for succ in mir.basic_block_data(bb).terminator.successors() {
if !seen[succ.index()] {
seen[succ.index()] = true;
worklist.push(*succ);
}
}
}

// These blocks are always required.
seen[START_BLOCK.index()] = true;
seen[END_BLOCK.index()] = true;
seen[DIVERGE_BLOCK.index()] = true;

retain_basic_blocks(mir, &seen);
}

/// Mass removal of basic blocks to keep the ID-remapping cheap.
pub fn retain_basic_blocks(mir: &mut Mir, keep: &[bool]) {
let num_blocks = mir.basic_blocks.len();
Expand Down