@@ -2,19 +2,11 @@ use crate::coverageinfo::ffi::{Counter, CounterExpression, ExprKind};
2
2
3
3
use rustc_data_structures:: fx:: FxIndexSet ;
4
4
use rustc_index:: bit_set:: BitSet ;
5
- use rustc_index:: IndexVec ;
6
5
use rustc_middle:: mir:: coverage:: {
7
- CodeRegion , CounterId , CovTerm , ExpressionId , FunctionCoverageInfo , Mapping , Op ,
6
+ CodeRegion , CounterId , CovTerm , Expression , ExpressionId , FunctionCoverageInfo , Mapping , Op ,
8
7
} ;
9
8
use rustc_middle:: ty:: Instance ;
10
9
11
- #[ derive( Clone , Debug , PartialEq ) ]
12
- pub struct Expression {
13
- lhs : CovTerm ,
14
- op : Op ,
15
- rhs : CovTerm ,
16
- }
17
-
18
10
/// Holds all of the coverage mapping data associated with a function instance,
19
11
/// collected during traversal of `Coverage` statements in the function's MIR.
20
12
#[ derive( Debug ) ]
@@ -26,7 +18,12 @@ pub struct FunctionCoverage<'tcx> {
26
18
/// Tracks which counters have been seen, so that we can identify mappings
27
19
/// to counters that were optimized out, and set them to zero.
28
20
counters_seen : BitSet < CounterId > ,
29
- expressions : IndexVec < ExpressionId , Option < Expression > > ,
21
+ /// Contains all expression IDs that have been seen in an `ExpressionUsed`
22
+ /// coverage statement, plus all expression IDs that aren't directly used
23
+ /// by any mappings (and therefore do not have expression-used statements).
24
+ /// After MIR traversal is finished, we can conclude that any IDs missing
25
+ /// from this set must have had their statements deleted by MIR opts.
26
+ expressions_seen : BitSet < ExpressionId > ,
30
27
}
31
28
32
29
impl < ' tcx > FunctionCoverage < ' tcx > {
@@ -52,16 +49,30 @@ impl<'tcx> FunctionCoverage<'tcx> {
52
49
is_used : bool ,
53
50
) -> Self {
54
51
let num_counters = function_coverage_info. num_counters ;
55
- let num_expressions = function_coverage_info. num_expressions ;
52
+ let num_expressions = function_coverage_info. expressions . len ( ) ;
56
53
debug ! (
57
54
"FunctionCoverage::create(instance={instance:?}) has \
58
55
num_counters={num_counters}, num_expressions={num_expressions}, is_used={is_used}"
59
56
) ;
57
+
58
+ // Create a filled set of expression IDs, so that expressions not
59
+ // directly used by mappings will be treated as "seen".
60
+ // (If they end up being unused, LLVM will delete them for us.)
61
+ let mut expressions_seen = BitSet :: new_filled ( num_expressions) ;
62
+ // For each expression ID that is directly used by one or more mappings,
63
+ // mark it as not-yet-seen. This indicates that we expect to see a
64
+ // corresponding `ExpressionUsed` statement during MIR traversal.
65
+ for Mapping { term, .. } in & function_coverage_info. mappings {
66
+ if let & CovTerm :: Expression ( id) = term {
67
+ expressions_seen. remove ( id) ;
68
+ }
69
+ }
70
+
60
71
Self {
61
72
function_coverage_info,
62
73
is_used,
63
74
counters_seen : BitSet :: new_empty ( num_counters) ,
64
- expressions : IndexVec :: from_elem_n ( None , num_expressions ) ,
75
+ expressions_seen ,
65
76
}
66
77
}
67
78
@@ -76,35 +87,10 @@ impl<'tcx> FunctionCoverage<'tcx> {
76
87
self . counters_seen . insert ( id) ;
77
88
}
78
89
79
- /// Adds information about a coverage expression.
90
+ /// Marks an expression ID as having been seen in an expression-used statement .
80
91
#[ 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
- }
92
+ pub ( crate ) fn mark_expression_id_seen ( & mut self , id : ExpressionId ) {
93
+ self . expressions_seen . insert ( id) ;
108
94
}
109
95
110
96
/// Identify expressions that will always have a value of zero, and note
@@ -125,13 +111,13 @@ impl<'tcx> FunctionCoverage<'tcx> {
125
111
// and then update the set of always-zero expressions if necessary.
126
112
// (By construction, expressions can only refer to other expressions
127
113
// 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,
114
+ for ( id, expression ) in self . function_coverage_info . expressions . iter_enumerated ( ) {
115
+ if ! self . expressions_seen . contains ( id ) {
116
+ // If an expression was not seen , it must have been optimized away,
131
117
// so any operand that refers to it can be replaced with zero.
132
118
zero_expressions. insert ( id) ;
133
119
continue ;
134
- } ;
120
+ }
135
121
136
122
// We don't need to simplify the actual expression data in the
137
123
// expressions list; we can just simplify a temporary copy and then
@@ -197,7 +183,7 @@ impl<'tcx> FunctionCoverage<'tcx> {
197
183
// Expression IDs are indices into `self.expressions`, and on the LLVM
198
184
// side they will be treated as indices into `counter_expressions`, so
199
185
// the two vectors should correspond 1:1.
200
- assert_eq ! ( self . expressions. len( ) , counter_expressions. len( ) ) ;
186
+ assert_eq ! ( self . function_coverage_info . expressions. len( ) , counter_expressions. len( ) ) ;
201
187
202
188
let counter_regions = self . counter_regions ( zero_expressions) ;
203
189
@@ -217,27 +203,16 @@ impl<'tcx> FunctionCoverage<'tcx> {
217
203
_ => Counter :: from_term ( operand) ,
218
204
} ;
219
205
220
- self . expressions
206
+ self . function_coverage_info
207
+ . expressions
221
208
. iter ( )
222
- . map ( |expression| match expression {
223
- None => {
224
- // This expression ID was allocated, but we never saw the
225
- // actual expression, so it must have been optimized out.
226
- // Replace it with a dummy expression, and let LLVM take
227
- // care of omitting it from the expression list.
228
- CounterExpression :: DUMMY
229
- }
230
- & Some ( Expression { lhs, op, rhs, .. } ) => {
231
- // Convert the operands and operator as normal.
232
- CounterExpression :: new (
233
- counter_from_operand ( lhs) ,
234
- match op {
235
- Op :: Add => ExprKind :: Add ,
236
- Op :: Subtract => ExprKind :: Subtract ,
237
- } ,
238
- counter_from_operand ( rhs) ,
239
- )
240
- }
209
+ . map ( |& Expression { lhs, op, rhs } | CounterExpression {
210
+ lhs : counter_from_operand ( lhs) ,
211
+ kind : match op {
212
+ Op :: Add => ExprKind :: Add ,
213
+ Op :: Subtract => ExprKind :: Subtract ,
214
+ } ,
215
+ rhs : counter_from_operand ( rhs) ,
241
216
} )
242
217
. collect :: < Vec < _ > > ( )
243
218
}
0 commit comments