@@ -245,13 +245,13 @@ impl<'a> MakeBcbCounters<'a> {
245245 // the loop. The `traversal` state includes a `context_stack`, providing a way to know if
246246 // the current BCB is in one or more nested loops or not.
247247 let mut traversal = TraverseCoverageGraphWithLoops :: new ( & self . basic_coverage_blocks ) ;
248- while let Some ( bcb) = traversal. next ( self . basic_coverage_blocks ) {
248+ while let Some ( bcb) = traversal. next ( ) {
249249 if bcb_has_coverage_spans ( bcb) {
250250 debug ! ( "{:?} has at least one coverage span. Get or make its counter" , bcb) ;
251251 let branching_counter_operand = self . get_or_make_counter_operand ( bcb) ?;
252252
253253 if self . bcb_needs_branch_counters ( bcb) {
254- self . make_branch_counters ( & mut traversal, bcb, branching_counter_operand) ?;
254+ self . make_branch_counters ( & traversal, bcb, branching_counter_operand) ?;
255255 }
256256 } else {
257257 debug ! (
@@ -274,7 +274,7 @@ impl<'a> MakeBcbCounters<'a> {
274274
275275 fn make_branch_counters (
276276 & mut self ,
277- traversal : & mut TraverseCoverageGraphWithLoops ,
277+ traversal : & TraverseCoverageGraphWithLoops < ' _ > ,
278278 branching_bcb : BasicCoverageBlock ,
279279 branching_counter_operand : Operand ,
280280 ) -> Result < ( ) , Error > {
@@ -507,21 +507,14 @@ impl<'a> MakeBcbCounters<'a> {
507507 /// found, select any branch.
508508 fn choose_preferred_expression_branch (
509509 & self ,
510- traversal : & TraverseCoverageGraphWithLoops ,
510+ traversal : & TraverseCoverageGraphWithLoops < ' _ > ,
511511 branches : & [ BcbBranch ] ,
512512 ) -> BcbBranch {
513- let branch_needs_a_counter = |branch : & BcbBranch | self . branch_has_no_counter ( branch) ;
514-
515- let some_reloop_branch = self . find_some_reloop_branch ( traversal, & branches) ;
516- if let Some ( reloop_branch_without_counter) =
517- some_reloop_branch. filter ( branch_needs_a_counter)
518- {
519- debug ! (
520- "Selecting reloop_branch={:?} that still needs a counter, to get the \
521- `Expression`",
522- reloop_branch_without_counter
523- ) ;
524- reloop_branch_without_counter
513+ let good_reloop_branch = self . find_good_reloop_branch ( traversal, & branches) ;
514+ if let Some ( reloop_branch) = good_reloop_branch {
515+ assert ! ( self . branch_has_no_counter( & reloop_branch) ) ;
516+ debug ! ( "Selecting reloop branch {reloop_branch:?} to get an expression" ) ;
517+ reloop_branch
525518 } else {
526519 let & branch_without_counter =
527520 branches. iter ( ) . find ( |& branch| self . branch_has_no_counter ( branch) ) . expect (
@@ -538,75 +531,52 @@ impl<'a> MakeBcbCounters<'a> {
538531 }
539532 }
540533
541- /// At most, one of the branches (or its edge, from the branching_bcb, if the branch has
542- /// multiple incoming edges) can have a counter computed by expression.
543- ///
544- /// If at least one of the branches leads outside of a loop (`found_loop_exit` is
545- /// true), and at least one other branch does not exit the loop (the first of which
546- /// is captured in `some_reloop_branch`), it's likely any reloop branch will be
547- /// executed far more often than loop exit branch, making the reloop branch a better
548- /// candidate for an expression.
549- fn find_some_reloop_branch (
534+ /// Tries to find a branch that leads back to the top of a loop, and that
535+ /// doesn't already have a counter. Such branches are good candidates to
536+ /// be given an expression (instead of a physical counter), because they
537+ /// will tend to be executed more times than a loop-exit branch.
538+ fn find_good_reloop_branch (
550539 & self ,
551- traversal : & TraverseCoverageGraphWithLoops ,
540+ traversal : & TraverseCoverageGraphWithLoops < ' _ > ,
552541 branches : & [ BcbBranch ] ,
553542 ) -> Option < BcbBranch > {
554- let branch_needs_a_counter = |branch : & BcbBranch | self . branch_has_no_counter ( branch) ;
555-
556- let mut some_reloop_branch: Option < BcbBranch > = None ;
557- for context in traversal. context_stack . iter ( ) . rev ( ) {
558- if let Some ( ( backedge_from_bcbs, _) ) = & context. loop_backedges {
559- let mut found_loop_exit = false ;
560- for & branch in branches. iter ( ) {
561- if backedge_from_bcbs. iter ( ) . any ( |& backedge_from_bcb| {
562- self . bcb_dominates ( branch. target_bcb , backedge_from_bcb)
563- } ) {
564- if let Some ( reloop_branch) = some_reloop_branch {
565- if self . branch_has_no_counter ( & reloop_branch) {
566- // we already found a candidate reloop_branch that still
567- // needs a counter
568- continue ;
569- }
570- }
571- // The path from branch leads back to the top of the loop. Set this
572- // branch as the `reloop_branch`. If this branch already has a
573- // counter, and we find another reloop branch that doesn't have a
574- // counter yet, that branch will be selected as the `reloop_branch`
575- // instead.
576- some_reloop_branch = Some ( branch) ;
577- } else {
578- // The path from branch leads outside this loop
579- found_loop_exit = true ;
580- }
581- if found_loop_exit
582- && some_reloop_branch. filter ( branch_needs_a_counter) . is_some ( )
583- {
584- // Found both a branch that exits the loop and a branch that returns
585- // to the top of the loop (`reloop_branch`), and the `reloop_branch`
586- // doesn't already have a counter.
587- break ;
543+ // Consider each loop on the current traversal context stack, top-down.
544+ for reloop_bcbs in traversal. reloop_bcbs_per_loop ( ) {
545+ let mut all_branches_exit_this_loop = true ;
546+
547+ // Try to find a branch that doesn't exit this loop and doesn't
548+ // already have a counter.
549+ for & branch in branches {
550+ // A branch is a reloop branch if it dominates any BCB that has
551+ // an edge back to the loop header. (Other branches are exits.)
552+ let is_reloop_branch = reloop_bcbs. iter ( ) . any ( |& reloop_bcb| {
553+ self . basic_coverage_blocks . dominates ( branch. target_bcb , reloop_bcb)
554+ } ) ;
555+
556+ if is_reloop_branch {
557+ all_branches_exit_this_loop = false ;
558+ if self . branch_has_no_counter ( & branch) {
559+ // We found a good branch to be given an expression.
560+ return Some ( branch) ;
588561 }
562+ // Keep looking for another reloop branch without a counter.
563+ } else {
564+ // This branch exits the loop.
589565 }
590- if !found_loop_exit {
591- debug ! (
592- "No branches exit the loop, so any branch without an existing \
593- counter can have the `Expression`."
594- ) ;
595- break ;
596- }
597- if some_reloop_branch. is_some ( ) {
598- debug ! (
599- "Found a branch that exits the loop and a branch the loops back to \
600- the top of the loop (`reloop_branch`). The `reloop_branch` will \
601- get the `Expression`, as long as it still needs a counter."
602- ) ;
603- break ;
604- }
605- // else all branches exited this loop context, so run the same checks with
606- // the outer loop(s)
607566 }
567+
568+ if !all_branches_exit_this_loop {
569+ // We found one or more reloop branches, but all of them already
570+ // have counters. Let the caller choose one of the exit branches.
571+ debug ! ( "All reloop branches had counters; skip checking the other loops" ) ;
572+ return None ;
573+ }
574+
575+ // All of the branches exit this loop, so keep looking for a good
576+ // reloop branch for one of the outer loops.
608577 }
609- some_reloop_branch
578+
579+ None
610580 }
611581
612582 #[ inline]
@@ -652,9 +622,4 @@ impl<'a> MakeBcbCounters<'a> {
652622 fn bcb_has_one_path_to_target ( & self , bcb : BasicCoverageBlock ) -> bool {
653623 self . bcb_predecessors ( bcb) . len ( ) <= 1
654624 }
655-
656- #[ inline]
657- fn bcb_dominates ( & self , dom : BasicCoverageBlock , node : BasicCoverageBlock ) -> bool {
658- self . basic_coverage_blocks . dominates ( dom, node)
659- }
660625}
0 commit comments