5151//!
5252//! [libfirm]: <https://pp.ipd.kit.edu/uploads/publikationen/priesner17masterarbeit.pdf>
5353
54- use std:: cell:: OnceCell ;
55-
5654use itertools:: Itertools as _;
5755use rustc_const_eval:: const_eval:: DummyMachine ;
5856use rustc_const_eval:: interpret:: { ImmTy , Immediate , InterpCx , OpTy , Projectable } ;
@@ -100,7 +98,6 @@ impl<'tcx> crate::MirPass<'tcx> for JumpThreading {
10098 map : Map :: new ( tcx, body, Some ( MAX_PLACES ) ) ,
10199 maybe_loop_headers : maybe_loop_headers ( body) ,
102100 entry_states : IndexVec :: from_elem ( ConditionSet :: default ( ) , & body. basic_blocks ) ,
103- costs : IndexVec :: from_elem ( OnceCell :: new ( ) , & body. basic_blocks ) ,
104101 } ;
105102
106103 for ( bb, bbdata) in traversal:: postorder ( body) {
@@ -136,6 +133,7 @@ impl<'tcx> crate::MirPass<'tcx> for JumpThreading {
136133
137134 let mut entry_states = finder. entry_states ;
138135 simplify_conditions ( body, & mut entry_states) ;
136+ remove_costly_conditions ( tcx, typing_env, body, & mut entry_states) ;
139137
140138 if let Some ( opportunities) = OpportunitySet :: new ( body, entry_states) {
141139 opportunities. apply ( ) ;
@@ -159,8 +157,6 @@ struct TOFinder<'a, 'tcx> {
159157 // Invariant: for each `bb`, each condition in `entry_states[bb]` has a `chain` that
160158 // starts with `bb`.
161159 entry_states : IndexVec < BasicBlock , ConditionSet > ,
162- /// Pre-computed cost of duplicating each block.
163- costs : IndexVec < BasicBlock , OnceCell < usize > > ,
164160}
165161
166162rustc_index:: newtype_index! {
@@ -222,7 +218,6 @@ struct ConditionSet {
222218 active : Vec < ( ConditionIndex , Condition ) > ,
223219 fulfilled : Vec < ConditionIndex > ,
224220 targets : IndexVec < ConditionIndex , Vec < EdgeEffect > > ,
225- costs : IndexVec < ConditionIndex , u8 > ,
226221}
227222
228223impl ConditionSet {
@@ -233,7 +228,6 @@ impl ConditionSet {
233228 #[ tracing:: instrument( level = "trace" , skip( self ) ) ]
234229 fn push_condition ( & mut self , c : Condition , target : BasicBlock ) {
235230 let index = self . targets . push ( vec ! [ EdgeEffect :: Goto { target } ] ) ;
236- self . costs . push ( 0 ) ;
237231 self . active . push ( ( index, c) ) ;
238232 }
239233
@@ -293,21 +287,18 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> {
293287 active : Vec :: with_capacity ( state_len) ,
294288 targets : IndexVec :: with_capacity ( state_len) ,
295289 fulfilled : Vec :: new ( ) ,
296- costs : IndexVec :: with_capacity ( state_len) ,
297290 } ;
298291
299292 // Use an index-set to deduplicate conditions coming from different successor blocks.
300293 let mut known_conditions =
301294 FxIndexSet :: with_capacity_and_hasher ( state_len, Default :: default ( ) ) ;
302- let mut insert = |condition, succ_block, succ_condition, cost | {
295+ let mut insert = |condition, succ_block, succ_condition| {
303296 let ( index, new) = known_conditions. insert_full ( condition) ;
304297 let index = ConditionIndex :: from_usize ( index) ;
305298 if new {
306299 state. active . push ( ( index, condition) ) ;
307300 let _index = state. targets . push ( Vec :: new ( ) ) ;
308301 debug_assert_eq ! ( _index, index) ;
309- let _index = state. costs . push ( u8:: MAX ) ;
310- debug_assert_eq ! ( _index, index) ;
311302 }
312303 let target = EdgeEffect :: Chain { succ_block, succ_condition } ;
313304 debug_assert ! (
@@ -316,7 +307,6 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> {
316307 & state. targets[ index] ,
317308 ) ;
318309 state. targets [ index] . push ( target) ;
319- state. costs [ index] = std:: cmp:: min ( state. costs [ index] , cost) ;
320310 } ;
321311
322312 // A given block may have several times the same successor.
@@ -331,35 +321,19 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> {
331321 continue ;
332322 }
333323
334- let succ_cost = self . cost ( succ) ;
335324 for & ( succ_index, cond) in self . entry_states [ succ] . active . iter ( ) {
336- let cost = self . entry_states [ succ] . costs [ succ_index] ;
337- if let Ok ( cost) = ( ( cost as usize ) + succ_cost) . try_into ( )
338- && cost < MAX_COST
339- {
340- insert ( cond, succ, succ_index, cost) ;
341- }
325+ insert ( cond, succ, succ_index) ;
342326 }
343327 }
344328
345329 let num_conditions = known_conditions. len ( ) ;
346330 debug_assert_eq ! ( num_conditions, state. active. len( ) ) ;
347331 debug_assert_eq ! ( num_conditions, state. targets. len( ) ) ;
348- debug_assert_eq ! ( num_conditions, state. costs. len( ) ) ;
349332 state. fulfilled . reserve ( num_conditions) ;
350333
351334 state
352335 }
353336
354- fn cost ( & self , bb : BasicBlock ) -> usize {
355- * self . costs [ bb] . get_or_init ( || {
356- let bbdata = & self . body [ bb] ;
357- let mut cost = CostChecker :: new ( self . tcx , self . typing_env , None , self . body ) ;
358- cost. visit_basic_block_data ( bb, bbdata) ;
359- cost. cost ( )
360- } )
361- }
362-
363337 /// Remove all conditions in the state that alias given place.
364338 fn flood_state (
365339 & self ,
@@ -751,8 +725,6 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> {
751725 // Fulfilling `index` may thread conditions that we do not want,
752726 // so create a brand new index to immediately mark fulfilled.
753727 let index = state. targets . push ( new_edges) ;
754- let _index = state. costs . push ( 0 ) ;
755- debug_assert_eq ! ( _index, index) ;
756728 state. fulfilled . push ( index) ;
757729 }
758730 }
@@ -865,6 +837,82 @@ fn simplify_conditions(body: &Body<'_>, entry_states: &mut IndexVec<BasicBlock,
865837 }
866838}
867839
840+ #[ instrument( level = "debug" , skip( tcx, typing_env, body, entry_states) ) ]
841+ fn remove_costly_conditions < ' tcx > (
842+ tcx : TyCtxt < ' tcx > ,
843+ typing_env : ty:: TypingEnv < ' tcx > ,
844+ body : & Body < ' tcx > ,
845+ entry_states : & mut IndexVec < BasicBlock , ConditionSet > ,
846+ ) {
847+ let basic_blocks = & body. basic_blocks ;
848+
849+ let mut costs = IndexVec :: from_elem ( None , basic_blocks) ;
850+ let mut cost = |bb : BasicBlock | -> u8 {
851+ let c = * costs[ bb] . get_or_insert_with ( || {
852+ let bbdata = & basic_blocks[ bb] ;
853+ let mut cost = CostChecker :: new ( tcx, typing_env, None , body) ;
854+ cost. visit_basic_block_data ( bb, bbdata) ;
855+ cost. cost ( ) . try_into ( ) . unwrap_or ( MAX_COST )
856+ } ) ;
857+ trace ! ( "cost[{bb:?}] = {c}" ) ;
858+ c
859+ } ;
860+
861+ // Initialize costs with `MAX_COST`: if we have a cycle, the cyclic `bb` has infinite costs.
862+ let mut condition_cost = IndexVec :: from_fn_n (
863+ |bb : BasicBlock | IndexVec :: from_elem_n ( MAX_COST , entry_states[ bb] . targets . len ( ) ) ,
864+ entry_states. len ( ) ,
865+ ) ;
866+
867+ let reverse_postorder = basic_blocks. reverse_postorder ( ) ;
868+
869+ for & bb in reverse_postorder. iter ( ) . rev ( ) {
870+ let state = & entry_states[ bb] ;
871+ trace ! ( ?bb, ?state) ;
872+
873+ let mut current_costs = IndexVec :: from_elem ( 0u8 , & state. targets ) ;
874+
875+ for ( condition, targets) in state. targets . iter_enumerated ( ) {
876+ for & target in targets {
877+ match target {
878+ // A `Goto` has cost 0.
879+ EdgeEffect :: Goto { .. } => { }
880+ // Chaining into an already-fulfilled condition is nop.
881+ EdgeEffect :: Chain { succ_block, succ_condition }
882+ if entry_states[ succ_block] . fulfilled . contains ( & succ_condition) => { }
883+ // When chaining, use `cost[succ_block][succ_condition] + cost(succ_block)`.
884+ EdgeEffect :: Chain { succ_block, succ_condition } => {
885+ // Cost associated with duplicating `succ_block`.
886+ let duplication_cost = cost ( succ_block) ;
887+ // Cost associated with the rest of the chain.
888+ let target_cost =
889+ * condition_cost[ succ_block] . get ( succ_condition) . unwrap_or ( & MAX_COST ) ;
890+ let cost = current_costs[ condition]
891+ . saturating_add ( duplication_cost)
892+ . saturating_add ( target_cost) ;
893+ trace ! ( ?condition, ?succ_block, ?duplication_cost, ?target_cost) ;
894+ current_costs[ condition] = cost;
895+ }
896+ }
897+ }
898+ }
899+
900+ trace ! ( "condition_cost[{bb:?}] = {:?}" , current_costs) ;
901+ condition_cost[ bb] = current_costs;
902+ }
903+
904+ trace ! ( ?condition_cost) ;
905+
906+ for & bb in reverse_postorder {
907+ for ( index, targets) in entry_states[ bb] . targets . iter_enumerated_mut ( ) {
908+ if condition_cost[ bb] [ index] >= MAX_COST {
909+ trace ! ( ?bb, ?index, ?targets, c = ?condition_cost[ bb] [ index] , "remove" ) ;
910+ targets. clear ( )
911+ }
912+ }
913+ }
914+ }
915+
868916struct OpportunitySet < ' a , ' tcx > {
869917 basic_blocks : & ' a mut IndexVec < BasicBlock , BasicBlockData < ' tcx > > ,
870918 entry_states : IndexVec < BasicBlock , ConditionSet > ,
@@ -887,7 +935,6 @@ impl<'a, 'tcx> OpportunitySet<'a, 'tcx> {
887935 // Free some memory, because we will need to clone condition sets.
888936 for state in entry_states. iter_mut ( ) {
889937 state. active = Default :: default ( ) ;
890- state. costs = Default :: default ( ) ;
891938 }
892939 let duplicates = Default :: default ( ) ;
893940 let basic_blocks = body. basic_blocks . as_mut ( ) ;
0 commit comments