@@ -20,6 +20,96 @@ mod iter_nodes;
20
20
mod node_flow;
21
21
mod union_find;
22
22
23
+ /// Ensures that each BCB node needing a counter has one, by creating physical
24
+ /// counters or counter expressions for nodes as required.
25
+ pub ( super ) fn make_bcb_counters (
26
+ graph : & CoverageGraph ,
27
+ bcb_needs_counter : & DenseBitSet < BasicCoverageBlock > ,
28
+ ) -> CoverageCounters {
29
+ let balanced_graph = BalancedFlowGraph :: for_graph ( graph, |n| !graph[ n] . is_out_summable ) ;
30
+ let merged_graph = MergedNodeFlowGraph :: for_balanced_graph ( & balanced_graph) ;
31
+
32
+ let nodes = make_node_counter_priority_list ( graph, balanced_graph) ;
33
+ let node_counters = merged_graph. make_node_counters ( & nodes) ;
34
+
35
+ transcribe_counters ( & node_counters, bcb_needs_counter)
36
+ }
37
+
38
+ fn make_node_counter_priority_list (
39
+ graph : & CoverageGraph ,
40
+ balanced_graph : BalancedFlowGraph < & CoverageGraph > ,
41
+ ) -> Vec < BasicCoverageBlock > {
42
+ // A "reloop" node has exactly one out-edge, which jumps back to the top
43
+ // of an enclosing loop. Reloop nodes are typically visited more times
44
+ // than loop-exit nodes, so try to avoid giving them physical counters.
45
+ let is_reloop_node = IndexVec :: from_fn_n (
46
+ |node| match graph. successors [ node] . as_slice ( ) {
47
+ & [ succ] => graph. dominates ( succ, node) ,
48
+ _ => false ,
49
+ } ,
50
+ graph. num_nodes ( ) ,
51
+ ) ;
52
+
53
+ let mut nodes = balanced_graph. iter_nodes ( ) . rev ( ) . collect :: < Vec < _ > > ( ) ;
54
+ // The first node is the sink, which must not get a physical counter.
55
+ assert_eq ! ( nodes[ 0 ] , balanced_graph. sink) ;
56
+ // Sort the real nodes, such that earlier (lesser) nodes take priority
57
+ // in being given a counter expression instead of a physical counter.
58
+ nodes[ 1 ..] . sort_by ( |& a, & b| {
59
+ // Start with a dummy `Equal` to make the actual tests line up nicely.
60
+ Ordering :: Equal
61
+ // Prefer a physical counter for return/yield nodes.
62
+ . then_with ( || Ord :: cmp ( & graph[ a] . is_out_summable , & graph[ b] . is_out_summable ) )
63
+ // Prefer an expression for reloop nodes (see definition above).
64
+ . then_with ( || Ord :: cmp ( & is_reloop_node[ a] , & is_reloop_node[ b] ) . reverse ( ) )
65
+ // Otherwise, prefer a physical counter for dominating nodes.
66
+ . then_with ( || graph. cmp_in_dominator_order ( a, b) . reverse ( ) )
67
+ } ) ;
68
+ nodes
69
+ }
70
+
71
+ fn transcribe_counters (
72
+ old : & NodeCounters < BasicCoverageBlock > ,
73
+ bcb_needs_counter : & DenseBitSet < BasicCoverageBlock > ,
74
+ ) -> CoverageCounters {
75
+ let mut new = CoverageCounters :: with_num_bcbs ( bcb_needs_counter. domain_size ( ) ) ;
76
+
77
+ for bcb in bcb_needs_counter. iter ( ) {
78
+ let ( mut pos, mut neg) : ( Vec < _ > , Vec < _ > ) =
79
+ old. counter_expr ( bcb) . iter ( ) . partition_map ( |& CounterTerm { node, op } | match op {
80
+ Op :: Add => Either :: Left ( node) ,
81
+ Op :: Subtract => Either :: Right ( node) ,
82
+ } ) ;
83
+
84
+ if pos. is_empty ( ) {
85
+ // If we somehow end up with no positive terms, fall back to
86
+ // creating a physical counter. There's no known way for this
87
+ // to happen, but we can avoid an ICE if it does.
88
+ debug_assert ! ( false , "{bcb:?} has no positive counter terms" ) ;
89
+ pos = vec ! [ bcb] ;
90
+ neg = vec ! [ ] ;
91
+ }
92
+
93
+ pos. sort ( ) ;
94
+ neg. sort ( ) ;
95
+
96
+ let mut new_counters_for_sites = |sites : Vec < BasicCoverageBlock > | {
97
+ sites. into_iter ( ) . map ( |node| new. ensure_phys_counter ( node) ) . collect :: < Vec < _ > > ( )
98
+ } ;
99
+ let mut pos = new_counters_for_sites ( pos) ;
100
+ let mut neg = new_counters_for_sites ( neg) ;
101
+
102
+ pos. sort ( ) ;
103
+ neg. sort ( ) ;
104
+
105
+ let pos_counter = new. make_sum ( & pos) . expect ( "`pos` should not be empty" ) ;
106
+ let new_counter = new. make_subtracted_sum ( pos_counter, & neg) ;
107
+ new. set_node_counter ( bcb, new_counter) ;
108
+ }
109
+
110
+ new
111
+ }
112
+
23
113
/// The coverage counter or counter expression associated with a particular
24
114
/// BCB node or BCB edge.
25
115
#[ derive( Clone , Copy , PartialEq , Eq , PartialOrd , Ord , Hash ) ]
@@ -73,46 +163,6 @@ pub(super) struct CoverageCounters {
73
163
}
74
164
75
165
impl CoverageCounters {
76
- /// Ensures that each BCB node needing a counter has one, by creating physical
77
- /// counters or counter expressions for nodes and edges as required.
78
- pub ( super ) fn make_bcb_counters (
79
- graph : & CoverageGraph ,
80
- bcb_needs_counter : & DenseBitSet < BasicCoverageBlock > ,
81
- ) -> Self {
82
- let balanced_graph = BalancedFlowGraph :: for_graph ( graph, |n| !graph[ n] . is_out_summable ) ;
83
- let merged_graph = MergedNodeFlowGraph :: for_balanced_graph ( & balanced_graph) ;
84
-
85
- // A "reloop" node has exactly one out-edge, which jumps back to the top
86
- // of an enclosing loop. Reloop nodes are typically visited more times
87
- // than loop-exit nodes, so try to avoid giving them physical counters.
88
- let is_reloop_node = IndexVec :: from_fn_n (
89
- |node| match graph. successors [ node] . as_slice ( ) {
90
- & [ succ] => graph. dominates ( succ, node) ,
91
- _ => false ,
92
- } ,
93
- graph. num_nodes ( ) ,
94
- ) ;
95
-
96
- let mut nodes = balanced_graph. iter_nodes ( ) . rev ( ) . collect :: < Vec < _ > > ( ) ;
97
- // The first node is the sink, which must not get a physical counter.
98
- assert_eq ! ( nodes[ 0 ] , balanced_graph. sink) ;
99
- // Sort the real nodes, such that earlier (lesser) nodes take priority
100
- // in being given a counter expression instead of a physical counter.
101
- nodes[ 1 ..] . sort_by ( |& a, & b| {
102
- // Start with a dummy `Equal` to make the actual tests line up nicely.
103
- Ordering :: Equal
104
- // Prefer a physical counter for return/yield nodes.
105
- . then_with ( || Ord :: cmp ( & graph[ a] . is_out_summable , & graph[ b] . is_out_summable ) )
106
- // Prefer an expression for reloop nodes (see definition above).
107
- . then_with ( || Ord :: cmp ( & is_reloop_node[ a] , & is_reloop_node[ b] ) . reverse ( ) )
108
- // Otherwise, prefer a physical counter for dominating nodes.
109
- . then_with ( || graph. cmp_in_dominator_order ( a, b) . reverse ( ) )
110
- } ) ;
111
- let node_counters = merged_graph. make_node_counters ( & nodes) ;
112
-
113
- Transcriber :: new ( graph. num_nodes ( ) , node_counters) . transcribe_counters ( bcb_needs_counter)
114
- }
115
-
116
166
fn with_num_bcbs ( num_bcbs : usize ) -> Self {
117
167
Self {
118
168
phys_counter_for_node : FxIndexMap :: default ( ) ,
@@ -216,56 +266,3 @@ impl CoverageCounters {
216
266
expressions
217
267
}
218
268
}
219
-
220
- struct Transcriber {
221
- old : NodeCounters < BasicCoverageBlock > ,
222
- new : CoverageCounters ,
223
- }
224
-
225
- impl Transcriber {
226
- fn new ( num_nodes : usize , old : NodeCounters < BasicCoverageBlock > ) -> Self {
227
- Self { old, new : CoverageCounters :: with_num_bcbs ( num_nodes) }
228
- }
229
-
230
- fn transcribe_counters (
231
- mut self ,
232
- bcb_needs_counter : & DenseBitSet < BasicCoverageBlock > ,
233
- ) -> CoverageCounters {
234
- for bcb in bcb_needs_counter. iter ( ) {
235
- let ( mut pos, mut neg) : ( Vec < _ > , Vec < _ > ) =
236
- self . old . counter_expr ( bcb) . iter ( ) . partition_map (
237
- |& CounterTerm { node, op } | match op {
238
- Op :: Add => Either :: Left ( node) ,
239
- Op :: Subtract => Either :: Right ( node) ,
240
- } ,
241
- ) ;
242
-
243
- if pos. is_empty ( ) {
244
- // If we somehow end up with no positive terms, fall back to
245
- // creating a physical counter. There's no known way for this
246
- // to happen, but we can avoid an ICE if it does.
247
- debug_assert ! ( false , "{bcb:?} has no positive counter terms" ) ;
248
- pos = vec ! [ bcb] ;
249
- neg = vec ! [ ] ;
250
- }
251
-
252
- pos. sort ( ) ;
253
- neg. sort ( ) ;
254
-
255
- let mut new_counters_for_sites = |sites : Vec < BasicCoverageBlock > | {
256
- sites. into_iter ( ) . map ( |node| self . new . ensure_phys_counter ( node) ) . collect :: < Vec < _ > > ( )
257
- } ;
258
- let mut pos = new_counters_for_sites ( pos) ;
259
- let mut neg = new_counters_for_sites ( neg) ;
260
-
261
- pos. sort ( ) ;
262
- neg. sort ( ) ;
263
-
264
- let pos_counter = self . new . make_sum ( & pos) . expect ( "`pos` should not be empty" ) ;
265
- let new_counter = self . new . make_subtracted_sum ( pos_counter, & neg) ;
266
- self . new . set_node_counter ( bcb, new_counter) ;
267
- }
268
-
269
- self . new
270
- }
271
- }
0 commit comments