@@ -27,6 +27,9 @@ pub struct FunctionCoverage<'tcx> {
27
27
/// that might be introduced by MIR inlining.
28
28
counters_seen : BitSet < CounterId > ,
29
29
expressions : IndexVec < ExpressionId , Option < Expression > > ,
30
+ /// Tracks which expressions are known to always have a value of zero.
31
+ /// Only updated during the finalize step.
32
+ zero_expressions : FxIndexSet < ExpressionId > ,
30
33
mappings : Vec < Mapping > ,
31
34
}
32
35
@@ -63,6 +66,7 @@ impl<'tcx> FunctionCoverage<'tcx> {
63
66
is_used,
64
67
counters_seen : BitSet :: new_empty ( num_counters) ,
65
68
expressions : IndexVec :: from_elem_n ( None , num_expressions) ,
69
+ zero_expressions : FxIndexSet :: default ( ) ,
66
70
mappings : Vec :: new ( ) ,
67
71
}
68
72
}
@@ -134,39 +138,44 @@ impl<'tcx> FunctionCoverage<'tcx> {
134
138
}
135
139
136
140
pub ( crate ) fn finalize ( & mut self ) {
137
- self . simplify_expressions ( ) ;
141
+ self . update_zero_expressions ( ) ;
138
142
139
143
// Sort all of the collected mappings into a predictable order.
140
144
// (Mappings have a total order, so an unstable sort should be fine.)
141
145
self . mappings . sort_unstable ( ) ;
142
146
}
143
147
144
- /// Perform some simplifications to make the final coverage mappings
145
- /// slightly smaller.
148
+ /// Identify expressions that will always have a value of zero, and note
149
+ /// their IDs in `zero_expressions`. Mappings that refer to a zero expression
150
+ /// can instead become mappings to a constant zero value.
146
151
///
147
152
/// This method mainly exists to preserve the simplifications that were
148
153
/// already being performed by the Rust-side expression renumbering, so that
149
154
/// the resulting coverage mappings don't get worse.
150
- fn simplify_expressions ( & mut self ) {
155
+ fn update_zero_expressions ( & mut self ) {
151
156
// The set of expressions that either were optimized out entirely, or
152
157
// have zero as both of their operands, and will therefore always have
153
158
// a value of zero. Other expressions that refer to these as operands
154
159
// can have those operands replaced with `CovTerm::Zero`.
155
- let mut zero_expressions = FxIndexSet :: default ( ) ;
160
+ let zero_expressions = & mut self . zero_expressions ;
156
161
157
- // For each expression, perform simplifications based on lower-numbered
158
- // expressions, and then update the set of always-zero expressions if
159
- // necessary.
162
+ // Simplify a copy of each expression based on lower-numbered expressions,
163
+ // and then update the set of always-zero expressions if necessary.
160
164
// (By construction, expressions can only refer to other expressions
161
- // that have lower IDs, so one simplification pass is sufficient.)
162
- for ( id, maybe_expression) in self . expressions . iter_enumerated_mut ( ) {
165
+ // that have lower IDs, so one pass is sufficient.)
166
+ for ( id, maybe_expression) in self . expressions . iter_enumerated ( ) {
163
167
let Some ( expression) = maybe_expression else {
164
168
// If an expression is missing, it must have been optimized away,
165
169
// so any operand that refers to it can be replaced with zero.
166
170
zero_expressions. insert ( id) ;
167
171
continue ;
168
172
} ;
169
173
174
+ // We don't need to simplify the actual expression data in the
175
+ // expressions list; we can just simplify a temporary copy and then
176
+ // use that to update the set of always-zero expressions.
177
+ let mut expression = expression. clone ( ) ;
178
+
170
179
// If an operand refers to an expression that is always zero, then
171
180
// that operand can be replaced with `CovTerm::Zero`.
172
181
let maybe_set_operand_to_zero = |operand : & mut CovTerm | match & * operand {
@@ -207,6 +216,11 @@ impl<'tcx> FunctionCoverage<'tcx> {
207
216
// thing on the Rust side unless we're confident we can do much better.
208
217
// (See `CounterExpressionsMinimizer` in `CoverageMappingWriter.cpp`.)
209
218
219
+ let counter_from_operand = |operand : CovTerm | match operand {
220
+ CovTerm :: Expression ( id) if self . zero_expressions . contains ( & id) => Counter :: ZERO ,
221
+ _ => Counter :: from_term ( operand) ,
222
+ } ;
223
+
210
224
self . expressions
211
225
. iter ( )
212
226
. map ( |expression| match expression {
@@ -220,12 +234,12 @@ impl<'tcx> FunctionCoverage<'tcx> {
220
234
& Some ( Expression { lhs, op, rhs, .. } ) => {
221
235
// Convert the operands and operator as normal.
222
236
CounterExpression :: new (
223
- Counter :: from_term ( lhs) ,
237
+ counter_from_operand ( lhs) ,
224
238
match op {
225
239
Op :: Add => ExprKind :: Add ,
226
240
Op :: Subtract => ExprKind :: Subtract ,
227
241
} ,
228
- Counter :: from_term ( rhs) ,
242
+ counter_from_operand ( rhs) ,
229
243
)
230
244
}
231
245
} )
0 commit comments