1
- use super :: graph;
2
-
3
- use graph:: { BasicCoverageBlock , BcbBranch , CoverageGraph , TraverseCoverageGraphWithLoops } ;
4
-
5
1
use rustc_data_structures:: fx:: FxHashMap ;
6
2
use rustc_data_structures:: graph:: WithNumNodes ;
7
3
use rustc_index:: bit_set:: BitSet ;
8
4
use rustc_index:: IndexVec ;
9
5
use rustc_middle:: mir:: coverage:: * ;
10
6
7
+ use super :: graph:: { BasicCoverageBlock , CoverageGraph , TraverseCoverageGraphWithLoops } ;
8
+
11
9
use std:: fmt:: { self , Debug } ;
12
10
13
11
/// The coverage counter or counter expression associated with a particular
@@ -259,49 +257,46 @@ impl<'a> MakeBcbCounters<'a> {
259
257
// We might also use its term later to compute one of the branch counters.
260
258
let from_bcb_operand = self . get_or_make_counter_operand ( from_bcb) ;
261
259
262
- let branches = self . bcb_branches ( from_bcb) ;
260
+ let branch_target_bcbs = self . basic_coverage_blocks . successors [ from_bcb] . as_slice ( ) ;
263
261
264
262
// If this node doesn't have multiple out-edges, or all of its out-edges
265
263
// already have counters, then we don't need to create edge counters.
266
- let needs_branch_counters =
267
- branches. len ( ) > 1 && branches. iter ( ) . any ( |branch| self . branch_has_no_counter ( branch) ) ;
264
+ let needs_branch_counters = branch_target_bcbs. len ( ) > 1
265
+ && branch_target_bcbs
266
+ . iter ( )
267
+ . any ( |& to_bcb| self . branch_has_no_counter ( from_bcb, to_bcb) ) ;
268
268
if !needs_branch_counters {
269
269
return ;
270
270
}
271
271
272
272
debug ! (
273
273
"{from_bcb:?} has some branch(es) without counters:\n {}" ,
274
- branches
274
+ branch_target_bcbs
275
275
. iter( )
276
- . map( |branch| { format!( "{:?}: {:?}" , branch, self . branch_counter( branch) ) } )
276
+ . map( |& to_bcb| {
277
+ format!( "{from_bcb:?}->{to_bcb:?}: {:?}" , self . branch_counter( from_bcb, to_bcb) )
278
+ } )
277
279
. collect:: <Vec <_>>( )
278
280
. join( "\n " ) ,
279
281
) ;
280
282
281
- // Use the `traversal` state to decide if a subset of the branches exit a loop, making it
282
- // likely that branch is executed less than branches that do not exit the same loop. In this
283
- // case, any branch that does not exit the loop (and has not already been assigned a
284
- // counter) should be counted by expression, if possible. (If a preferred expression branch
285
- // is not selected based on the loop context, select any branch without an existing
286
- // counter.)
287
- let expression_branch = self . choose_preferred_expression_branch ( traversal, & branches) ;
283
+ // Of the branch edges that don't have counters yet, one can be given an expression
284
+ // (computed from the other edges) instead of a dedicated counter.
285
+ let expression_to_bcb = self . choose_preferred_expression_branch ( traversal, from_bcb) ;
288
286
289
287
// For each branch arm other than the one that was chosen to get an expression,
290
288
// ensure that it has a counter (existing counter/expression or a new counter),
291
289
// and accumulate the corresponding terms into a single sum term.
292
290
let sum_of_all_other_branches: BcbCounter = {
293
- let _span = debug_span ! ( "sum_of_all_other_branches" , ?expression_branch) . entered ( ) ;
294
- branches
295
- . into_iter ( )
291
+ let _span = debug_span ! ( "sum_of_all_other_branches" , ?expression_to_bcb) . entered ( ) ;
292
+ branch_target_bcbs
293
+ . iter ( )
294
+ . copied ( )
296
295
// Skip the chosen branch, since we'll calculate it from the other branches.
297
- . filter ( |branch| branch != & expression_branch)
298
- . fold ( None , |accum, branch| {
299
- let _span = debug_span ! ( "branch" , ?accum, ?branch) . entered ( ) ;
300
- let branch_counter = if branch. is_only_path_to_target ( ) {
301
- self . get_or_make_counter_operand ( branch. target_bcb )
302
- } else {
303
- self . get_or_make_edge_counter_operand ( from_bcb, branch. target_bcb )
304
- } ;
296
+ . filter ( |& to_bcb| to_bcb != expression_to_bcb)
297
+ . fold ( None , |accum, to_bcb| {
298
+ let _span = debug_span ! ( "to_bcb" , ?accum, ?to_bcb) . entered ( ) ;
299
+ let branch_counter = self . get_or_make_edge_counter_operand ( from_bcb, to_bcb) ;
305
300
Some ( self . coverage_counters . make_sum_expression ( accum, branch_counter) )
306
301
} )
307
302
. expect ( "there must be at least one other branch" )
@@ -311,22 +306,20 @@ impl<'a> MakeBcbCounters<'a> {
311
306
// by taking the count of the node we're branching from, and subtracting the
312
307
// sum of all the other branches.
313
308
debug ! (
314
- "Making an expression for the selected expression_branch: {:?} \
315
- (expression_branch predecessors: {:?})",
316
- expression_branch,
317
- self . bcb_predecessors( expression_branch. target_bcb) ,
309
+ "Making an expression for the selected expression_branch: \
310
+ {expression_to_bcb:?} (expression_branch predecessors: {:?})",
311
+ self . bcb_predecessors( expression_to_bcb) ,
318
312
) ;
319
313
let expression = self . coverage_counters . make_expression (
320
314
from_bcb_operand,
321
315
Op :: Subtract ,
322
316
sum_of_all_other_branches,
323
317
) ;
324
- debug ! ( "{:?} gets an expression: {:?}" , expression_branch, expression) ;
325
- let bcb = expression_branch. target_bcb ;
326
- if expression_branch. is_only_path_to_target ( ) {
327
- self . coverage_counters . set_bcb_counter ( bcb, expression) ;
318
+ debug ! ( "{expression_to_bcb:?} gets an expression: {expression:?}" ) ;
319
+ if self . basic_coverage_blocks . bcb_has_multiple_in_edges ( expression_to_bcb) {
320
+ self . coverage_counters . set_bcb_edge_counter ( from_bcb, expression_to_bcb, expression) ;
328
321
} else {
329
- self . coverage_counters . set_bcb_edge_counter ( from_bcb , bcb , expression) ;
322
+ self . coverage_counters . set_bcb_counter ( expression_to_bcb , expression) ;
330
323
}
331
324
}
332
325
@@ -383,10 +376,16 @@ impl<'a> MakeBcbCounters<'a> {
383
376
from_bcb : BasicCoverageBlock ,
384
377
to_bcb : BasicCoverageBlock ,
385
378
) -> BcbCounter {
379
+ // If the target BCB has only one in-edge (i.e. this one), then create
380
+ // a node counter instead, since it will have the same value.
381
+ if !self . basic_coverage_blocks . bcb_has_multiple_in_edges ( to_bcb) {
382
+ assert_eq ! ( [ from_bcb] . as_slice( ) , self . basic_coverage_blocks. predecessors[ to_bcb] ) ;
383
+ return self . get_or_make_counter_operand ( to_bcb) ;
384
+ }
385
+
386
386
// If the source BCB has only one successor (assumed to be the given target), an edge
387
387
// counter is unnecessary. Just get or make a counter for the source BCB.
388
- let successors = self . bcb_successors ( from_bcb) . iter ( ) ;
389
- if successors. len ( ) == 1 {
388
+ if self . bcb_successors ( from_bcb) . len ( ) == 1 {
390
389
return self . get_or_make_counter_operand ( from_bcb) ;
391
390
}
392
391
@@ -409,16 +408,19 @@ impl<'a> MakeBcbCounters<'a> {
409
408
fn choose_preferred_expression_branch (
410
409
& self ,
411
410
traversal : & TraverseCoverageGraphWithLoops < ' _ > ,
412
- branches : & [ BcbBranch ] ,
413
- ) -> BcbBranch {
414
- let good_reloop_branch = self . find_good_reloop_branch ( traversal, & branches ) ;
415
- if let Some ( reloop_branch ) = good_reloop_branch {
416
- assert ! ( self . branch_has_no_counter( & reloop_branch ) ) ;
417
- debug ! ( "Selecting reloop branch {reloop_branch :?} to get an expression" ) ;
418
- reloop_branch
411
+ from_bcb : BasicCoverageBlock ,
412
+ ) -> BasicCoverageBlock {
413
+ let good_reloop_branch = self . find_good_reloop_branch ( traversal, from_bcb ) ;
414
+ if let Some ( reloop_target ) = good_reloop_branch {
415
+ assert ! ( self . branch_has_no_counter( from_bcb , reloop_target ) ) ;
416
+ debug ! ( "Selecting reloop target {reloop_target :?} to get an expression" ) ;
417
+ reloop_target
419
418
} else {
420
- let & branch_without_counter =
421
- branches. iter ( ) . find ( |& branch| self . branch_has_no_counter ( branch) ) . expect (
419
+ let & branch_without_counter = self
420
+ . bcb_successors ( from_bcb)
421
+ . iter ( )
422
+ . find ( |& & to_bcb| self . branch_has_no_counter ( from_bcb, to_bcb) )
423
+ . expect (
422
424
"needs_branch_counters was `true` so there should be at least one \
423
425
branch",
424
426
) ;
@@ -439,26 +441,28 @@ impl<'a> MakeBcbCounters<'a> {
439
441
fn find_good_reloop_branch (
440
442
& self ,
441
443
traversal : & TraverseCoverageGraphWithLoops < ' _ > ,
442
- branches : & [ BcbBranch ] ,
443
- ) -> Option < BcbBranch > {
444
+ from_bcb : BasicCoverageBlock ,
445
+ ) -> Option < BasicCoverageBlock > {
446
+ let branch_target_bcbs = self . bcb_successors ( from_bcb) ;
447
+
444
448
// Consider each loop on the current traversal context stack, top-down.
445
449
for reloop_bcbs in traversal. reloop_bcbs_per_loop ( ) {
446
450
let mut all_branches_exit_this_loop = true ;
447
451
448
452
// Try to find a branch that doesn't exit this loop and doesn't
449
453
// already have a counter.
450
- for & branch in branches {
454
+ for & branch_target_bcb in branch_target_bcbs {
451
455
// A branch is a reloop branch if it dominates any BCB that has
452
456
// an edge back to the loop header. (Other branches are exits.)
453
457
let is_reloop_branch = reloop_bcbs. iter ( ) . any ( |& reloop_bcb| {
454
- self . basic_coverage_blocks . dominates ( branch . target_bcb , reloop_bcb)
458
+ self . basic_coverage_blocks . dominates ( branch_target_bcb , reloop_bcb)
455
459
} ) ;
456
460
457
461
if is_reloop_branch {
458
462
all_branches_exit_this_loop = false ;
459
- if self . branch_has_no_counter ( & branch ) {
463
+ if self . branch_has_no_counter ( from_bcb , branch_target_bcb ) {
460
464
// We found a good branch to be given an expression.
461
- return Some ( branch ) ;
465
+ return Some ( branch_target_bcb ) ;
462
466
}
463
467
// Keep looking for another reloop branch without a counter.
464
468
} else {
@@ -491,20 +495,20 @@ impl<'a> MakeBcbCounters<'a> {
491
495
}
492
496
493
497
#[ inline]
494
- fn bcb_branches ( & self , from_bcb : BasicCoverageBlock ) -> Vec < BcbBranch > {
495
- self . bcb_successors ( from_bcb)
496
- . iter ( )
497
- . map ( |& to_bcb| BcbBranch :: from_to ( from_bcb, to_bcb, & self . basic_coverage_blocks ) )
498
- . collect :: < Vec < _ > > ( )
499
- }
500
-
501
- fn branch_has_no_counter ( & self , branch : & BcbBranch ) -> bool {
502
- self . branch_counter ( branch) . is_none ( )
498
+ fn branch_has_no_counter (
499
+ & self ,
500
+ from_bcb : BasicCoverageBlock ,
501
+ to_bcb : BasicCoverageBlock ,
502
+ ) -> bool {
503
+ self . branch_counter ( from_bcb, to_bcb) . is_none ( )
503
504
}
504
505
505
- fn branch_counter ( & self , branch : & BcbBranch ) -> Option < & BcbCounter > {
506
- let to_bcb = branch. target_bcb ;
507
- if let Some ( from_bcb) = branch. edge_from_bcb {
506
+ fn branch_counter (
507
+ & self ,
508
+ from_bcb : BasicCoverageBlock ,
509
+ to_bcb : BasicCoverageBlock ,
510
+ ) -> Option < & BcbCounter > {
511
+ if self . basic_coverage_blocks . bcb_has_multiple_in_edges ( to_bcb) {
508
512
self . coverage_counters . bcb_edge_counters . get ( & ( from_bcb, to_bcb) )
509
513
} else {
510
514
self . coverage_counters . bcb_counters [ to_bcb] . as_ref ( )
0 commit comments