@@ -8,17 +8,28 @@ use debug::{DebugCounters, NESTED_INDENT};
88use graph:: { BasicCoverageBlock , BcbBranch , CoverageGraph , TraverseCoverageGraphWithLoops } ;
99use spans:: CoverageSpan ;
1010
11+ use rustc_data_structures:: fx:: FxHashMap ;
1112use rustc_data_structures:: graph:: WithNumNodes ;
1213use rustc_index:: bit_set:: BitSet ;
14+ use rustc_index:: IndexVec ;
1315use rustc_middle:: mir:: coverage:: * ;
1416
15- /// Manages the counter and expression indexes/IDs to generate `CoverageKind` components for MIR
16- /// `Coverage` statements .
17+ /// Generates and stores coverage counter and coverage expression information
18+ /// associated with nodes/edges in the BCB graph .
1719pub ( super ) struct CoverageCounters {
1820 function_source_hash : u64 ,
1921 next_counter_id : CounterId ,
2022 next_expression_id : ExpressionId ,
2123
24+ /// Coverage counters/expressions that are associated with individual BCBs.
25+ bcb_counters : IndexVec < BasicCoverageBlock , Option < CoverageKind > > ,
26+ /// Coverage counters/expressions that are associated with the control-flow
27+ /// edge between two BCBs.
28+ bcb_edge_counters : FxHashMap < ( BasicCoverageBlock , BasicCoverageBlock ) , CoverageKind > ,
29+ /// Tracks which BCBs have a counter associated with some incoming edge.
30+ /// Only used by debug assertions, to verify that BCBs with incoming edge
31+ /// counters do not have their own physical counters (expressions are allowed).
32+ bcb_has_incoming_edge_counters : BitSet < BasicCoverageBlock > ,
2233 /// Expression nodes that are not directly associated with any particular
2334 /// BCB/edge, but are needed as operands to more complex expressions.
2435 /// These are always `CoverageKind::Expression`.
@@ -28,12 +39,17 @@ pub(super) struct CoverageCounters {
2839}
2940
3041impl CoverageCounters {
31- pub fn new ( function_source_hash : u64 ) -> Self {
42+ pub ( super ) fn new ( function_source_hash : u64 , basic_coverage_blocks : & CoverageGraph ) -> Self {
43+ let num_bcbs = basic_coverage_blocks. num_nodes ( ) ;
44+
3245 Self {
3346 function_source_hash,
3447 next_counter_id : CounterId :: START ,
3548 next_expression_id : ExpressionId :: START ,
3649
50+ bcb_counters : IndexVec :: from_elem_n ( None , num_bcbs) ,
51+ bcb_edge_counters : FxHashMap :: default ( ) ,
52+ bcb_has_incoming_edge_counters : BitSet :: new_empty ( num_bcbs) ,
3753 intermediate_expressions : Vec :: new ( ) ,
3854
3955 debug_counters : DebugCounters :: new ( ) ,
@@ -51,7 +67,7 @@ impl CoverageCounters {
5167 /// representing intermediate values.
5268 pub fn make_bcb_counters (
5369 & mut self ,
54- basic_coverage_blocks : & mut CoverageGraph ,
70+ basic_coverage_blocks : & CoverageGraph ,
5571 coverage_spans : & [ CoverageSpan ] ,
5672 ) -> Result < ( ) , Error > {
5773 MakeBcbCounters :: new ( self , basic_coverage_blocks) . make_bcb_counters ( coverage_spans)
@@ -114,6 +130,80 @@ impl CoverageCounters {
114130 self . next_expression_id = next. next_id ( ) ;
115131 next
116132 }
133+
134+ fn set_bcb_counter (
135+ & mut self ,
136+ bcb : BasicCoverageBlock ,
137+ counter_kind : CoverageKind ,
138+ ) -> Result < Operand , Error > {
139+ debug_assert ! (
140+ // If the BCB has an edge counter (to be injected into a new `BasicBlock`), it can also
141+ // have an expression (to be injected into an existing `BasicBlock` represented by this
142+ // `BasicCoverageBlock`).
143+ counter_kind. is_expression( ) || !self . bcb_has_incoming_edge_counters. contains( bcb) ,
144+ "attempt to add a `Counter` to a BCB target with existing incoming edge counters"
145+ ) ;
146+ let operand = counter_kind. as_operand ( ) ;
147+ if let Some ( replaced) = self . bcb_counters [ bcb] . replace ( counter_kind) {
148+ Error :: from_string ( format ! (
149+ "attempt to set a BasicCoverageBlock coverage counter more than once; \
150+ {bcb:?} already had counter {replaced:?}",
151+ ) )
152+ } else {
153+ Ok ( operand)
154+ }
155+ }
156+
157+ fn set_bcb_edge_counter (
158+ & mut self ,
159+ from_bcb : BasicCoverageBlock ,
160+ to_bcb : BasicCoverageBlock ,
161+ counter_kind : CoverageKind ,
162+ ) -> Result < Operand , Error > {
163+ if level_enabled ! ( tracing:: Level :: DEBUG ) {
164+ // If the BCB has an edge counter (to be injected into a new `BasicBlock`), it can also
165+ // have an expression (to be injected into an existing `BasicBlock` represented by this
166+ // `BasicCoverageBlock`).
167+ if self . bcb_counter ( to_bcb) . is_some_and ( |c| !c. is_expression ( ) ) {
168+ return Error :: from_string ( format ! (
169+ "attempt to add an incoming edge counter from {from_bcb:?} when the target BCB already \
170+ has a `Counter`"
171+ ) ) ;
172+ }
173+ }
174+ self . bcb_has_incoming_edge_counters . insert ( to_bcb) ;
175+ let operand = counter_kind. as_operand ( ) ;
176+ if let Some ( replaced) = self . bcb_edge_counters . insert ( ( from_bcb, to_bcb) , counter_kind) {
177+ Error :: from_string ( format ! (
178+ "attempt to set an edge counter more than once; from_bcb: \
179+ {from_bcb:?} already had counter {replaced:?}",
180+ ) )
181+ } else {
182+ Ok ( operand)
183+ }
184+ }
185+
186+ pub ( super ) fn bcb_counter ( & self , bcb : BasicCoverageBlock ) -> Option < & CoverageKind > {
187+ self . bcb_counters [ bcb] . as_ref ( )
188+ }
189+
190+ pub ( super ) fn take_bcb_counter ( & mut self , bcb : BasicCoverageBlock ) -> Option < CoverageKind > {
191+ self . bcb_counters [ bcb] . take ( )
192+ }
193+
194+ pub ( super ) fn drain_bcb_counters (
195+ & mut self ,
196+ ) -> impl Iterator < Item = ( BasicCoverageBlock , CoverageKind ) > + ' _ {
197+ self . bcb_counters
198+ . iter_enumerated_mut ( )
199+ . filter_map ( |( bcb, counter) | Some ( ( bcb, counter. take ( ) ?) ) )
200+ }
201+
202+ pub ( super ) fn drain_bcb_edge_counters (
203+ & mut self ,
204+ ) -> impl Iterator < Item = ( ( BasicCoverageBlock , BasicCoverageBlock ) , CoverageKind ) > + ' _ {
205+ self . bcb_edge_counters . drain ( )
206+ }
117207}
118208
119209/// Traverse the `CoverageGraph` and add either a `Counter` or `Expression` to every BCB, to be
@@ -122,13 +212,13 @@ impl CoverageCounters {
122212/// embedded counter, an `Expression` should be used.
123213struct MakeBcbCounters < ' a > {
124214 coverage_counters : & ' a mut CoverageCounters ,
125- basic_coverage_blocks : & ' a mut CoverageGraph ,
215+ basic_coverage_blocks : & ' a CoverageGraph ,
126216}
127217
128218impl < ' a > MakeBcbCounters < ' a > {
129219 fn new (
130220 coverage_counters : & ' a mut CoverageCounters ,
131- basic_coverage_blocks : & ' a mut CoverageGraph ,
221+ basic_coverage_blocks : & ' a CoverageGraph ,
132222 ) -> Self {
133223 Self { coverage_counters, basic_coverage_blocks }
134224 }
@@ -202,9 +292,7 @@ impl<'a> MakeBcbCounters<'a> {
202292 branching_bcb,
203293 branches
204294 . iter( )
205- . map( |branch| {
206- format!( "{:?}: {:?}" , branch, branch. counter( & self . basic_coverage_blocks) )
207- } )
295+ . map( |branch| { format!( "{:?}: {:?}" , branch, self . branch_counter( branch) ) } )
208296 . collect:: <Vec <_>>( )
209297 . join( "\n " ) ,
210298 ) ;
@@ -274,9 +362,9 @@ impl<'a> MakeBcbCounters<'a> {
274362 debug ! ( "{:?} gets an expression: {}" , expression_branch, self . format_counter( & expression) ) ;
275363 let bcb = expression_branch. target_bcb ;
276364 if expression_branch. is_only_path_to_target ( ) {
277- self . basic_coverage_blocks [ bcb ] . set_counter ( expression) ?;
365+ self . coverage_counters . set_bcb_counter ( bcb , expression) ?;
278366 } else {
279- self . basic_coverage_blocks [ bcb ] . set_edge_counter_from ( branching_bcb, expression) ?;
367+ self . coverage_counters . set_bcb_edge_counter ( branching_bcb, bcb , expression) ?;
280368 }
281369 Ok ( ( ) )
282370 }
@@ -291,7 +379,7 @@ impl<'a> MakeBcbCounters<'a> {
291379 debug_indent_level : usize ,
292380 ) -> Result < Operand , Error > {
293381 // If the BCB already has a counter, return it.
294- if let Some ( counter_kind) = self . basic_coverage_blocks [ bcb] . counter ( ) {
382+ if let Some ( counter_kind) = & self . coverage_counters . bcb_counters [ bcb] {
295383 debug ! (
296384 "{}{:?} already has a counter: {}" ,
297385 NESTED_INDENT . repeat( debug_indent_level) ,
@@ -324,7 +412,7 @@ impl<'a> MakeBcbCounters<'a> {
324412 self . format_counter( & counter_kind) ,
325413 ) ;
326414 }
327- return self . basic_coverage_blocks [ bcb ] . set_counter ( counter_kind) ;
415+ return self . coverage_counters . set_bcb_counter ( bcb , counter_kind) ;
328416 }
329417
330418 // A BCB with multiple incoming edges can compute its count by `Expression`, summing up the
@@ -380,7 +468,7 @@ impl<'a> MakeBcbCounters<'a> {
380468 bcb,
381469 self . format_counter( & counter_kind)
382470 ) ;
383- self . basic_coverage_blocks [ bcb ] . set_counter ( counter_kind)
471+ self . coverage_counters . set_bcb_counter ( bcb , counter_kind)
384472 }
385473
386474 fn get_or_make_edge_counter_operand (
@@ -405,7 +493,9 @@ impl<'a> MakeBcbCounters<'a> {
405493 }
406494
407495 // If the edge already has a counter, return it.
408- if let Some ( counter_kind) = self . basic_coverage_blocks [ to_bcb] . edge_counter_from ( from_bcb) {
496+ if let Some ( counter_kind) =
497+ self . coverage_counters . bcb_edge_counters . get ( & ( from_bcb, to_bcb) )
498+ {
409499 debug ! (
410500 "{}Edge {:?}->{:?} already has a counter: {}" ,
411501 NESTED_INDENT . repeat( debug_indent_level) ,
@@ -426,7 +516,7 @@ impl<'a> MakeBcbCounters<'a> {
426516 to_bcb,
427517 self . format_counter( & counter_kind)
428518 ) ;
429- self . basic_coverage_blocks [ to_bcb ] . set_edge_counter_from ( from_bcb, counter_kind)
519+ self . coverage_counters . set_bcb_edge_counter ( from_bcb, to_bcb , counter_kind)
430520 }
431521
432522 /// Select a branch for the expression, either the recommended `reloop_branch`, or if none was
@@ -436,8 +526,7 @@ impl<'a> MakeBcbCounters<'a> {
436526 traversal : & TraverseCoverageGraphWithLoops ,
437527 branches : & [ BcbBranch ] ,
438528 ) -> BcbBranch {
439- let branch_needs_a_counter =
440- |branch : & BcbBranch | branch. counter ( & self . basic_coverage_blocks ) . is_none ( ) ;
529+ let branch_needs_a_counter = |branch : & BcbBranch | self . branch_has_no_counter ( branch) ;
441530
442531 let some_reloop_branch = self . find_some_reloop_branch ( traversal, & branches) ;
443532 if let Some ( reloop_branch_without_counter) =
@@ -450,10 +539,8 @@ impl<'a> MakeBcbCounters<'a> {
450539 ) ;
451540 reloop_branch_without_counter
452541 } else {
453- let & branch_without_counter = branches
454- . iter ( )
455- . find ( |& & branch| branch. counter ( & self . basic_coverage_blocks ) . is_none ( ) )
456- . expect (
542+ let & branch_without_counter =
543+ branches. iter ( ) . find ( |& branch| self . branch_has_no_counter ( branch) ) . expect (
457544 "needs_branch_counters was `true` so there should be at least one \
458545 branch",
459546 ) ;
@@ -480,8 +567,7 @@ impl<'a> MakeBcbCounters<'a> {
480567 traversal : & TraverseCoverageGraphWithLoops ,
481568 branches : & [ BcbBranch ] ,
482569 ) -> Option < BcbBranch > {
483- let branch_needs_a_counter =
484- |branch : & BcbBranch | branch. counter ( & self . basic_coverage_blocks ) . is_none ( ) ;
570+ let branch_needs_a_counter = |branch : & BcbBranch | self . branch_has_no_counter ( branch) ;
485571
486572 let mut some_reloop_branch: Option < BcbBranch > = None ;
487573 for context in traversal. context_stack . iter ( ) . rev ( ) {
@@ -492,7 +578,7 @@ impl<'a> MakeBcbCounters<'a> {
492578 self . bcb_dominates ( branch. target_bcb , backedge_from_bcb)
493579 } ) {
494580 if let Some ( reloop_branch) = some_reloop_branch {
495- if reloop_branch . counter ( & self . basic_coverage_blocks ) . is_none ( ) {
581+ if self . branch_has_no_counter ( & reloop_branch ) {
496582 // we already found a candidate reloop_branch that still
497583 // needs a counter
498584 continue ;
@@ -558,12 +644,24 @@ impl<'a> MakeBcbCounters<'a> {
558644 }
559645
560646 fn bcb_needs_branch_counters ( & self , bcb : BasicCoverageBlock ) -> bool {
561- let branch_needs_a_counter =
562- |branch : & BcbBranch | branch. counter ( & self . basic_coverage_blocks ) . is_none ( ) ;
647+ let branch_needs_a_counter = |branch : & BcbBranch | self . branch_has_no_counter ( branch) ;
563648 let branches = self . bcb_branches ( bcb) ;
564649 branches. len ( ) > 1 && branches. iter ( ) . any ( branch_needs_a_counter)
565650 }
566651
652+ fn branch_has_no_counter ( & self , branch : & BcbBranch ) -> bool {
653+ self . branch_counter ( branch) . is_none ( )
654+ }
655+
656+ fn branch_counter ( & self , branch : & BcbBranch ) -> Option < & CoverageKind > {
657+ let to_bcb = branch. target_bcb ;
658+ if let Some ( from_bcb) = branch. edge_from_bcb {
659+ self . coverage_counters . bcb_edge_counters . get ( & ( from_bcb, to_bcb) )
660+ } else {
661+ self . coverage_counters . bcb_counters [ to_bcb] . as_ref ( )
662+ }
663+ }
664+
567665 /// Returns true if the BasicCoverageBlock has zero or one incoming edge. (If zero, it should be
568666 /// the entry point for the function.)
569667 #[ inline]
0 commit comments