@@ -245,13 +245,13 @@ impl<'a> MakeBcbCounters<'a> {
245
245
// the loop. The `traversal` state includes a `context_stack`, providing a way to know if
246
246
// the current BCB is in one or more nested loops or not.
247
247
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 ( ) {
249
249
if bcb_has_coverage_spans ( bcb) {
250
250
debug ! ( "{:?} has at least one coverage span. Get or make its counter" , bcb) ;
251
251
let branching_counter_operand = self . get_or_make_counter_operand ( bcb) ?;
252
252
253
253
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) ?;
255
255
}
256
256
} else {
257
257
debug ! (
@@ -274,7 +274,7 @@ impl<'a> MakeBcbCounters<'a> {
274
274
275
275
fn make_branch_counters (
276
276
& mut self ,
277
- traversal : & mut TraverseCoverageGraphWithLoops ,
277
+ traversal : & TraverseCoverageGraphWithLoops < ' _ > ,
278
278
branching_bcb : BasicCoverageBlock ,
279
279
branching_counter_operand : Operand ,
280
280
) -> Result < ( ) , Error > {
@@ -507,21 +507,14 @@ impl<'a> MakeBcbCounters<'a> {
507
507
/// found, select any branch.
508
508
fn choose_preferred_expression_branch (
509
509
& self ,
510
- traversal : & TraverseCoverageGraphWithLoops ,
510
+ traversal : & TraverseCoverageGraphWithLoops < ' _ > ,
511
511
branches : & [ BcbBranch ] ,
512
512
) -> 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
525
518
} else {
526
519
let & branch_without_counter =
527
520
branches. iter ( ) . find ( |& branch| self . branch_has_no_counter ( branch) ) . expect (
@@ -538,75 +531,52 @@ impl<'a> MakeBcbCounters<'a> {
538
531
}
539
532
}
540
533
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 (
550
539
& self ,
551
- traversal : & TraverseCoverageGraphWithLoops ,
540
+ traversal : & TraverseCoverageGraphWithLoops < ' _ > ,
552
541
branches : & [ BcbBranch ] ,
553
542
) -> 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) ;
588
561
}
562
+ // Keep looking for another reloop branch without a counter.
563
+ } else {
564
+ // This branch exits the loop.
589
565
}
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)
607
566
}
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.
608
577
}
609
- some_reloop_branch
578
+
579
+ None
610
580
}
611
581
612
582
#[ inline]
@@ -652,9 +622,4 @@ impl<'a> MakeBcbCounters<'a> {
652
622
fn bcb_has_one_path_to_target ( & self , bcb : BasicCoverageBlock ) -> bool {
653
623
self . bcb_predecessors ( bcb) . len ( ) <= 1
654
624
}
655
-
656
- #[ inline]
657
- fn bcb_dominates ( & self , dom : BasicCoverageBlock , node : BasicCoverageBlock ) -> bool {
658
- self . basic_coverage_blocks . dominates ( dom, node)
659
- }
660
625
}
0 commit comments