@@ -234,21 +234,17 @@ impl<'tcx, 'a> TOFinder<'tcx, 'a> {
234234
235235 let predecessors = & self . body . basic_blocks . predecessors ( ) [ bb] ;
236236 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 ) ;
241242 }
242- _ => { }
243+ _ => self . recurse_through_terminator ( pred , & state , & cost , depth ) ,
243244 }
244245 } else {
245246 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) ;
252248 }
253249 }
254250
@@ -464,43 +460,97 @@ impl<'tcx, 'a> TOFinder<'tcx, 'a> {
464460 None
465461 }
466462
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 :: CoroutineDrop => 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+
467517 #[ instrument( level = "trace" , skip( self ) ) ]
468518 fn process_switch_int (
469519 & mut self ,
470- state : State < ConditionSet < ' a > > ,
471520 discr : & Operand < ' tcx > ,
472521 targets : & SwitchTargets ,
473- bb : BasicBlock ,
522+ target_bb : BasicBlock ,
523+ state : & mut State < ConditionSet < ' a > > ,
474524 ) -> 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 ) ;
477527
478528 let discr = discr. place ( ) ?;
479529 let discr_ty = discr. ty ( self . body , self . tcx ) . ty ;
480530 let discr_layout = self . tcx . layout_of ( self . param_env . and ( discr_ty) ) . ok ( ) ?;
481531 let conditions = state. try_get ( discr. as_ref ( ) , self . map ) ?;
482532
483- if let Some ( ( value, _) ) = targets. iter ( ) . find ( |& ( _, target) | target == bb ) {
533+ if let Some ( ( value, _) ) = targets. iter ( ) . find ( |& ( _, target) | target == target_bb ) {
484534 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 ) ;
486536
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
488538 // through the `SwitchInt` before arriving here. Therefore, we know that
489539 // `discr == value`. If one condition can be fulfilled by `discr == value`,
490540 // that's an opportunity.
491541 for c in conditions. iter_matches ( value) {
492- debug ! ( ?bb , ?c. target, "register" ) ;
542+ debug ! ( ?target_bb , ?c. target, "register" ) ;
493543 self . opportunities . push ( ThreadingOpportunity { chain : vec ! [ ] , target : c. target } ) ;
494544 }
495- } else if bb == targets. otherwise ( ) {
545+ } else if target_bb == targets. otherwise ( ) {
496546 let ( value, _, _) = targets. as_static_if ( ) ?;
497547 let value = ScalarInt :: try_from_uint ( value, discr_layout. size ) ?;
498548
499549 // Likewise, we know that `discr != value`. That's a must weaker information,
500550 // so we can only match the exact same condition.
501551 for c in conditions. iter ( ) {
502552 if c. value == value && c. polarity == false {
503- debug ! ( ?bb , ?c. target, "register" ) ;
553+ debug ! ( ?target_bb , ?c. target, "register" ) ;
504554 self . opportunities
505555 . push ( ThreadingOpportunity { chain : vec ! [ ] , target : c. target } ) ;
506556 }
0 commit comments