@@ -2,19 +2,11 @@ use crate::coverageinfo::ffi::{Counter, CounterExpression, ExprKind};
22
33use rustc_data_structures:: fx:: FxIndexSet ;
44use rustc_index:: bit_set:: BitSet ;
5- use rustc_index:: IndexVec ;
65use rustc_middle:: mir:: coverage:: {
7- CodeRegion , CounterId , CovTerm , ExpressionId , FunctionCoverageInfo , Mapping , Op ,
6+ CodeRegion , CounterId , CovTerm , Expression , ExpressionId , FunctionCoverageInfo , Mapping , Op ,
87} ;
98use rustc_middle:: ty:: Instance ;
109
11- #[ derive( Clone , Debug , PartialEq ) ]
12- pub struct Expression {
13- lhs : CovTerm ,
14- op : Op ,
15- rhs : CovTerm ,
16- }
17-
1810/// Holds all of the coverage mapping data associated with a function instance,
1911/// collected during traversal of `Coverage` statements in the function's MIR.
2012#[ derive( Debug ) ]
@@ -26,7 +18,9 @@ pub struct FunctionCoverage<'tcx> {
2618 /// Tracks which counters have been seen, so that we can identify mappings
2719 /// to counters that were optimized out, and set them to zero.
2820 counters_seen : BitSet < CounterId > ,
29- expressions : IndexVec < ExpressionId , Option < Expression > > ,
21+ /// Tracks which expressions have one or more associated mappings, but have
22+ /// not yet been seen. This lets us detect that they were optimized out.
23+ expressions_not_seen : BitSet < ExpressionId > ,
3024}
3125
3226impl < ' tcx > FunctionCoverage < ' tcx > {
@@ -52,16 +46,27 @@ impl<'tcx> FunctionCoverage<'tcx> {
5246 is_used : bool ,
5347 ) -> Self {
5448 let num_counters = function_coverage_info. num_counters ;
55- let num_expressions = function_coverage_info. num_expressions ;
49+ let num_expressions = function_coverage_info. expressions . len ( ) ;
5650 debug ! (
5751 "FunctionCoverage::create(instance={instance:?}) has \
5852 num_counters={num_counters}, num_expressions={num_expressions}, is_used={is_used}"
5953 ) ;
54+
55+ // Every expression that has an associated mapping should have a
56+ // corresponding statement in MIR. If we don't see that statement, we
57+ // know that it was removed by MIR optimizations.
58+ let mut expressions_not_seen = BitSet :: new_empty ( num_expressions) ;
59+ for Mapping { term, .. } in & function_coverage_info. mappings {
60+ if let & CovTerm :: Expression ( id) = term {
61+ expressions_not_seen. insert ( id) ;
62+ }
63+ }
64+
6065 Self {
6166 function_coverage_info,
6267 is_used,
6368 counters_seen : BitSet :: new_empty ( num_counters) ,
64- expressions : IndexVec :: from_elem_n ( None , num_expressions ) ,
69+ expressions_not_seen ,
6570 }
6671 }
6772
@@ -76,35 +81,10 @@ impl<'tcx> FunctionCoverage<'tcx> {
7681 self . counters_seen . insert ( id) ;
7782 }
7883
79- /// Adds information about a coverage expression .
84+ /// Marks an expression ID as having been seen .
8085 #[ instrument( level = "debug" , skip( self ) ) ]
81- pub ( crate ) fn add_counter_expression (
82- & mut self ,
83- expression_id : ExpressionId ,
84- lhs : CovTerm ,
85- op : Op ,
86- rhs : CovTerm ,
87- ) {
88- debug_assert ! (
89- expression_id. as_usize( ) < self . expressions. len( ) ,
90- "expression_id {} is out of range for expressions.len() = {}
91- for {:?}" ,
92- expression_id. as_usize( ) ,
93- self . expressions. len( ) ,
94- self ,
95- ) ;
96-
97- let expression = Expression { lhs, op, rhs } ;
98- let slot = & mut self . expressions [ expression_id] ;
99- match slot {
100- None => * slot = Some ( expression) ,
101- // If this expression ID slot has already been filled, it should
102- // contain identical information.
103- Some ( ref previous_expression) => assert_eq ! (
104- previous_expression, & expression,
105- "add_counter_expression: expression for id changed"
106- ) ,
107- }
86+ pub ( crate ) fn add_counter_expression ( & mut self , expression_id : ExpressionId ) {
87+ self . expressions_not_seen . remove ( expression_id) ;
10888 }
10989
11090 /// Identify expressions that will always have a value of zero, and note
@@ -125,13 +105,13 @@ impl<'tcx> FunctionCoverage<'tcx> {
125105 // and then update the set of always-zero expressions if necessary.
126106 // (By construction, expressions can only refer to other expressions
127107 // that have lower IDs, so one pass is sufficient.)
128- for ( id, maybe_expression ) in self . expressions . iter_enumerated ( ) {
129- let Some ( expression ) = maybe_expression else {
130- // If an expression is missing , it must have been optimized away,
108+ for ( id, expression ) in self . function_coverage_info . expressions . iter_enumerated ( ) {
109+ if self . expressions_not_seen . contains ( id ) {
110+ // If an expression was not seen , it must have been optimized away,
131111 // so any operand that refers to it can be replaced with zero.
132112 zero_expressions. insert ( id) ;
133113 continue ;
134- } ;
114+ }
135115
136116 // We don't need to simplify the actual expression data in the
137117 // expressions list; we can just simplify a temporary copy and then
@@ -184,7 +164,7 @@ impl<'tcx> FunctionCoverage<'tcx> {
184164 // Expression IDs are indices into `self.expressions`, and on the LLVM
185165 // side they will be treated as indices into `counter_expressions`, so
186166 // the two vectors should correspond 1:1.
187- assert_eq ! ( self . expressions. len( ) , counter_expressions. len( ) ) ;
167+ assert_eq ! ( self . function_coverage_info . expressions. len( ) , counter_expressions. len( ) ) ;
188168
189169 let counter_regions = self . counter_regions ( zero_expressions) ;
190170
@@ -204,17 +184,17 @@ impl<'tcx> FunctionCoverage<'tcx> {
204184 _ => Counter :: from_term ( operand) ,
205185 } ;
206186
207- self . expressions
208- . iter ( )
209- . map ( |expression| match expression {
210- None => {
187+ self . function_coverage_info
188+ . expressions
189+ . iter_enumerated ( )
190+ . map ( |( id, & Expression { lhs, op, rhs } ) | {
191+ if self . expressions_not_seen . contains ( id) {
211192 // This expression ID was allocated, but we never saw the
212193 // actual expression, so it must have been optimized out.
213194 // Replace it with a dummy expression, and let LLVM take
214195 // care of omitting it from the expression list.
215196 CounterExpression :: DUMMY
216- }
217- & Some ( Expression { lhs, op, rhs, .. } ) => {
197+ } else {
218198 // Convert the operands and operator as normal.
219199 CounterExpression :: new (
220200 counter_from_operand ( lhs) ,
0 commit comments