diff --git a/src/librustc_mir/transform/simplify.rs b/src/librustc_mir/transform/simplify.rs index 3a1ccb50465..d8de9f2180d 100644 --- a/src/librustc_mir/transform/simplify.rs +++ b/src/librustc_mir/transform/simplify.rs @@ -95,6 +95,7 @@ pub fn simplify(mut self) { let mut start = START_BLOCK; + let mut merged_blocks = Vec::new(); loop { let mut changed = false; @@ -118,10 +119,23 @@ pub fn simplify(mut self) { while inner_changed { inner_changed = false; inner_changed |= self.simplify_branch(&mut terminator); - inner_changed |= self.merge_successor(bb, &mut terminator); + inner_changed |= self.merge_successor(&mut merged_blocks, &mut terminator); changed |= inner_changed; } + let merged_block_count = + merged_blocks.iter().map(|&i| self.basic_blocks[i].statements.len()).sum(); + + if merged_block_count > 0 { + let mut statements = std::mem::take(&mut self.basic_blocks[bb].statements); + statements.reserve(merged_block_count); + for &from in &merged_blocks { + statements.append(&mut self.basic_blocks[from].statements); + } + self.basic_blocks[bb].statements = statements; + } + merged_blocks.clear(); + self.basic_blocks[bb].terminator = Some(terminator); changed |= inner_changed; @@ -196,7 +210,7 @@ fn collapse_goto_chain(&mut self, start: &mut BasicBlock, changed: &mut bool) { // merge a block with 1 `goto` predecessor to its parent fn merge_successor( &mut self, - merge_into: BasicBlock, + merged_blocks: &mut Vec, terminator: &mut Terminator<'tcx>, ) -> bool { let target = match terminator.kind { @@ -214,8 +228,7 @@ fn merge_successor( } }; - let (from, to) = self.basic_blocks.pick2_mut(target, merge_into); - to.statements.append(&mut from.statements); + merged_blocks.push(target); self.pred_count[target] = 0; true