@@ -2,18 +2,18 @@ pub use super::ffi::*;
22
33use rustc_index:: vec:: IndexVec ;
44use rustc_middle:: mir:: coverage:: {
5- CodeRegion , CounterValueReference , ExpressionOperandId , InjectedExpressionIndex ,
6- MappedExpressionIndex , Op ,
5+ CodeRegion , CounterValueReference , ExpressionOperandId , InjectedExpressionId ,
6+ InjectedExpressionIndex , MappedExpressionIndex , Op ,
77} ;
88use rustc_middle:: ty:: Instance ;
99use rustc_middle:: ty:: TyCtxt ;
1010
1111#[ derive( Clone , Debug ) ]
12- pub struct ExpressionRegion {
12+ pub struct Expression {
1313 lhs : ExpressionOperandId ,
1414 op : Op ,
1515 rhs : ExpressionOperandId ,
16- region : CodeRegion ,
16+ region : Option < CodeRegion > ,
1717}
1818
1919/// Collects all of the coverage regions associated with (a) injected counters, (b) counter
@@ -28,24 +28,43 @@ pub struct ExpressionRegion {
2828/// only whitespace or comments). According to LLVM Code Coverage Mapping documentation, "A count
2929/// for a gap area is only used as the line execution count if there are no other regions on a
3030/// line."
31- pub struct FunctionCoverage {
31+ pub struct FunctionCoverage < ' tcx > {
32+ instance : Instance < ' tcx > ,
3233 source_hash : u64 ,
3334 counters : IndexVec < CounterValueReference , Option < CodeRegion > > ,
34- expressions : IndexVec < InjectedExpressionIndex , Option < ExpressionRegion > > ,
35+ expressions : IndexVec < InjectedExpressionIndex , Option < Expression > > ,
3536 unreachable_regions : Vec < CodeRegion > ,
3637}
3738
38- impl FunctionCoverage {
39- pub fn new < ' tcx > ( tcx : TyCtxt < ' tcx > , instance : Instance < ' tcx > ) -> Self {
39+ impl < ' tcx > FunctionCoverage < ' tcx > {
40+ pub fn new ( tcx : TyCtxt < ' tcx > , instance : Instance < ' tcx > ) -> Self {
4041 let coverageinfo = tcx. coverageinfo ( instance. def_id ( ) ) ;
42+ debug ! (
43+ "FunctionCoverage::new(instance={:?}) has coverageinfo={:?}" ,
44+ instance, coverageinfo
45+ ) ;
4146 Self {
47+ instance,
4248 source_hash : 0 , // will be set with the first `add_counter()`
4349 counters : IndexVec :: from_elem_n ( None , coverageinfo. num_counters as usize ) ,
4450 expressions : IndexVec :: from_elem_n ( None , coverageinfo. num_expressions as usize ) ,
4551 unreachable_regions : Vec :: new ( ) ,
4652 }
4753 }
4854
55+ /// Although every function should have at least one `Counter`, the `Counter` isn't required to
56+ /// have a `CodeRegion`. (The `CodeRegion` may be associated only with `Expressions`.) This
57+ /// method supports the ability to ensure the `function_source_hash` is set from `Counters` that
58+ /// do not trigger the call to `add_counter()` because they don't have an associated
59+ /// `CodeRegion` to add.
60+ pub fn set_function_source_hash ( & mut self , source_hash : u64 ) {
61+ if self . source_hash == 0 {
62+ self . source_hash = source_hash;
63+ } else {
64+ debug_assert_eq ! ( source_hash, self . source_hash) ;
65+ }
66+ }
67+
4968 /// Adds a code region to be counted by an injected counter intrinsic.
5069 /// The source_hash (computed during coverage instrumentation) should also be provided, and
5170 /// should be the same for all counters in a given function.
@@ -74,15 +93,19 @@ impl FunctionCoverage {
7493 /// counters and expressions have been added.
7594 pub fn add_counter_expression (
7695 & mut self ,
77- expression_id : InjectedExpressionIndex ,
96+ expression_id : InjectedExpressionId ,
7897 lhs : ExpressionOperandId ,
7998 op : Op ,
8099 rhs : ExpressionOperandId ,
81- region : CodeRegion ,
100+ region : Option < CodeRegion > ,
82101 ) {
102+ debug ! (
103+ "add_counter_expression({:?}, lhs={:?}, op={:?}, rhs={:?} at {:?}" ,
104+ expression_id, lhs, op, rhs, region
105+ ) ;
83106 let expression_index = self . expression_index ( u32:: from ( expression_id) ) ;
84107 self . expressions [ expression_index]
85- . replace ( ExpressionRegion { lhs, op, rhs, region } )
108+ . replace ( Expression { lhs, op, rhs, region } )
86109 . expect_none ( "add_counter_expression called with duplicate `id_descending_from_max`" ) ;
87110 }
88111
@@ -103,7 +126,11 @@ impl FunctionCoverage {
103126 pub fn get_expressions_and_counter_regions < ' a > (
104127 & ' a self ,
105128 ) -> ( Vec < CounterExpression > , impl Iterator < Item = ( Counter , & ' a CodeRegion ) > ) {
106- assert ! ( self . source_hash != 0 ) ;
129+ assert ! (
130+ self . source_hash != 0 ,
131+ "No counters provided the source_hash for function: {:?}" ,
132+ self . instance
133+ ) ;
107134
108135 let counter_regions = self . counter_regions ( ) ;
109136 let ( counter_expressions, expression_regions) = self . expressions_with_regions ( ) ;
@@ -129,54 +156,60 @@ impl FunctionCoverage {
129156 ) -> ( Vec < CounterExpression > , impl Iterator < Item = ( Counter , & ' a CodeRegion ) > ) {
130157 let mut counter_expressions = Vec :: with_capacity ( self . expressions . len ( ) ) ;
131158 let mut expression_regions = Vec :: with_capacity ( self . expressions . len ( ) ) ;
132- let mut new_indexes =
133- IndexVec :: from_elem_n ( MappedExpressionIndex :: from ( u32:: MAX ) , self . expressions . len ( ) ) ;
134- // Note, the initial value shouldn't matter since every index in use in `self.expressions`
135- // will be set, and after that, `new_indexes` will only be accessed using those same
136- // indexes.
137-
138- // Note that an `ExpressionRegion`s at any given index can include other expressions as
159+ let mut new_indexes = IndexVec :: from_elem_n ( None , self . expressions . len ( ) ) ;
160+ // Note that an `Expression`s at any given index can include other expressions as
139161 // operands, but expression operands can only come from the subset of expressions having
140- // `expression_index`s lower than the referencing `ExpressionRegion `. Therefore, it is
162+ // `expression_index`s lower than the referencing `Expression `. Therefore, it is
141163 // reasonable to look up the new index of an expression operand while the `new_indexes`
142164 // vector is only complete up to the current `ExpressionIndex`.
143165 let id_to_counter =
144- |new_indexes : & IndexVec < InjectedExpressionIndex , MappedExpressionIndex > ,
166+ |new_indexes : & IndexVec < InjectedExpressionIndex , Option < MappedExpressionIndex > > ,
145167 id : ExpressionOperandId | {
146168 if id == ExpressionOperandId :: ZERO {
147169 Some ( Counter :: zero ( ) )
148170 } else if id. index ( ) < self . counters . len ( ) {
171+ // Note: Some codegen-injected Counters may be only referenced by `Expression`s,
172+ // and may not have their own `CodeRegion`s,
149173 let index = CounterValueReference :: from ( id. index ( ) ) ;
150- self . counters
151- . get ( index)
152- . unwrap ( ) // pre-validated
153- . as_ref ( )
154- . map ( |_| Counter :: counter_value_reference ( index) )
174+ Some ( Counter :: counter_value_reference ( index) )
155175 } else {
156176 let index = self . expression_index ( u32:: from ( id) ) ;
157177 self . expressions
158178 . get ( index)
159179 . expect ( "expression id is out of range" )
160180 . as_ref ( )
161- . map ( |_| Counter :: expression ( new_indexes[ index] ) )
181+ // If an expression was optimized out, assume it would have produced a count
182+ // of zero. This ensures that expressions dependent on optimized-out
183+ // expressions are still valid.
184+ . map_or ( Some ( Counter :: zero ( ) ) , |_| {
185+ new_indexes[ index] . map ( |new_index| Counter :: expression ( new_index) )
186+ } )
162187 }
163188 } ;
164189
165- for ( original_index, expression_region ) in
190+ for ( original_index, expression ) in
166191 self . expressions . iter_enumerated ( ) . filter_map ( |( original_index, entry) | {
167192 // Option::map() will return None to filter out missing expressions. This may happen
168193 // if, for example, a MIR-instrumented expression is removed during an optimization.
169- entry. as_ref ( ) . map ( |region | ( original_index, region ) )
194+ entry. as_ref ( ) . map ( |expression | ( original_index, expression ) )
170195 } )
171196 {
172- let region = & expression_region . region ;
173- let ExpressionRegion { lhs, op, rhs, .. } = * expression_region ;
197+ let optional_region = & expression . region ;
198+ let Expression { lhs, op, rhs, .. } = * expression ;
174199
175200 if let Some ( Some ( ( lhs_counter, rhs_counter) ) ) =
176201 id_to_counter ( & new_indexes, lhs) . map ( |lhs_counter| {
177202 id_to_counter ( & new_indexes, rhs) . map ( |rhs_counter| ( lhs_counter, rhs_counter) )
178203 } )
179204 {
205+ debug_assert ! (
206+ ( lhs_counter. id as usize )
207+ < usize :: max( self . counters. len( ) , self . expressions. len( ) )
208+ ) ;
209+ debug_assert ! (
210+ ( rhs_counter. id as usize )
211+ < usize :: max( self . counters. len( ) , self . expressions. len( ) )
212+ ) ;
180213 // Both operands exist. `Expression` operands exist in `self.expressions` and have
181214 // been assigned a `new_index`.
182215 let mapped_expression_index =
@@ -190,12 +223,20 @@ impl FunctionCoverage {
190223 rhs_counter,
191224 ) ;
192225 debug ! (
193- "Adding expression {:?} = {:?} at {:?}" ,
194- mapped_expression_index, expression, region
226+ "Adding expression {:?} = {:?}, region: {:?}" ,
227+ mapped_expression_index, expression, optional_region
195228 ) ;
196229 counter_expressions. push ( expression) ;
197- new_indexes[ original_index] = mapped_expression_index;
198- expression_regions. push ( ( Counter :: expression ( mapped_expression_index) , region) ) ;
230+ new_indexes[ original_index] = Some ( mapped_expression_index) ;
231+ if let Some ( region) = optional_region {
232+ expression_regions. push ( ( Counter :: expression ( mapped_expression_index) , region) ) ;
233+ }
234+ } else {
235+ debug ! (
236+ "Ignoring expression with one or more missing operands: \
237+ original_index={:?}, lhs={:?}, op={:?}, rhs={:?}, region={:?}",
238+ original_index, lhs, op, rhs, optional_region,
239+ )
199240 }
200241 }
201242 ( counter_expressions, expression_regions. into_iter ( ) )
0 commit comments