11use crate :: coverageinfo:: ffi:: { Counter , CounterExpression , ExprKind } ;
22
33use rustc_data_structures:: fx:: FxIndexSet ;
4+ use rustc_index:: bit_set:: BitSet ;
45use rustc_index:: IndexVec ;
56use rustc_middle:: mir:: coverage:: { CodeRegion , CounterId , CovTerm , ExpressionId , Op } ;
67use rustc_middle:: ty:: Instance ;
@@ -11,7 +12,6 @@ pub struct Expression {
1112 lhs : CovTerm ,
1213 op : Op ,
1314 rhs : CovTerm ,
14- code_regions : Vec < CodeRegion > ,
1515}
1616
1717/// Collects all of the coverage regions associated with (a) injected counters, (b) counter
@@ -30,9 +30,10 @@ pub struct FunctionCoverage<'tcx> {
3030 instance : Instance < ' tcx > ,
3131 source_hash : u64 ,
3232 is_used : bool ,
33- counters : IndexVec < CounterId , Option < Vec < CodeRegion > > > ,
33+
34+ counters_seen : BitSet < CounterId > ,
3435 expressions : IndexVec < ExpressionId , Option < Expression > > ,
35- unreachable_regions : Vec < CodeRegion > ,
36+ mappings : Vec < ( CovTerm , CodeRegion ) > ,
3637}
3738
3839impl < ' tcx > FunctionCoverage < ' tcx > {
@@ -56,9 +57,9 @@ impl<'tcx> FunctionCoverage<'tcx> {
5657 instance,
5758 source_hash : 0 , // will be set with the first `add_counter()`
5859 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 ) ,
6061 expressions : IndexVec :: from_elem_n ( None , coverageinfo. num_expressions as usize ) ,
61- unreachable_regions : Vec :: new ( ) ,
62+ mappings : Vec :: new ( ) ,
6263 }
6364 }
6465
@@ -80,20 +81,10 @@ impl<'tcx> FunctionCoverage<'tcx> {
8081 /// Adds code regions to be counted by an injected counter intrinsic.
8182 #[ instrument( level = "debug" , skip( self ) ) ]
8283 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 ) {
8485 return ;
8586 }
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) ;
9788 }
9889
9990 /// Adds information about a coverage expression, along with zero or more
@@ -120,24 +111,45 @@ impl<'tcx> FunctionCoverage<'tcx> {
120111 self ,
121112 ) ;
122113
123- let expression = Expression { lhs, op, rhs, code_regions : code_regions . to_owned ( ) } ;
114+ let expression = Expression { lhs, op, rhs } ;
124115 let slot = & mut self . expressions [ expression_id] ;
125116 match slot {
126117 None => * slot = Some ( expression) ,
127118 // If this expression ID slot has already been filled, it should
128119 // 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+ }
133127 }
128+
129+ self . add_mappings ( CovTerm :: Expression ( expression_id) , code_regions) ;
134130 }
135131
136132 /// Adds regions that will be marked as "unreachable", with a constant "zero counter".
137133 #[ instrument( level = "debug" , skip( self ) ) ]
138134 pub ( crate ) fn add_unreachable_regions ( & mut self , code_regions : & [ CodeRegion ] ) {
139135 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) ) ;
141153 }
142154
143155 /// Perform some simplifications to make the final coverage mappings
@@ -146,7 +158,7 @@ impl<'tcx> FunctionCoverage<'tcx> {
146158 /// This method mainly exists to preserve the simplifications that were
147159 /// already being performed by the Rust-side expression renumbering, so that
148160 /// the resulting coverage mappings don't get worse.
149- pub ( crate ) fn simplify_expressions ( & mut self ) {
161+ fn simplify_expressions ( & mut self ) {
150162 // The set of expressions that either were optimized out entirely, or
151163 // have zero as both of their operands, and will therefore always have
152164 // a value of zero. Other expressions that refer to these as operands
@@ -216,28 +228,14 @@ impl<'tcx> FunctionCoverage<'tcx> {
216228 // the two vectors should correspond 1:1.
217229 assert_eq ! ( self . expressions. len( ) , counter_expressions. len( ) ) ;
218230
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+ } ) ;
222235
223- let counter_regions =
224- counter_regions. chain ( expression_regions. into_iter ( ) . chain ( unreachable_regions) ) ;
225236 ( counter_expressions, counter_regions)
226237 }
227238
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-
241239 /// Convert this function's coverage expression data into a form that can be
242240 /// passed through FFI to LLVM.
243241 fn counter_expressions ( & self ) -> Vec < CounterExpression > {
@@ -267,25 +265,4 @@ impl<'tcx> FunctionCoverage<'tcx> {
267265 } )
268266 . collect :: < Vec < _ > > ( )
269267 }
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- }
291268}
0 commit comments