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
@@ -257,49 +255,46 @@ impl<'a> MakeBcbCounters<'a> {
257255 // We might also use its term later to compute one of the branch counters.
258256 let from_bcb_operand = self . get_or_make_counter_operand ( from_bcb) ;
259257
260- let branches = self . bcb_branches ( from_bcb) ;
258+ let branch_target_bcbs = self . basic_coverage_blocks . successors [ from_bcb] . as_slice ( ) ;
261259
262260 // If this node doesn't have multiple out-edges, or all of its out-edges
263261 // 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) ) ;
266266 if !needs_branch_counters {
267267 return ;
268268 }
269269
270270 debug ! (
271271 "{from_bcb:?} has some branch(es) without counters:\n {}" ,
272- branches
272+ branch_target_bcbs
273273 . 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+ } )
275277 . collect:: <Vec <_>>( )
276278 . join( "\n " ) ,
277279 ) ;
278280
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) ;
286284
287285 // For each branch arm other than the one that was chosen to get an expression,
288286 // ensure that it has a counter (existing counter/expression or a new counter),
289287 // and accumulate the corresponding terms into a single sum term.
290288 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 ( )
289+ let _span = debug_span ! ( "sum_of_all_other_branches" , ?expression_to_bcb) . entered ( ) ;
290+ branch_target_bcbs
291+ . iter ( )
292+ . copied ( )
294293 // 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) ;
303298 Some ( self . coverage_counters . make_sum_expression ( accum, branch_counter) )
304299 } )
305300 . expect ( "there must be at least one other branch" )
@@ -309,22 +304,20 @@ impl<'a> MakeBcbCounters<'a> {
309304 // by taking the count of the node we're branching from, and subtracting the
310305 // sum of all the other branches.
311306 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) ,
316310 ) ;
317311 let expression = self . coverage_counters . make_expression (
318312 from_bcb_operand,
319313 Op :: Subtract ,
320314 sum_of_all_other_branches,
321315 ) ;
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) ;
326319 } else {
327- self . coverage_counters . set_bcb_edge_counter ( from_bcb , bcb , expression) ;
320+ self . coverage_counters . set_bcb_counter ( expression_to_bcb , expression) ;
328321 }
329322 }
330323
@@ -381,10 +374,16 @@ impl<'a> MakeBcbCounters<'a> {
381374 from_bcb : BasicCoverageBlock ,
382375 to_bcb : BasicCoverageBlock ,
383376 ) -> 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+
384384 // If the source BCB has only one successor (assumed to be the given target), an edge
385385 // 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 {
388387 return self . get_or_make_counter_operand ( from_bcb) ;
389388 }
390389
@@ -407,16 +406,19 @@ impl<'a> MakeBcbCounters<'a> {
407406 fn choose_preferred_expression_branch (
408407 & self ,
409408 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
417416 } 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 (
420422 "needs_branch_counters was `true` so there should be at least one \
421423 branch",
422424 ) ;
@@ -437,26 +439,28 @@ impl<'a> MakeBcbCounters<'a> {
437439 fn find_good_reloop_branch (
438440 & self ,
439441 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+
442446 // Consider each loop on the current traversal context stack, top-down.
443447 for reloop_bcbs in traversal. reloop_bcbs_per_loop ( ) {
444448 let mut all_branches_exit_this_loop = true ;
445449
446450 // Try to find a branch that doesn't exit this loop and doesn't
447451 // already have a counter.
448- for & branch in branches {
452+ for & branch_target_bcb in branch_target_bcbs {
449453 // A branch is a reloop branch if it dominates any BCB that has
450454 // an edge back to the loop header. (Other branches are exits.)
451455 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)
453457 } ) ;
454458
455459 if is_reloop_branch {
456460 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 ) {
458462 // We found a good branch to be given an expression.
459- return Some ( branch ) ;
463+ return Some ( branch_target_bcb ) ;
460464 }
461465 // Keep looking for another reloop branch without a counter.
462466 } else {
@@ -489,20 +493,20 @@ impl<'a> MakeBcbCounters<'a> {
489493 }
490494
491495 #[ 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 ( )
501502 }
502503
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) {
506510 self . coverage_counters . bcb_edge_counters . get ( & ( from_bcb, to_bcb) )
507511 } else {
508512 self . coverage_counters . bcb_counters [ to_bcb] . as_ref ( )
0 commit comments