diff options
| author | Ben Kimock <kimockb@gmail.com> | 2023-02-24 16:32:10 -0500 |
|---|---|---|
| committer | Ben Kimock <kimockb@gmail.com> | 2023-03-18 14:29:04 -0400 |
| commit | 41eda69516dd3ee217ae07c0efa369d31f630405 (patch) | |
| tree | 8e1d53ae15abd9ecdb84afa1164e2898299b95a5 /compiler | |
| parent | 511364e7874dba9649a264100407e4bffe7b5425 (diff) | |
| download | rust-41eda69516dd3ee217ae07c0efa369d31f630405.tar.gz rust-41eda69516dd3ee217ae07c0efa369d31f630405.zip | |
Remove duplicate unreachable blocks
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/rustc_mir_transform/src/simplify.rs | 44 |
1 files changed, 43 insertions, 1 deletions
diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs index 929d229dcdf..c8474a455b5 100644 --- a/compiler/rustc_mir_transform/src/simplify.rs +++ b/compiler/rustc_mir_transform/src/simplify.rs @@ -28,7 +28,7 @@ //! return. use crate::MirPass; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; use rustc_index::vec::{Idx, IndexVec}; use rustc_middle::mir::coverage::*; use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor}; @@ -48,6 +48,7 @@ impl SimplifyCfg { pub fn simplify_cfg<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { CfgSimplifier::new(body).simplify(); + remove_duplicate_unreachable_blocks(tcx, body); remove_dead_blocks(tcx, body); // FIXME: Should probably be moved into some kind of pass manager @@ -259,6 +260,47 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> { } } +pub fn remove_duplicate_unreachable_blocks<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + struct OptApplier<'tcx> { + tcx: TyCtxt<'tcx>, + duplicates: FxIndexSet<BasicBlock>, + } + + impl<'tcx> MutVisitor<'tcx> for OptApplier<'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } + + fn visit_terminator(&mut self, terminator: &mut Terminator<'tcx>, location: Location) { + for target in terminator.successors_mut() { + if self.duplicates.contains(target) { + *target = self.duplicates[0]; + } + } + + self.super_terminator(terminator, location); + } + } + + let unreachable_blocks = body + .basic_blocks + .iter_enumerated() + .filter(|(_, bb)| { + // CfgSimplifier::simplify leaves behind some unreachable basic blocks without a + // terminator. Those blocks will be deleted by remove_dead_blocks, but we run just + // before then so we need to handle missing terminators. + // We also need to prevent confusing cleanup and non-cleanup blocks. In practice we + // don't emit empty unreachable cleanup blocks, so this simple check suffices. + bb.terminator.is_some() && bb.is_empty_unreachable() && !bb.is_cleanup + }) + .map(|(block, _)| block) + .collect::<FxIndexSet<_>>(); + + if unreachable_blocks.len() > 1 { + OptApplier { tcx, duplicates: unreachable_blocks }.visit_body(body); + } +} + pub fn remove_dead_blocks<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { let reachable = traversal::reachable_as_bitset(body); let num_blocks = body.basic_blocks.len(); |
