@@ -134,7 +134,10 @@ impl<'tcx> crate::MirPass<'tcx> for JumpThreading {
134134 finder. entry_states [ bb] = state;
135135 }
136136
137- if let Some ( opportunities) = OpportunitySet :: new ( body, finder. entry_states ) {
137+ let mut entry_states = finder. entry_states ;
138+ simplify_conditions ( body, & mut entry_states) ;
139+
140+ if let Some ( opportunities) = OpportunitySet :: new ( body, entry_states) {
138141 opportunities. apply ( ) ;
139142 }
140143 }
@@ -777,6 +780,91 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> {
777780 }
778781}
779782
783+ /// Propagate fulfilled conditions forward in the CFG to reduce the amount of duplication.
784+ #[ instrument( level = "debug" , skip( body, entry_states) ) ]
785+ fn simplify_conditions ( body : & Body < ' _ > , entry_states : & mut IndexVec < BasicBlock , ConditionSet > ) {
786+ let basic_blocks = & body. basic_blocks ;
787+ let reverse_postorder = basic_blocks. reverse_postorder ( ) ;
788+
789+ // Start by computing the number of *incoming edges* for each block.
790+ // We do not use the cached `basic_blocks.predecessors` as we only want reachable predecessors.
791+ let mut predecessors = IndexVec :: from_elem ( 0 , & entry_states) ;
792+ predecessors[ START_BLOCK ] = 1 ; // Account for the implicit entry edge.
793+ for & bb in reverse_postorder {
794+ let term = basic_blocks[ bb] . terminator ( ) ;
795+ for s in term. successors ( ) {
796+ predecessors[ s] += 1 ;
797+ }
798+ }
799+
800+ // Compute the number of edges into each block that carry each condition.
801+ let mut fulfill_in_pred_count = IndexVec :: from_fn_n (
802+ |bb : BasicBlock | IndexVec :: from_elem_n ( 0 , entry_states[ bb] . targets . len ( ) ) ,
803+ entry_states. len ( ) ,
804+ ) ;
805+
806+ // By traversing in RPO, we increase the likelihood to visit predecessors before successors.
807+ for & bb in reverse_postorder {
808+ let preds = predecessors[ bb] ;
809+ trace ! ( ?bb, ?preds) ;
810+
811+ // We have removed all the input edges towards this block. Just skip visiting it.
812+ if preds == 0 {
813+ continue ;
814+ }
815+
816+ let state = & mut entry_states[ bb] ;
817+ trace ! ( ?state) ;
818+
819+ // Conditions that are fulfilled in all the predecessors, are fulfilled in `bb`.
820+ trace ! ( fulfilled_count = ?fulfill_in_pred_count[ bb] ) ;
821+ for ( condition, & cond_preds) in fulfill_in_pred_count[ bb] . iter_enumerated ( ) {
822+ if cond_preds == preds {
823+ trace ! ( ?condition) ;
824+ state. fulfilled . push ( condition) ;
825+ }
826+ }
827+
828+ // We want to count how many times each condition is fulfilled,
829+ // so ensure we are not counting the same edge twice.
830+ let mut targets: Vec < _ > = state
831+ . fulfilled
832+ . iter ( )
833+ . flat_map ( |& index| state. targets [ index] . iter ( ) . copied ( ) )
834+ . collect ( ) ;
835+ targets. sort ( ) ;
836+ targets. dedup ( ) ;
837+ trace ! ( ?targets) ;
838+
839+ // We may modify the set of successors by applying edges, so track them here.
840+ let mut successors = basic_blocks[ bb] . terminator ( ) . successors ( ) . collect :: < Vec < _ > > ( ) ;
841+
842+ targets. reverse ( ) ;
843+ while let Some ( target) = targets. pop ( ) {
844+ match target {
845+ EdgeEffect :: Goto { target } => {
846+ // We update the count of predecessors. If target or any successor has not been
847+ // processed yet, this increases the likelihood we find something relevant.
848+ predecessors[ target] += 1 ;
849+ for & s in successors. iter ( ) {
850+ predecessors[ s] -= 1 ;
851+ }
852+ // Only process edges that still exist.
853+ targets. retain ( |t| t. block ( ) == target) ;
854+ successors. clear ( ) ;
855+ successors. push ( target) ;
856+ }
857+ EdgeEffect :: Chain { succ_block, succ_condition } => {
858+ // `predecessors` is the number of incoming *edges* in each block.
859+ // Count the number of edges that apply `succ_condition` into `succ_block`.
860+ let count = successors. iter ( ) . filter ( |& & s| s == succ_block) . count ( ) ;
861+ fulfill_in_pred_count[ succ_block] [ succ_condition] += count;
862+ }
863+ }
864+ }
865+ }
866+ }
867+
780868struct OpportunitySet < ' a , ' tcx > {
781869 basic_blocks : & ' a mut IndexVec < BasicBlock , BasicBlockData < ' tcx > > ,
782870 entry_states : IndexVec < BasicBlock , ConditionSet > ,
0 commit comments