1- use super :: graph;
2-
3- use graph:: { BasicCoverageBlock , BcbBranch , CoverageGraph , TraverseCoverageGraphWithLoops } ;
4-
51use rustc_data_structures:: fx:: FxHashMap ;
62use rustc_data_structures:: graph:: WithNumNodes ;
73use rustc_index:: bit_set:: BitSet ;
84use rustc_index:: IndexVec ;
95use rustc_middle:: mir:: coverage:: * ;
106
7+ use super :: graph:: { BasicCoverageBlock , CoverageGraph , TraverseCoverageGraphWithLoops } ;
8+
119use std:: fmt:: { self , Debug } ;
1210
1311/// The coverage counter or counter expression associated with a particular
@@ -259,49 +257,46 @@ impl<'a> MakeBcbCounters<'a> {
259257 // We might also use its term later to compute one of the branch counters.
260258 let from_bcb_operand = self . get_or_make_counter_operand ( from_bcb) ;
261259
262- let branches = self . bcb_branches ( from_bcb) ;
260+ let branch_target_bcbs = self . basic_coverage_blocks . successors [ from_bcb] . as_slice ( ) ;
263261
264262 // If this node doesn't have multiple out-edges, or all of its out-edges
265263 // 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) ) ;
268268 if !needs_branch_counters {
269269 return ;
270270 }
271271
272272 debug ! (
273273 "{from_bcb:?} has some branch(es) without counters:\n {}" ,
274- branches
274+ branch_target_bcbs
275275 . 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+ } )
277279 . collect:: <Vec <_>>( )
278280 . join( "\n " ) ,
279281 ) ;
280282
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) ;
288286
289287 // For each branch arm other than the one that was chosen to get an expression,
290288 // ensure that it has a counter (existing counter/expression or a new counter),
291289 // and accumulate the corresponding terms into a single sum term.
292290 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 ( )
296295 // 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) ;
305300 Some ( self . coverage_counters . make_sum_expression ( accum, branch_counter) )
306301 } )
307302 . expect ( "there must be at least one other branch" )
@@ -311,22 +306,20 @@ impl<'a> MakeBcbCounters<'a> {
311306 // by taking the count of the node we're branching from, and subtracting the
312307 // sum of all the other branches.
313308 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) ,
318312 ) ;
319313 let expression = self . coverage_counters . make_expression (
320314 from_bcb_operand,
321315 Op :: Subtract ,
322316 sum_of_all_other_branches,
323317 ) ;
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) ;
328321 } else {
329- self . coverage_counters . set_bcb_edge_counter ( from_bcb , bcb , expression) ;
322+ self . coverage_counters . set_bcb_counter ( expression_to_bcb , expression) ;
330323 }
331324 }
332325
@@ -383,10 +376,16 @@ impl<'a> MakeBcbCounters<'a> {
383376 from_bcb : BasicCoverageBlock ,
384377 to_bcb : BasicCoverageBlock ,
385378 ) -> 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+
386386 // If the source BCB has only one successor (assumed to be the given target), an edge
387387 // 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 {
390389 return self . get_or_make_counter_operand ( from_bcb) ;
391390 }
392391
@@ -409,16 +408,19 @@ impl<'a> MakeBcbCounters<'a> {
409408 fn choose_preferred_expression_branch (
410409 & self ,
411410 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
419418 } 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 (
422424 "needs_branch_counters was `true` so there should be at least one \
423425 branch",
424426 ) ;
@@ -439,26 +441,28 @@ impl<'a> MakeBcbCounters<'a> {
439441 fn find_good_reloop_branch (
440442 & self ,
441443 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+
444448 // Consider each loop on the current traversal context stack, top-down.
445449 for reloop_bcbs in traversal. reloop_bcbs_per_loop ( ) {
446450 let mut all_branches_exit_this_loop = true ;
447451
448452 // Try to find a branch that doesn't exit this loop and doesn't
449453 // already have a counter.
450- for & branch in branches {
454+ for & branch_target_bcb in branch_target_bcbs {
451455 // A branch is a reloop branch if it dominates any BCB that has
452456 // an edge back to the loop header. (Other branches are exits.)
453457 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)
455459 } ) ;
456460
457461 if is_reloop_branch {
458462 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 ) {
460464 // We found a good branch to be given an expression.
461- return Some ( branch ) ;
465+ return Some ( branch_target_bcb ) ;
462466 }
463467 // Keep looking for another reloop branch without a counter.
464468 } else {
@@ -491,20 +495,20 @@ impl<'a> MakeBcbCounters<'a> {
491495 }
492496
493497 #[ 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 ( )
503504 }
504505
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) {
508512 self . coverage_counters . bcb_edge_counters . get ( & ( from_bcb, to_bcb) )
509513 } else {
510514 self . coverage_counters . bcb_counters [ to_bcb] . as_ref ( )
0 commit comments