@@ -91,43 +91,8 @@ impl<'tcx> MirPass<'tcx> for JumpThreading {
9191 opportunities : Vec :: new ( ) ,
9292 } ;
9393
94- for ( bb, bbdata) in body. basic_blocks . iter_enumerated ( ) {
95- debug ! ( ?bb, term = ?bbdata. terminator( ) ) ;
96- if bbdata. is_cleanup || loop_headers. contains ( bb) {
97- continue ;
98- }
99- let Some ( ( discr, targets) ) = bbdata. terminator ( ) . kind . as_switch ( ) else { continue } ;
100- let Some ( discr) = discr. place ( ) else { continue } ;
101- debug ! ( ?discr, ?bb) ;
102-
103- let discr_ty = discr. ty ( body, tcx) . ty ;
104- let Ok ( discr_layout) = finder. ecx . layout_of ( discr_ty) else { continue } ;
105-
106- let Some ( discr) = finder. map . find ( discr. as_ref ( ) ) else { continue } ;
107- debug ! ( ?discr) ;
108-
109- let cost = CostChecker :: new ( tcx, param_env, None , body) ;
110-
111- let mut state = State :: new ( ConditionSet :: default ( ) , finder. map ) ;
112-
113- let conds = if let Some ( ( value, then, else_) ) = targets. as_static_if ( ) {
114- let Some ( value) = ScalarInt :: try_from_uint ( value, discr_layout. size ) else {
115- continue ;
116- } ;
117- arena. alloc_from_iter ( [
118- Condition { value, polarity : Polarity :: Eq , target : then } ,
119- Condition { value, polarity : Polarity :: Ne , target : else_ } ,
120- ] )
121- } else {
122- arena. alloc_from_iter ( targets. iter ( ) . filter_map ( |( value, target) | {
123- let value = ScalarInt :: try_from_uint ( value, discr_layout. size ) ?;
124- Some ( Condition { value, polarity : Polarity :: Eq , target } )
125- } ) )
126- } ;
127- let conds = ConditionSet ( conds) ;
128- state. insert_value_idx ( discr, conds, finder. map ) ;
129-
130- finder. find_opportunity ( bb, state, cost, 0 ) ;
94+ for bb in body. basic_blocks . indices ( ) {
95+ finder. start_from_switch ( bb) ;
13196 }
13297
13398 let opportunities = finder. opportunities ;
@@ -216,6 +181,46 @@ impl<'tcx, 'a> TOFinder<'tcx, 'a> {
216181 }
217182
218183 /// Recursion entry point to find threading opportunities.
184+ #[ instrument( level = "trace" , skip( self ) ) ]
185+ fn start_from_switch ( & mut self , bb : BasicBlock ) -> Option < !> {
186+ let bbdata = & self . body [ bb] ;
187+ if bbdata. is_cleanup || self . loop_headers . contains ( bb) {
188+ return None ;
189+ }
190+ let ( discr, targets) = bbdata. terminator ( ) . kind . as_switch ( ) ?;
191+ let discr = discr. place ( ) ?;
192+ debug ! ( ?discr, ?bb) ;
193+
194+ let discr_ty = discr. ty ( self . body , self . tcx ) . ty ;
195+ let discr_layout = self . ecx . layout_of ( discr_ty) . ok ( ) ?;
196+
197+ let discr = self . map . find ( discr. as_ref ( ) ) ?;
198+ debug ! ( ?discr) ;
199+
200+ let cost = CostChecker :: new ( self . tcx , self . param_env , None , self . body ) ;
201+ let mut state = State :: new ( ConditionSet :: default ( ) , self . map ) ;
202+
203+ let conds = if let Some ( ( value, then, else_) ) = targets. as_static_if ( ) {
204+ let value = ScalarInt :: try_from_uint ( value, discr_layout. size ) ?;
205+ self . arena . alloc_from_iter ( [
206+ Condition { value, polarity : Polarity :: Eq , target : then } ,
207+ Condition { value, polarity : Polarity :: Ne , target : else_ } ,
208+ ] )
209+ } else {
210+ self . arena . alloc_from_iter ( targets. iter ( ) . filter_map ( |( value, target) | {
211+ let value = ScalarInt :: try_from_uint ( value, discr_layout. size ) ?;
212+ Some ( Condition { value, polarity : Polarity :: Eq , target } )
213+ } ) )
214+ } ;
215+ let conds = ConditionSet ( conds) ;
216+ state. insert_value_idx ( discr, conds, self . map ) ;
217+
218+ self . find_opportunity ( bb, state, cost, 0 ) ;
219+ None
220+ }
221+
222+ /// Recursively walk statements backwards from this bb's terminator to find threading
223+ /// opportunities.
219224 #[ instrument( level = "trace" , skip( self , cost) , ret) ]
220225 fn find_opportunity (
221226 & mut self ,
@@ -270,12 +275,13 @@ impl<'tcx, 'a> TOFinder<'tcx, 'a> {
270275 self . process_switch_int ( discr, targets, bb, & mut state) ;
271276 self . find_opportunity ( pred, state, cost, depth + 1 ) ;
272277 }
273- _ => self . recurse_through_terminator ( pred, & state, & cost, depth) ,
278+ _ => self . recurse_through_terminator ( pred, || state, & cost, depth) ,
274279 }
275- } else {
280+ } else if let & [ ref predecessors @ .. , last_pred ] = & predecessors [ .. ] {
276281 for & pred in predecessors {
277- self . recurse_through_terminator ( pred, & state, & cost, depth) ;
282+ self . recurse_through_terminator ( pred, || state. clone ( ) , & cost, depth) ;
278283 }
284+ self . recurse_through_terminator ( last_pred, || state, & cost, depth) ;
279285 }
280286
281287 let new_tos = & mut self . opportunities [ last_non_rec..] ;
@@ -566,11 +572,12 @@ impl<'tcx, 'a> TOFinder<'tcx, 'a> {
566572 None
567573 }
568574
569- #[ instrument( level = "trace" , skip( self , cost) ) ]
575+ #[ instrument( level = "trace" , skip( self , state , cost) ) ]
570576 fn recurse_through_terminator (
571577 & mut self ,
572578 bb : BasicBlock ,
573- state : & State < ConditionSet < ' a > > ,
579+ // Pass a closure that may clone the state, as we don't want to do it each time.
580+ state : impl FnOnce ( ) -> State < ConditionSet < ' a > > ,
574581 cost : & CostChecker < ' _ , ' tcx > ,
575582 depth : usize ,
576583 ) {
@@ -600,7 +607,7 @@ impl<'tcx, 'a> TOFinder<'tcx, 'a> {
600607 } ;
601608
602609 // We can recurse through this terminator.
603- let mut state = state. clone ( ) ;
610+ let mut state = state ( ) ;
604611 if let Some ( place_to_flood) = place_to_flood {
605612 state. flood_with ( place_to_flood. as_ref ( ) , self . map , ConditionSet :: default ( ) ) ;
606613 }
0 commit comments