1
1
use crate :: coverageinfo:: ffi:: { Counter , CounterExpression , ExprKind } ;
2
2
3
3
use rustc_data_structures:: fx:: FxIndexSet ;
4
+ use rustc_index:: bit_set:: BitSet ;
4
5
use rustc_index:: IndexVec ;
5
6
use rustc_middle:: mir:: coverage:: { CodeRegion , CounterId , CovTerm , ExpressionId , Op } ;
6
7
use rustc_middle:: ty:: Instance ;
@@ -11,7 +12,6 @@ pub struct Expression {
11
12
lhs : CovTerm ,
12
13
op : Op ,
13
14
rhs : CovTerm ,
14
- code_regions : Vec < CodeRegion > ,
15
15
}
16
16
17
17
/// Collects all of the coverage regions associated with (a) injected counters, (b) counter
@@ -30,9 +30,10 @@ pub struct FunctionCoverage<'tcx> {
30
30
instance : Instance < ' tcx > ,
31
31
source_hash : u64 ,
32
32
is_used : bool ,
33
- counters : IndexVec < CounterId , Option < Vec < CodeRegion > > > ,
33
+
34
+ counters_seen : BitSet < CounterId > ,
34
35
expressions : IndexVec < ExpressionId , Option < Expression > > ,
35
- unreachable_regions : Vec < CodeRegion > ,
36
+ mappings : Vec < ( CovTerm , CodeRegion ) > ,
36
37
}
37
38
38
39
impl < ' tcx > FunctionCoverage < ' tcx > {
@@ -56,9 +57,9 @@ impl<'tcx> FunctionCoverage<'tcx> {
56
57
instance,
57
58
source_hash : 0 , // will be set with the first `add_counter()`
58
59
is_used,
59
- counters : IndexVec :: from_elem_n ( None , coverageinfo. num_counters as usize ) ,
60
+ counters_seen : BitSet :: new_empty ( coverageinfo. num_counters as usize ) ,
60
61
expressions : IndexVec :: from_elem_n ( None , coverageinfo. num_expressions as usize ) ,
61
- unreachable_regions : Vec :: new ( ) ,
62
+ mappings : Vec :: new ( ) ,
62
63
}
63
64
}
64
65
@@ -80,20 +81,10 @@ impl<'tcx> FunctionCoverage<'tcx> {
80
81
/// Adds code regions to be counted by an injected counter intrinsic.
81
82
#[ instrument( level = "debug" , skip( self ) ) ]
82
83
pub ( crate ) fn add_counter ( & mut self , id : CounterId , code_regions : & [ CodeRegion ] ) {
83
- if code_regions . is_empty ( ) {
84
+ if ! self . counters_seen . insert ( id ) {
84
85
return ;
85
86
}
86
-
87
- let slot = & mut self . counters [ id] ;
88
- match slot {
89
- None => * slot = Some ( code_regions. to_owned ( ) ) ,
90
- // If this counter ID slot has already been filled, it should
91
- // contain identical information.
92
- Some ( ref previous_regions) => assert_eq ! (
93
- previous_regions, code_regions,
94
- "add_counter: code regions for id changed"
95
- ) ,
96
- }
87
+ self . add_mappings ( CovTerm :: Counter ( id) , code_regions) ;
97
88
}
98
89
99
90
/// Adds information about a coverage expression, along with zero or more
@@ -120,24 +111,45 @@ impl<'tcx> FunctionCoverage<'tcx> {
120
111
self ,
121
112
) ;
122
113
123
- let expression = Expression { lhs, op, rhs, code_regions : code_regions . to_owned ( ) } ;
114
+ let expression = Expression { lhs, op, rhs } ;
124
115
let slot = & mut self . expressions [ expression_id] ;
125
116
match slot {
126
117
None => * slot = Some ( expression) ,
127
118
// If this expression ID slot has already been filled, it should
128
119
// contain identical information.
129
- Some ( ref previous_expression) => assert_eq ! (
130
- previous_expression, & expression,
131
- "add_counter_expression: expression for id changed"
132
- ) ,
120
+ Some ( ref previous_expression) => {
121
+ assert_eq ! (
122
+ previous_expression, & expression,
123
+ "add_counter_expression: expression for id changed"
124
+ ) ;
125
+ return ;
126
+ }
133
127
}
128
+
129
+ self . add_mappings ( CovTerm :: Expression ( expression_id) , code_regions) ;
134
130
}
135
131
136
132
/// Adds regions that will be marked as "unreachable", with a constant "zero counter".
137
133
#[ instrument( level = "debug" , skip( self ) ) ]
138
134
pub ( crate ) fn add_unreachable_regions ( & mut self , code_regions : & [ CodeRegion ] ) {
139
135
assert ! ( !code_regions. is_empty( ) , "unreachable regions always have code regions" ) ;
140
- self . unreachable_regions . extend_from_slice ( code_regions) ;
136
+ self . add_mappings ( CovTerm :: Zero , code_regions) ;
137
+ }
138
+
139
+ fn add_mappings ( & mut self , kind : CovTerm , code_regions : & [ CodeRegion ] ) {
140
+ self . mappings
141
+ . extend ( code_regions. iter ( ) . cloned ( ) . map ( move |code_region| ( kind, code_region) ) ) ;
142
+ }
143
+
144
+ pub ( crate ) fn finalize ( & mut self ) {
145
+ self . simplify_expressions ( ) ;
146
+
147
+ let mapping_kind_sort_key = |mapping_kind : & CovTerm | match mapping_kind {
148
+ CovTerm :: Counter ( _) => 0 ,
149
+ CovTerm :: Expression ( _) => 1 ,
150
+ CovTerm :: Zero => u8:: MAX ,
151
+ } ;
152
+ self . mappings . sort_by_key ( |( mapping_kind, _) | mapping_kind_sort_key ( mapping_kind) ) ;
141
153
}
142
154
143
155
/// Perform some simplifications to make the final coverage mappings
@@ -146,7 +158,7 @@ impl<'tcx> FunctionCoverage<'tcx> {
146
158
/// This method mainly exists to preserve the simplifications that were
147
159
/// already being performed by the Rust-side expression renumbering, so that
148
160
/// the resulting coverage mappings don't get worse.
149
- pub ( crate ) fn simplify_expressions ( & mut self ) {
161
+ fn simplify_expressions ( & mut self ) {
150
162
// The set of expressions that either were optimized out entirely, or
151
163
// have zero as both of their operands, and will therefore always have
152
164
// a value of zero. Other expressions that refer to these as operands
@@ -216,28 +228,14 @@ impl<'tcx> FunctionCoverage<'tcx> {
216
228
// the two vectors should correspond 1:1.
217
229
assert_eq ! ( self . expressions. len( ) , counter_expressions. len( ) ) ;
218
230
219
- let counter_regions = self . counter_regions ( ) ;
220
- let expression_regions = self . expression_regions ( ) ;
221
- let unreachable_regions = self . unreachable_regions ( ) ;
231
+ let counter_regions = self . mappings . iter ( ) . map ( |( mapping_kind, code_region) | {
232
+ let counter = Counter :: from_term ( * mapping_kind) ;
233
+ ( counter, code_region)
234
+ } ) ;
222
235
223
- let counter_regions =
224
- counter_regions. chain ( expression_regions. into_iter ( ) . chain ( unreachable_regions) ) ;
225
236
( counter_expressions, counter_regions)
226
237
}
227
238
228
- fn counter_regions ( & self ) -> impl Iterator < Item = ( Counter , & CodeRegion ) > {
229
- self . counters
230
- . iter_enumerated ( )
231
- // Filter out counter IDs that we never saw during MIR traversal.
232
- // This can happen if a counter was optimized out by MIR transforms
233
- // (and replaced with `CoverageKind::Unreachable` instead).
234
- . filter_map ( |( id, maybe_code_regions) | Some ( ( id, maybe_code_regions. as_ref ( ) ?) ) )
235
- . flat_map ( |( id, code_regions) | {
236
- let counter = Counter :: counter_value_reference ( id) ;
237
- code_regions. iter ( ) . map ( move |region| ( counter, region) )
238
- } )
239
- }
240
-
241
239
/// Convert this function's coverage expression data into a form that can be
242
240
/// passed through FFI to LLVM.
243
241
fn counter_expressions ( & self ) -> Vec < CounterExpression > {
@@ -267,25 +265,4 @@ impl<'tcx> FunctionCoverage<'tcx> {
267
265
} )
268
266
. collect :: < Vec < _ > > ( )
269
267
}
270
-
271
- fn expression_regions ( & self ) -> Vec < ( Counter , & CodeRegion ) > {
272
- // Find all of the expression IDs that weren't optimized out AND have
273
- // one or more attached code regions, and return the corresponding
274
- // mappings as counter/region pairs.
275
- self . expressions
276
- . iter_enumerated ( )
277
- . filter_map ( |( id, maybe_expression) | {
278
- let code_regions = & maybe_expression. as_ref ( ) ?. code_regions ;
279
- Some ( ( id, code_regions) )
280
- } )
281
- . flat_map ( |( id, code_regions) | {
282
- let counter = Counter :: expression ( id) ;
283
- code_regions. iter ( ) . map ( move |code_region| ( counter, code_region) )
284
- } )
285
- . collect :: < Vec < _ > > ( )
286
- }
287
-
288
- fn unreachable_regions ( & self ) -> impl Iterator < Item = ( Counter , & CodeRegion ) > {
289
- self . unreachable_regions . iter ( ) . map ( |region| ( Counter :: ZERO , region) )
290
- }
291
268
}
0 commit comments