@@ -234,21 +234,17 @@ impl<'tcx, 'a> TOFinder<'tcx, 'a> {
234
234
235
235
let predecessors = & self . body . basic_blocks . predecessors ( ) [ bb] ;
236
236
if let & [ pred] = & predecessors[ ..] && bb != START_BLOCK {
237
- match & self . body . basic_blocks [ pred] . terminator ( ) . kind {
238
- TerminatorKind :: Goto { .. } => self . find_opportunity ( pred, state, cost, depth) ,
239
- TerminatorKind :: SwitchInt { discr, targets } => {
240
- self . process_switch_int ( state, discr, targets, bb) ;
237
+ let term = self . body . basic_blocks [ pred] . terminator ( ) ;
238
+ match term. kind {
239
+ TerminatorKind :: SwitchInt { ref discr, ref targets } => {
240
+ self . process_switch_int ( discr, targets, bb, & mut state) ;
241
+ self . find_opportunity ( pred, state, cost, depth + 1 ) ;
241
242
}
242
- _ => { }
243
+ _ => self . recurse_through_terminator ( pred , & state , & cost , depth ) ,
243
244
}
244
245
} else {
245
246
for & pred in predecessors {
246
- if matches ! (
247
- self . body. basic_blocks[ pred] . terminator( ) . kind,
248
- TerminatorKind :: Goto { .. }
249
- ) {
250
- self . find_opportunity ( pred, state. clone ( ) , cost. clone ( ) , depth + 1 ) ;
251
- }
247
+ self . recurse_through_terminator ( pred, & state, & cost, depth) ;
252
248
}
253
249
}
254
250
@@ -464,43 +460,97 @@ impl<'tcx, 'a> TOFinder<'tcx, 'a> {
464
460
None
465
461
}
466
462
463
+ #[ instrument( level = "trace" , skip( self , cost) ) ]
464
+ fn recurse_through_terminator (
465
+ & mut self ,
466
+ bb : BasicBlock ,
467
+ state : & State < ConditionSet < ' a > > ,
468
+ cost : & CostChecker < ' _ , ' tcx > ,
469
+ depth : usize ,
470
+ ) {
471
+ let register_opportunity = |c : Condition | {
472
+ debug ! ( ?bb, ?c. target, "register" ) ;
473
+ self . opportunities . push ( ThreadingOpportunity { chain : vec ! [ bb] , target : c. target } )
474
+ } ;
475
+
476
+ let term = self . body . basic_blocks [ bb] . terminator ( ) ;
477
+ let place_to_flood = match term. kind {
478
+ // We come from a target, so those are not possible.
479
+ TerminatorKind :: UnwindResume
480
+ | TerminatorKind :: UnwindTerminate ( _)
481
+ | TerminatorKind :: Return
482
+ | TerminatorKind :: Unreachable
483
+ | TerminatorKind :: GeneratorDrop => bug ! ( "{term:?} has no terminators" ) ,
484
+ // Disallowed during optimizations.
485
+ TerminatorKind :: FalseEdge { .. }
486
+ | TerminatorKind :: FalseUnwind { .. }
487
+ | TerminatorKind :: Yield { .. } => bug ! ( "{term:?} invalid" ) ,
488
+ // Cannot reason about inline asm.
489
+ TerminatorKind :: InlineAsm { .. } => return ,
490
+ // `SwitchInt` is handled specially.
491
+ TerminatorKind :: SwitchInt { .. } => return ,
492
+ // We can recurse, no thing particular to do.
493
+ TerminatorKind :: Goto { .. } => None ,
494
+ // Flood the overwritten place, and progress through.
495
+ TerminatorKind :: Drop { place : destination, .. }
496
+ | TerminatorKind :: Call { destination, .. } => Some ( destination) ,
497
+ // Treat as an `assume(cond == expected)`.
498
+ TerminatorKind :: Assert { ref cond, expected, .. } => {
499
+ if let Some ( place) = cond. place ( )
500
+ && let Some ( conditions) = state. try_get ( place. as_ref ( ) , self . map )
501
+ {
502
+ let expected = if expected { ScalarInt :: TRUE } else { ScalarInt :: FALSE } ;
503
+ conditions. iter_matches ( expected) . for_each ( register_opportunity) ;
504
+ }
505
+ None
506
+ }
507
+ } ;
508
+
509
+ // We can recurse through this terminator.
510
+ let mut state = state. clone ( ) ;
511
+ if let Some ( place_to_flood) = place_to_flood {
512
+ state. flood_with ( place_to_flood. as_ref ( ) , self . map , ConditionSet :: default ( ) ) ;
513
+ }
514
+ self . find_opportunity ( bb, state, cost. clone ( ) , depth + 1 ) ;
515
+ }
516
+
467
517
#[ instrument( level = "trace" , skip( self ) ) ]
468
518
fn process_switch_int (
469
519
& mut self ,
470
- state : State < ConditionSet < ' a > > ,
471
520
discr : & Operand < ' tcx > ,
472
521
targets : & SwitchTargets ,
473
- bb : BasicBlock ,
522
+ target_bb : BasicBlock ,
523
+ state : & mut State < ConditionSet < ' a > > ,
474
524
) -> Option < !> {
475
- debug_assert_ne ! ( bb , START_BLOCK ) ;
476
- debug_assert_eq ! ( self . body. basic_blocks. predecessors( ) [ bb ] . len( ) , 1 ) ;
525
+ debug_assert_ne ! ( target_bb , START_BLOCK ) ;
526
+ debug_assert_eq ! ( self . body. basic_blocks. predecessors( ) [ target_bb ] . len( ) , 1 ) ;
477
527
478
528
let discr = discr. place ( ) ?;
479
529
let discr_ty = discr. ty ( self . body , self . tcx ) . ty ;
480
530
let discr_layout = self . tcx . layout_of ( self . param_env . and ( discr_ty) ) . ok ( ) ?;
481
531
let conditions = state. try_get ( discr. as_ref ( ) , self . map ) ?;
482
532
483
- if let Some ( ( value, _) ) = targets. iter ( ) . find ( |& ( _, target) | target == bb ) {
533
+ if let Some ( ( value, _) ) = targets. iter ( ) . find ( |& ( _, target) | target == target_bb ) {
484
534
let value = ScalarInt :: try_from_uint ( value, discr_layout. size ) ?;
485
- debug_assert_eq ! ( targets. iter( ) . filter( |& ( _, target) | target == bb ) . count( ) , 1 ) ;
535
+ debug_assert_eq ! ( targets. iter( ) . filter( |& ( _, target) | target == target_bb ) . count( ) , 1 ) ;
486
536
487
- // We are inside `bb `. Since we have a single predecessor, we know we passed
537
+ // We are inside `target_bb `. Since we have a single predecessor, we know we passed
488
538
// through the `SwitchInt` before arriving here. Therefore, we know that
489
539
// `discr == value`. If one condition can be fulfilled by `discr == value`,
490
540
// that's an opportunity.
491
541
for c in conditions. iter_matches ( value) {
492
- debug ! ( ?bb , ?c. target, "register" ) ;
542
+ debug ! ( ?target_bb , ?c. target, "register" ) ;
493
543
self . opportunities . push ( ThreadingOpportunity { chain : vec ! [ ] , target : c. target } ) ;
494
544
}
495
- } else if bb == targets. otherwise ( ) {
545
+ } else if target_bb == targets. otherwise ( ) {
496
546
let ( value, _, _) = targets. as_static_if ( ) ?;
497
547
let value = ScalarInt :: try_from_uint ( value, discr_layout. size ) ?;
498
548
499
549
// Likewise, we know that `discr != value`. That's a must weaker information,
500
550
// so we can only match the exact same condition.
501
551
for c in conditions. iter ( ) {
502
552
if c. value == value && c. polarity == false {
503
- debug ! ( ?bb , ?c. target, "register" ) ;
553
+ debug ! ( ?target_bb , ?c. target, "register" ) ;
504
554
self . opportunities
505
555
. push ( ThreadingOpportunity { chain : vec ! [ ] , target : c. target } ) ;
506
556
}
0 commit comments