diff --git a/src/librustc_mir/transform/simplify_cfg.rs b/src/librustc_mir/transform/simplify_cfg.rs index 558276a13a8b8..32eea9d7c8acf 100644 --- a/src/librustc_mir/transform/simplify_cfg.rs +++ b/src/librustc_mir/transform/simplify_cfg.rs @@ -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 @@ -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); @@ -82,7 +61,7 @@ impl SimplifyCfg { } mir.basic_block_data_mut(bb).terminator = terminator; - } + }); changed } @@ -90,7 +69,7 @@ impl SimplifyCfg { 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); @@ -114,7 +93,7 @@ impl SimplifyCfg { } _ => terminator } - } + }); changed } @@ -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 diff --git a/src/librustc_mir/transform/util.rs b/src/librustc_mir/transform/util.rs index 9510269454485..23ba61260e4ae 100644 --- a/src/librustc_mir/transform/util.rs +++ b/src/librustc_mir/transform/util.rs @@ -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(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();