diff --git a/src/librustc_mir/transform/simplify.rs b/src/librustc_mir/transform/simplify.rs index f643870dec2..592f721b2f5 100644 --- a/src/librustc_mir/transform/simplify.rs +++ b/src/librustc_mir/transform/simplify.rs @@ -108,10 +108,14 @@ impl<'a, 'tcx: 'a> CfgSimplifier<'a, 'tcx> { pub fn simplify(mut self) { self.strip_nops(); + let mut start = START_BLOCK; + loop { let mut changed = false; - for bb in (0..self.basic_blocks.len()).map(BasicBlock::new) { + self.collapse_goto_chain(&mut start, &mut changed); + + for bb in self.basic_blocks.indices() { if self.pred_count[bb] == 0 { continue } @@ -142,6 +146,27 @@ impl<'a, 'tcx: 'a> CfgSimplifier<'a, 'tcx> { if !changed { break } } + + if start != START_BLOCK { + debug_assert!(self.pred_count[START_BLOCK] == 0); + self.basic_blocks.swap(START_BLOCK, start); + self.pred_count.swap(START_BLOCK, start); + + // pred_count == 1 if the start block has no predecessor _blocks_. + if self.pred_count[START_BLOCK] > 1 { + for (bb, data) in self.basic_blocks.iter_enumerated_mut() { + if self.pred_count[bb] == 0 { + continue; + } + + for target in data.terminator_mut().successors_mut() { + if *target == start { + *target = START_BLOCK; + } + } + } + } + } } // Collapse a goto chain starting from `start` diff --git a/src/test/mir-opt/simplify_cfg.rs b/src/test/mir-opt/simplify_cfg.rs new file mode 100644 index 00000000000..ef843f71581 --- /dev/null +++ b/src/test/mir-opt/simplify_cfg.rs @@ -0,0 +1,54 @@ +// Test that the goto chain starting from bb0 is collapsed. + +fn main() { + loop { + if bar() { + break; + } + } +} + +#[inline(never)] +fn bar() -> bool { + true +} + +// END RUST SOURCE +// START rustc.main.SimplifyCfg-initial.before.mir +// bb0: { +// goto -> bb1; +// } +// bb1: { +// falseUnwind -> [real: bb3, cleanup: bb4]; +// } +// ... +// bb11: { +// ... +// goto -> bb1; +// } +// END rustc.main.SimplifyCfg-initial.before.mir +// START rustc.main.SimplifyCfg-initial.after.mir +// bb0: { +// falseUnwind -> [real: bb1, cleanup: bb2]; +// } +// ... +// bb5: { +// ... +// goto -> bb0; +// } +// END rustc.main.SimplifyCfg-initial.after.mir +// START rustc.main.SimplifyCfg-early-opt.before.mir +// bb0: { +// goto -> bb1; +// } +// bb1: { +// StorageLive(_2); +// _2 = const bar() -> bb3; +// } +// END rustc.main.SimplifyCfg-early-opt.before.mir +// START rustc.main.SimplifyCfg-early-opt.after.mir +// bb0: { +// StorageLive(_2); +// _2 = const bar() -> bb1; +// } +// END rustc.main.SimplifyCfg-early-opt.after.mir