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