27
27
//! naively generate still contains the `_a = ()` write in the unreachable block "after" the
28
28
//! return.
29
29
30
- use rustc_data_structures:: fx:: FxIndexSet ;
31
30
use rustc_index:: { Idx , IndexSlice , IndexVec } ;
32
31
use rustc_middle:: mir:: visit:: { MutVisitor , MutatingUseContext , PlaceContext , Visitor } ;
33
32
use rustc_middle:: mir:: * ;
@@ -62,9 +61,8 @@ impl SimplifyCfg {
62
61
}
63
62
}
64
63
65
- pub fn simplify_cfg < ' tcx > ( tcx : TyCtxt < ' tcx > , body : & mut Body < ' tcx > ) {
64
+ pub ( crate ) fn simplify_cfg ( body : & mut Body < ' _ > ) {
66
65
CfgSimplifier :: new ( body) . simplify ( ) ;
67
- remove_duplicate_unreachable_blocks ( tcx, body) ;
68
66
remove_dead_blocks ( body) ;
69
67
70
68
// FIXME: Should probably be moved into some kind of pass manager
@@ -76,9 +74,9 @@ impl<'tcx> MirPass<'tcx> for SimplifyCfg {
76
74
self . name ( )
77
75
}
78
76
79
- fn run_pass ( & self , tcx : TyCtxt < ' tcx > , body : & mut Body < ' tcx > ) {
77
+ fn run_pass ( & self , _ : TyCtxt < ' tcx > , body : & mut Body < ' tcx > ) {
80
78
debug ! ( "SimplifyCfg({:?}) - simplifying {:?}" , self . name( ) , body. source) ;
81
- simplify_cfg ( tcx , body) ;
79
+ simplify_cfg ( body) ;
82
80
}
83
81
}
84
82
@@ -289,55 +287,25 @@ pub fn simplify_duplicate_switch_targets(terminator: &mut Terminator<'_>) {
289
287
}
290
288
}
291
289
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
+ } ;
317
299
318
- let unreachable_blocks = body
300
+ let reachable = traversal:: reachable_as_bitset ( body) ;
301
+ let empty_unreachable_blocks = body
319
302
. basic_blocks
320
303
. 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 ( ) ;
336
306
337
- pub fn remove_dead_blocks ( body : & mut Body < ' _ > ) {
338
- let reachable = traversal:: reachable_as_bitset ( body) ;
339
307
let num_blocks = body. basic_blocks . len ( ) ;
340
- if num_blocks == reachable. count ( ) {
308
+ if num_blocks == reachable. count ( ) && empty_unreachable_blocks <= 1 {
341
309
return ;
342
310
}
343
311
@@ -346,14 +314,28 @@ pub fn remove_dead_blocks(body: &mut Body<'_>) {
346
314
let mut replacements: Vec < _ > = ( 0 ..num_blocks) . map ( BasicBlock :: new) . collect ( ) ;
347
315
let mut orig_index = 0 ;
348
316
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
+ }
354
333
}
334
+
335
+ replacements[ orig_index] = used_bb;
336
+ used_index += 1 ;
355
337
orig_index += 1 ;
356
- keep
338
+ true
357
339
} ) ;
358
340
359
341
for block in basic_blocks {
0 commit comments