@@ -8,17 +8,28 @@ use debug::{DebugCounters, NESTED_INDENT};
8
8
use graph:: { BasicCoverageBlock , BcbBranch , CoverageGraph , TraverseCoverageGraphWithLoops } ;
9
9
use spans:: CoverageSpan ;
10
10
11
+ use rustc_data_structures:: fx:: FxHashMap ;
11
12
use rustc_data_structures:: graph:: WithNumNodes ;
12
13
use rustc_index:: bit_set:: BitSet ;
14
+ use rustc_index:: IndexVec ;
13
15
use rustc_middle:: mir:: coverage:: * ;
14
16
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 .
17
19
pub ( super ) struct CoverageCounters {
18
20
function_source_hash : u64 ,
19
21
next_counter_id : CounterId ,
20
22
next_expression_id : ExpressionId ,
21
23
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 > ,
22
33
/// Expression nodes that are not directly associated with any particular
23
34
/// BCB/edge, but are needed as operands to more complex expressions.
24
35
/// These are always `CoverageKind::Expression`.
@@ -28,12 +39,17 @@ pub(super) struct CoverageCounters {
28
39
}
29
40
30
41
impl 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
+
32
45
Self {
33
46
function_source_hash,
34
47
next_counter_id : CounterId :: START ,
35
48
next_expression_id : ExpressionId :: START ,
36
49
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) ,
37
53
intermediate_expressions : Vec :: new ( ) ,
38
54
39
55
debug_counters : DebugCounters :: new ( ) ,
@@ -51,7 +67,7 @@ impl CoverageCounters {
51
67
/// representing intermediate values.
52
68
pub fn make_bcb_counters (
53
69
& mut self ,
54
- basic_coverage_blocks : & mut CoverageGraph ,
70
+ basic_coverage_blocks : & CoverageGraph ,
55
71
coverage_spans : & [ CoverageSpan ] ,
56
72
) -> Result < ( ) , Error > {
57
73
MakeBcbCounters :: new ( self , basic_coverage_blocks) . make_bcb_counters ( coverage_spans)
@@ -114,6 +130,80 @@ impl CoverageCounters {
114
130
self . next_expression_id = next. next_id ( ) ;
115
131
next
116
132
}
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
+ }
117
207
}
118
208
119
209
/// Traverse the `CoverageGraph` and add either a `Counter` or `Expression` to every BCB, to be
@@ -122,13 +212,13 @@ impl CoverageCounters {
122
212
/// embedded counter, an `Expression` should be used.
123
213
struct MakeBcbCounters < ' a > {
124
214
coverage_counters : & ' a mut CoverageCounters ,
125
- basic_coverage_blocks : & ' a mut CoverageGraph ,
215
+ basic_coverage_blocks : & ' a CoverageGraph ,
126
216
}
127
217
128
218
impl < ' a > MakeBcbCounters < ' a > {
129
219
fn new (
130
220
coverage_counters : & ' a mut CoverageCounters ,
131
- basic_coverage_blocks : & ' a mut CoverageGraph ,
221
+ basic_coverage_blocks : & ' a CoverageGraph ,
132
222
) -> Self {
133
223
Self { coverage_counters, basic_coverage_blocks }
134
224
}
@@ -202,9 +292,7 @@ impl<'a> MakeBcbCounters<'a> {
202
292
branching_bcb,
203
293
branches
204
294
. iter( )
205
- . map( |branch| {
206
- format!( "{:?}: {:?}" , branch, branch. counter( & self . basic_coverage_blocks) )
207
- } )
295
+ . map( |branch| { format!( "{:?}: {:?}" , branch, self . branch_counter( branch) ) } )
208
296
. collect:: <Vec <_>>( )
209
297
. join( "\n " ) ,
210
298
) ;
@@ -274,9 +362,9 @@ impl<'a> MakeBcbCounters<'a> {
274
362
debug ! ( "{:?} gets an expression: {}" , expression_branch, self . format_counter( & expression) ) ;
275
363
let bcb = expression_branch. target_bcb ;
276
364
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) ?;
278
366
} 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) ?;
280
368
}
281
369
Ok ( ( ) )
282
370
}
@@ -291,7 +379,7 @@ impl<'a> MakeBcbCounters<'a> {
291
379
debug_indent_level : usize ,
292
380
) -> Result < Operand , Error > {
293
381
// 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] {
295
383
debug ! (
296
384
"{}{:?} already has a counter: {}" ,
297
385
NESTED_INDENT . repeat( debug_indent_level) ,
@@ -324,7 +412,7 @@ impl<'a> MakeBcbCounters<'a> {
324
412
self . format_counter( & counter_kind) ,
325
413
) ;
326
414
}
327
- return self . basic_coverage_blocks [ bcb ] . set_counter ( counter_kind) ;
415
+ return self . coverage_counters . set_bcb_counter ( bcb , counter_kind) ;
328
416
}
329
417
330
418
// A BCB with multiple incoming edges can compute its count by `Expression`, summing up the
@@ -380,7 +468,7 @@ impl<'a> MakeBcbCounters<'a> {
380
468
bcb,
381
469
self . format_counter( & counter_kind)
382
470
) ;
383
- self . basic_coverage_blocks [ bcb ] . set_counter ( counter_kind)
471
+ self . coverage_counters . set_bcb_counter ( bcb , counter_kind)
384
472
}
385
473
386
474
fn get_or_make_edge_counter_operand (
@@ -405,7 +493,9 @@ impl<'a> MakeBcbCounters<'a> {
405
493
}
406
494
407
495
// 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
+ {
409
499
debug ! (
410
500
"{}Edge {:?}->{:?} already has a counter: {}" ,
411
501
NESTED_INDENT . repeat( debug_indent_level) ,
@@ -426,7 +516,7 @@ impl<'a> MakeBcbCounters<'a> {
426
516
to_bcb,
427
517
self . format_counter( & counter_kind)
428
518
) ;
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)
430
520
}
431
521
432
522
/// Select a branch for the expression, either the recommended `reloop_branch`, or if none was
@@ -436,8 +526,7 @@ impl<'a> MakeBcbCounters<'a> {
436
526
traversal : & TraverseCoverageGraphWithLoops ,
437
527
branches : & [ BcbBranch ] ,
438
528
) -> 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) ;
441
530
442
531
let some_reloop_branch = self . find_some_reloop_branch ( traversal, & branches) ;
443
532
if let Some ( reloop_branch_without_counter) =
@@ -450,10 +539,8 @@ impl<'a> MakeBcbCounters<'a> {
450
539
) ;
451
540
reloop_branch_without_counter
452
541
} 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 (
457
544
"needs_branch_counters was `true` so there should be at least one \
458
545
branch",
459
546
) ;
@@ -480,8 +567,7 @@ impl<'a> MakeBcbCounters<'a> {
480
567
traversal : & TraverseCoverageGraphWithLoops ,
481
568
branches : & [ BcbBranch ] ,
482
569
) -> 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) ;
485
571
486
572
let mut some_reloop_branch: Option < BcbBranch > = None ;
487
573
for context in traversal. context_stack . iter ( ) . rev ( ) {
@@ -492,7 +578,7 @@ impl<'a> MakeBcbCounters<'a> {
492
578
self . bcb_dominates ( branch. target_bcb , backedge_from_bcb)
493
579
} ) {
494
580
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 ) {
496
582
// we already found a candidate reloop_branch that still
497
583
// needs a counter
498
584
continue ;
@@ -558,12 +644,24 @@ impl<'a> MakeBcbCounters<'a> {
558
644
}
559
645
560
646
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) ;
563
648
let branches = self . bcb_branches ( bcb) ;
564
649
branches. len ( ) > 1 && branches. iter ( ) . any ( branch_needs_a_counter)
565
650
}
566
651
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
+
567
665
/// Returns true if the BasicCoverageBlock has zero or one incoming edge. (If zero, it should be
568
666
/// the entry point for the function.)
569
667
#[ inline]
0 commit comments