Skip to content

[MIR] Generalize the depth first search logic and use it in all of SimplifyCfg. #30239

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 3 commits into from
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