2727//! naively generate still contains the `_a = ()` write in the unreachable block "after" the
2828//! return.
2929
30- use rustc_data_structures:: fx:: FxIndexSet ;
3130use rustc_index:: { Idx , IndexSlice , IndexVec } ;
3231use rustc_middle:: mir:: visit:: { MutVisitor , MutatingUseContext , PlaceContext , Visitor } ;
3332use rustc_middle:: mir:: * ;
@@ -62,9 +61,8 @@ impl SimplifyCfg {
6261 }
6362}
6463
65- pub fn simplify_cfg < ' tcx > ( tcx : TyCtxt < ' tcx > , body : & mut Body < ' tcx > ) {
64+ pub ( crate ) fn simplify_cfg ( body : & mut Body < ' _ > ) {
6665 CfgSimplifier :: new ( body) . simplify ( ) ;
67- remove_duplicate_unreachable_blocks ( tcx, body) ;
6866 remove_dead_blocks ( body) ;
6967
7068 // FIXME: Should probably be moved into some kind of pass manager
@@ -76,9 +74,9 @@ impl<'tcx> MirPass<'tcx> for SimplifyCfg {
7674 self . name ( )
7775 }
7876
79- fn run_pass ( & self , tcx : TyCtxt < ' tcx > , body : & mut Body < ' tcx > ) {
77+ fn run_pass ( & self , _ : TyCtxt < ' tcx > , body : & mut Body < ' tcx > ) {
8078 debug ! ( "SimplifyCfg({:?}) - simplifying {:?}" , self . name( ) , body. source) ;
81- simplify_cfg ( tcx , body) ;
79+ simplify_cfg ( body) ;
8280 }
8381}
8482
@@ -289,55 +287,25 @@ pub fn simplify_duplicate_switch_targets(terminator: &mut Terminator<'_>) {
289287 }
290288}
291289
292- pub fn remove_duplicate_unreachable_blocks < ' tcx > ( tcx : TyCtxt < ' tcx > , body : & mut Body < ' tcx > ) {
293- struct OptApplier < ' tcx > {
294- tcx : TyCtxt < ' tcx > ,
295- duplicates : FxIndexSet < BasicBlock > ,
296- }
297-
298- impl < ' tcx > MutVisitor < ' tcx > for OptApplier < ' tcx > {
299- fn tcx ( & self ) -> TyCtxt < ' tcx > {
300- self . tcx
301- }
302-
303- fn visit_terminator ( & mut self , terminator : & mut Terminator < ' tcx > , location : Location ) {
304- for target in terminator. successors_mut ( ) {
305- // We don't have to check whether `target` is a cleanup block, because have
306- // entirely excluded cleanup blocks in building the set of duplicates.
307- if self . duplicates . contains ( target) {
308- * target = self . duplicates [ 0 ] ;
309- }
310- }
311-
312- simplify_duplicate_switch_targets ( terminator) ;
313-
314- self . super_terminator ( terminator, location) ;
315- }
316- }
290+ pub ( crate ) fn remove_dead_blocks ( body : & mut Body < ' _ > ) {
291+ let should_deduplicate_unreachable = |bbdata : & BasicBlockData < ' _ > | {
292+ // CfgSimplifier::simplify leaves behind some unreachable basic blocks without a
293+ // terminator. Those blocks will be deleted by remove_dead_blocks, but we run just
294+ // before then so we need to handle missing terminators.
295+ // We also need to prevent confusing cleanup and non-cleanup blocks. In practice we
296+ // don't emit empty unreachable cleanup blocks, so this simple check suffices.
297+ bbdata. terminator . is_some ( ) && bbdata. is_empty_unreachable ( ) && !bbdata. is_cleanup
298+ } ;
317299
318- let unreachable_blocks = body
300+ let reachable = traversal:: reachable_as_bitset ( body) ;
301+ let empty_unreachable_blocks = body
319302 . basic_blocks
320303 . iter_enumerated ( )
321- . filter ( |( _, bb) | {
322- // CfgSimplifier::simplify leaves behind some unreachable basic blocks without a
323- // terminator. Those blocks will be deleted by remove_dead_blocks, but we run just
324- // before then so we need to handle missing terminators.
325- // We also need to prevent confusing cleanup and non-cleanup blocks. In practice we
326- // don't emit empty unreachable cleanup blocks, so this simple check suffices.
327- bb. terminator . is_some ( ) && bb. is_empty_unreachable ( ) && !bb. is_cleanup
328- } )
329- . map ( |( block, _) | block)
330- . collect :: < FxIndexSet < _ > > ( ) ;
331-
332- if unreachable_blocks. len ( ) > 1 {
333- OptApplier { tcx, duplicates : unreachable_blocks } . visit_body ( body) ;
334- }
335- }
304+ . filter ( |( bb, bbdata) | should_deduplicate_unreachable ( bbdata) && reachable. contains ( * bb) )
305+ . count ( ) ;
336306
337- pub fn remove_dead_blocks ( body : & mut Body < ' _ > ) {
338- let reachable = traversal:: reachable_as_bitset ( body) ;
339307 let num_blocks = body. basic_blocks . len ( ) ;
340- if num_blocks == reachable. count ( ) {
308+ if num_blocks == reachable. count ( ) && empty_unreachable_blocks <= 1 {
341309 return ;
342310 }
343311
@@ -346,14 +314,28 @@ pub fn remove_dead_blocks(body: &mut Body<'_>) {
346314 let mut replacements: Vec < _ > = ( 0 ..num_blocks) . map ( BasicBlock :: new) . collect ( ) ;
347315 let mut orig_index = 0 ;
348316 let mut used_index = 0 ;
349- basic_blocks. raw . retain ( |_| {
350- let keep = reachable. contains ( BasicBlock :: new ( orig_index) ) ;
351- if keep {
352- replacements[ orig_index] = BasicBlock :: new ( used_index) ;
353- used_index += 1 ;
317+ let mut kept_unreachable = None ;
318+ basic_blocks. raw . retain ( |bbdata| {
319+ let orig_bb = BasicBlock :: new ( orig_index) ;
320+ if !reachable. contains ( orig_bb) {
321+ orig_index += 1 ;
322+ return false ;
323+ }
324+
325+ let used_bb = BasicBlock :: new ( used_index) ;
326+ if should_deduplicate_unreachable ( bbdata) {
327+ let kept_unreachable = * kept_unreachable. get_or_insert ( used_bb) ;
328+ if kept_unreachable != used_bb {
329+ replacements[ orig_index] = kept_unreachable;
330+ orig_index += 1 ;
331+ return false ;
332+ }
354333 }
334+
335+ replacements[ orig_index] = used_bb;
336+ used_index += 1 ;
355337 orig_index += 1 ;
356- keep
338+ true
357339 } ) ;
358340
359341 for block in basic_blocks {
0 commit comments