@@ -253,12 +253,6 @@ impl<'a> MakeBcbCounters<'a> {
253
253
Self { coverage_counters, basic_coverage_blocks }
254
254
}
255
255
256
- /// If two `BasicCoverageBlock`s branch from another `BasicCoverageBlock`, one of the branches
257
- /// can be counted by `Expression` by subtracting the other branch from the branching
258
- /// block. Otherwise, the `BasicCoverageBlock` executed the least should have the `Counter`.
259
- /// One way to predict which branch executes the least is by considering loops. A loop is exited
260
- /// at a branch, so the branch that jumps to a `BasicCoverageBlock` outside the loop is almost
261
- /// always executed less than the branch that does not exit the loop.
262
256
fn make_bcb_counters ( & mut self , bcb_needs_counter : impl Fn ( BasicCoverageBlock ) -> bool ) {
263
257
debug ! ( "make_bcb_counters(): adding a counter or expression to each BasicCoverageBlock" ) ;
264
258
@@ -273,7 +267,7 @@ impl<'a> MakeBcbCounters<'a> {
273
267
while let Some ( bcb) = traversal. next ( ) {
274
268
let _span = debug_span ! ( "traversal" , ?bcb) . entered ( ) ;
275
269
if bcb_needs_counter ( bcb) {
276
- self . make_node_and_branch_counters ( & traversal, bcb) ;
270
+ self . make_node_counter_and_out_edge_counters ( & traversal, bcb) ;
277
271
}
278
272
}
279
273
@@ -284,74 +278,66 @@ impl<'a> MakeBcbCounters<'a> {
284
278
) ;
285
279
}
286
280
281
+ /// Make sure the given node has a node counter, and then make sure each of
282
+ /// its out-edges has an edge counter (if appropriate).
287
283
#[ instrument( level = "debug" , skip( self , traversal) ) ]
288
- fn make_node_and_branch_counters (
284
+ fn make_node_counter_and_out_edge_counters (
289
285
& mut self ,
290
286
traversal : & TraverseCoverageGraphWithLoops < ' _ > ,
291
287
from_bcb : BasicCoverageBlock ,
292
288
) {
293
289
// First, ensure that this node has a counter of some kind.
294
- // We might also use its term later to compute one of the branch counters.
290
+ // We might also use that counter to compute one of the out-edge counters.
295
291
let from_bcb_operand = self . get_or_make_counter_operand ( from_bcb) ;
296
292
297
- let branch_target_bcbs = self . basic_coverage_blocks . successors [ from_bcb] . as_slice ( ) ;
293
+ let successors = self . basic_coverage_blocks . successors [ from_bcb] . as_slice ( ) ;
298
294
299
295
// If this node doesn't have multiple out-edges, or all of its out-edges
300
296
// already have counters, then we don't need to create edge counters.
301
- let needs_branch_counters = branch_target_bcbs. len ( ) > 1
302
- && branch_target_bcbs
303
- . iter ( )
304
- . any ( |& to_bcb| self . branch_has_no_counter ( from_bcb, to_bcb) ) ;
305
- if !needs_branch_counters {
297
+ let needs_out_edge_counters = successors. len ( ) > 1
298
+ && successors. iter ( ) . any ( |& to_bcb| self . edge_has_no_counter ( from_bcb, to_bcb) ) ;
299
+ if !needs_out_edge_counters {
306
300
return ;
307
301
}
308
302
309
- debug ! (
310
- "{from_bcb:?} has some branch(es) without counters:\n {}" ,
311
- branch_target_bcbs
312
- . iter( )
313
- . map( |& to_bcb| {
314
- format!( "{from_bcb:?}->{to_bcb:?}: {:?}" , self . branch_counter( from_bcb, to_bcb) )
315
- } )
316
- . collect:: <Vec <_>>( )
317
- . join( "\n " ) ,
318
- ) ;
303
+ if tracing:: enabled!( tracing:: Level :: DEBUG ) {
304
+ let _span =
305
+ debug_span ! ( "node has some out-edges without counters" , ?from_bcb) . entered ( ) ;
306
+ for & to_bcb in successors {
307
+ debug ! ( ?to_bcb, counter=?self . edge_counter( from_bcb, to_bcb) ) ;
308
+ }
309
+ }
319
310
320
- // Of the branch edges that don't have counters yet, one can be given an expression
321
- // (computed from the other edges) instead of a dedicated counter.
322
- let expression_to_bcb = self . choose_preferred_expression_branch ( traversal, from_bcb) ;
311
+ // Of the out- edges that don't have counters yet, one can be given an expression
312
+ // (computed from the other out- edges) instead of a dedicated counter.
313
+ let expression_to_bcb = self . choose_out_edge_for_expression ( traversal, from_bcb) ;
323
314
324
- // For each branch arm other than the one that was chosen to get an expression,
315
+ // For each out-edge other than the one that was chosen to get an expression,
325
316
// ensure that it has a counter (existing counter/expression or a new counter),
326
- // and accumulate the corresponding terms into a single sum term .
327
- let sum_of_all_other_branches : BcbCounter = {
328
- let _span = debug_span ! ( "sum_of_all_other_branches " , ?expression_to_bcb) . entered ( ) ;
329
- branch_target_bcbs
317
+ // and accumulate the corresponding counters into a single sum expression .
318
+ let sum_of_all_other_out_edges : BcbCounter = {
319
+ let _span = debug_span ! ( "sum_of_all_other_out_edges " , ?expression_to_bcb) . entered ( ) ;
320
+ successors
330
321
. iter ( )
331
322
. copied ( )
332
- // Skip the chosen branch , since we'll calculate it from the other branches .
323
+ // Skip the chosen edge , since we'll calculate its count from this sum .
333
324
. filter ( |& to_bcb| to_bcb != expression_to_bcb)
334
325
. fold ( None , |accum, to_bcb| {
335
326
let _span = debug_span ! ( "to_bcb" , ?accum, ?to_bcb) . entered ( ) ;
336
- let branch_counter = self . get_or_make_edge_counter_operand ( from_bcb, to_bcb) ;
337
- Some ( self . coverage_counters . make_sum_expression ( accum, branch_counter ) )
327
+ let edge_counter = self . get_or_make_edge_counter_operand ( from_bcb, to_bcb) ;
328
+ Some ( self . coverage_counters . make_sum_expression ( accum, edge_counter ) )
338
329
} )
339
- . expect ( "there must be at least one other branch " )
330
+ . expect ( "there must be at least one other out-edge " )
340
331
} ;
341
332
342
- // For the branch that was chosen to get an expression, create that expression
343
- // by taking the count of the node we're branching from, and subtracting the
344
- // sum of all the other branches.
345
- debug ! (
346
- "Making an expression for the selected expression_branch: \
347
- {expression_to_bcb:?} (expression_branch predecessors: {:?})",
348
- self . bcb_predecessors( expression_to_bcb) ,
349
- ) ;
333
+ // Now create an expression for the chosen edge, by taking the counter
334
+ // for its source node and subtracting the sum of its sibling out-edges.
350
335
let expression = self . coverage_counters . make_expression (
351
336
from_bcb_operand,
352
337
Op :: Subtract ,
353
- sum_of_all_other_branches ,
338
+ sum_of_all_other_out_edges ,
354
339
) ;
340
+
355
341
debug ! ( "{expression_to_bcb:?} gets an expression: {expression:?}" ) ;
356
342
if self . basic_coverage_blocks . bcb_has_multiple_in_edges ( expression_to_bcb) {
357
343
self . coverage_counters . set_bcb_edge_counter ( from_bcb, expression_to_bcb, expression) ;
@@ -442,82 +428,79 @@ impl<'a> MakeBcbCounters<'a> {
442
428
self . coverage_counters . set_bcb_edge_counter ( from_bcb, to_bcb, counter_kind)
443
429
}
444
430
445
- /// Select a branch for the expression, either the recommended `reloop_branch`, or if none was
446
- /// found, select any branch.
447
- fn choose_preferred_expression_branch (
431
+ /// Choose one of the out-edges of `from_bcb` to receive an expression
432
+ /// instead of a physical counter, and returns that edge's target node.
433
+ ///
434
+ /// - Precondition: The node must have at least one out-edge without a counter.
435
+ /// - Postcondition: The selected edge does not have an edge counter.
436
+ fn choose_out_edge_for_expression (
448
437
& self ,
449
438
traversal : & TraverseCoverageGraphWithLoops < ' _ > ,
450
439
from_bcb : BasicCoverageBlock ,
451
440
) -> BasicCoverageBlock {
452
- let good_reloop_branch = self . find_good_reloop_branch ( traversal, from_bcb) ;
453
- if let Some ( reloop_target) = good_reloop_branch {
454
- assert ! ( self . branch_has_no_counter( from_bcb, reloop_target) ) ;
441
+ if let Some ( reloop_target) = self . find_good_reloop_edge ( traversal, from_bcb) {
442
+ assert ! ( self . edge_has_no_counter( from_bcb, reloop_target) ) ;
455
443
debug ! ( "Selecting reloop target {reloop_target:?} to get an expression" ) ;
456
- reloop_target
457
- } else {
458
- let & branch_without_counter = self
459
- . bcb_successors ( from_bcb)
460
- . iter ( )
461
- . find ( |& & to_bcb| self . branch_has_no_counter ( from_bcb, to_bcb) )
462
- . expect (
463
- "needs_branch_counters was `true` so there should be at least one \
464
- branch",
465
- ) ;
466
- debug ! (
467
- "Selecting any branch={:?} that still needs a counter, to get the \
468
- `Expression` because there was no `reloop_branch`, or it already had a \
469
- counter",
470
- branch_without_counter
471
- ) ;
472
- branch_without_counter
444
+ return reloop_target;
473
445
}
446
+
447
+ // We couldn't identify a "good" edge, so just choose any edge that
448
+ // doesn't already have a counter.
449
+ let arbitrary_target = self
450
+ . bcb_successors ( from_bcb)
451
+ . iter ( )
452
+ . copied ( )
453
+ . find ( |& to_bcb| self . edge_has_no_counter ( from_bcb, to_bcb) )
454
+ . expect ( "precondition: at least one out-edge without a counter" ) ;
455
+ debug ! ( ?arbitrary_target, "selecting arbitrary out-edge to get an expression" ) ;
456
+ arbitrary_target
474
457
}
475
458
476
- /// Tries to find a branch that leads back to the top of a loop, and that
477
- /// doesn't already have a counter. Such branches are good candidates to
459
+ /// Tries to find an edge that leads back to the top of a loop, and that
460
+ /// doesn't already have a counter. Such edges are good candidates to
478
461
/// be given an expression (instead of a physical counter), because they
479
- /// will tend to be executed more times than a loop-exit branch .
480
- fn find_good_reloop_branch (
462
+ /// will tend to be executed more times than a loop-exit edge .
463
+ fn find_good_reloop_edge (
481
464
& self ,
482
465
traversal : & TraverseCoverageGraphWithLoops < ' _ > ,
483
466
from_bcb : BasicCoverageBlock ,
484
467
) -> Option < BasicCoverageBlock > {
485
- let branch_target_bcbs = self . bcb_successors ( from_bcb) ;
468
+ let successors = self . bcb_successors ( from_bcb) ;
486
469
487
470
// Consider each loop on the current traversal context stack, top-down.
488
471
for reloop_bcbs in traversal. reloop_bcbs_per_loop ( ) {
489
- let mut all_branches_exit_this_loop = true ;
472
+ let mut all_edges_exit_this_loop = true ;
490
473
491
- // Try to find a branch that doesn't exit this loop and doesn't
474
+ // Try to find an out-edge that doesn't exit this loop and doesn't
492
475
// already have a counter.
493
- for & branch_target_bcb in branch_target_bcbs {
494
- // A branch is a reloop branch if it dominates any BCB that has
495
- // an edge back to the loop header. (Other branches are exits .)
496
- let is_reloop_branch = reloop_bcbs. iter ( ) . any ( |& reloop_bcb| {
497
- self . basic_coverage_blocks . dominates ( branch_target_bcb , reloop_bcb)
476
+ for & target_bcb in successors {
477
+ // An edge is a reloop edge if its target dominates any BCB that has
478
+ // an edge back to the loop header. (Otherwise it's an exit edge .)
479
+ let is_reloop_edge = reloop_bcbs. iter ( ) . any ( |& reloop_bcb| {
480
+ self . basic_coverage_blocks . dominates ( target_bcb , reloop_bcb)
498
481
} ) ;
499
482
500
- if is_reloop_branch {
501
- all_branches_exit_this_loop = false ;
502
- if self . branch_has_no_counter ( from_bcb, branch_target_bcb ) {
503
- // We found a good branch to be given an expression.
504
- return Some ( branch_target_bcb ) ;
483
+ if is_reloop_edge {
484
+ all_edges_exit_this_loop = false ;
485
+ if self . edge_has_no_counter ( from_bcb, target_bcb ) {
486
+ // We found a good out-edge to be given an expression.
487
+ return Some ( target_bcb ) ;
505
488
}
506
- // Keep looking for another reloop branch without a counter.
489
+ // Keep looking for another reloop edge without a counter.
507
490
} else {
508
- // This branch exits the loop.
491
+ // This edge exits the loop.
509
492
}
510
493
}
511
494
512
- if !all_branches_exit_this_loop {
513
- // We found one or more reloop branches , but all of them already
514
- // have counters. Let the caller choose one of the exit branches .
515
- debug ! ( "All reloop branches had counters; skip checking the other loops" ) ;
495
+ if !all_edges_exit_this_loop {
496
+ // We found one or more reloop edges , but all of them already
497
+ // have counters. Let the caller choose one of the other edges .
498
+ debug ! ( "All reloop edges had counters; skipping the other loops" ) ;
516
499
return None ;
517
500
}
518
501
519
- // All of the branches exit this loop, so keep looking for a good
520
- // reloop branch for one of the outer loops.
502
+ // All of the out-edges exit this loop, so keep looking for a good
503
+ // reloop edge for one of the outer loops.
521
504
}
522
505
523
506
None
@@ -534,15 +517,15 @@ impl<'a> MakeBcbCounters<'a> {
534
517
}
535
518
536
519
#[ inline]
537
- fn branch_has_no_counter (
520
+ fn edge_has_no_counter (
538
521
& self ,
539
522
from_bcb : BasicCoverageBlock ,
540
523
to_bcb : BasicCoverageBlock ,
541
524
) -> bool {
542
- self . branch_counter ( from_bcb, to_bcb) . is_none ( )
525
+ self . edge_counter ( from_bcb, to_bcb) . is_none ( )
543
526
}
544
527
545
- fn branch_counter (
528
+ fn edge_counter (
546
529
& self ,
547
530
from_bcb : BasicCoverageBlock ,
548
531
to_bcb : BasicCoverageBlock ,
0 commit comments