Skip to content

Commit 34b9792

Browse files
committed
coverage: Make expression simplification non-destructive
1 parent 9684257 commit 34b9792

File tree

1 file changed

+26
-12
lines changed
  • compiler/rustc_codegen_llvm/src/coverageinfo

1 file changed

+26
-12
lines changed

compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ pub struct FunctionCoverage<'tcx> {
2727
/// that might be introduced by MIR inlining.
2828
counters_seen: BitSet<CounterId>,
2929
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>,
3033
mappings: Vec<Mapping>,
3134
}
3235

@@ -63,6 +66,7 @@ impl<'tcx> FunctionCoverage<'tcx> {
6366
is_used,
6467
counters_seen: BitSet::new_empty(num_counters),
6568
expressions: IndexVec::from_elem_n(None, num_expressions),
69+
zero_expressions: FxIndexSet::default(),
6670
mappings: Vec::new(),
6771
}
6872
}
@@ -134,39 +138,44 @@ impl<'tcx> FunctionCoverage<'tcx> {
134138
}
135139

136140
pub(crate) fn finalize(&mut self) {
137-
self.simplify_expressions();
141+
self.update_zero_expressions();
138142

139143
// Sort all of the collected mappings into a predictable order.
140144
// (Mappings have a total order, so an unstable sort should be fine.)
141145
self.mappings.sort_unstable();
142146
}
143147

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.
146151
///
147152
/// This method mainly exists to preserve the simplifications that were
148153
/// already being performed by the Rust-side expression renumbering, so that
149154
/// the resulting coverage mappings don't get worse.
150-
fn simplify_expressions(&mut self) {
155+
fn update_zero_expressions(&mut self) {
151156
// The set of expressions that either were optimized out entirely, or
152157
// have zero as both of their operands, and will therefore always have
153158
// a value of zero. Other expressions that refer to these as operands
154159
// can have those operands replaced with `CovTerm::Zero`.
155-
let mut zero_expressions = FxIndexSet::default();
160+
let zero_expressions = &mut self.zero_expressions;
156161

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.
160164
// (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() {
163167
let Some(expression) = maybe_expression else {
164168
// If an expression is missing, it must have been optimized away,
165169
// so any operand that refers to it can be replaced with zero.
166170
zero_expressions.insert(id);
167171
continue;
168172
};
169173

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+
170179
// If an operand refers to an expression that is always zero, then
171180
// that operand can be replaced with `CovTerm::Zero`.
172181
let maybe_set_operand_to_zero = |operand: &mut CovTerm| match &*operand {
@@ -207,6 +216,11 @@ impl<'tcx> FunctionCoverage<'tcx> {
207216
// thing on the Rust side unless we're confident we can do much better.
208217
// (See `CounterExpressionsMinimizer` in `CoverageMappingWriter.cpp`.)
209218

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+
210224
self.expressions
211225
.iter()
212226
.map(|expression| match expression {
@@ -220,12 +234,12 @@ impl<'tcx> FunctionCoverage<'tcx> {
220234
&Some(Expression { lhs, op, rhs, .. }) => {
221235
// Convert the operands and operator as normal.
222236
CounterExpression::new(
223-
Counter::from_term(lhs),
237+
counter_from_operand(lhs),
224238
match op {
225239
Op::Add => ExprKind::Add,
226240
Op::Subtract => ExprKind::Subtract,
227241
},
228-
Counter::from_term(rhs),
242+
counter_from_operand(rhs),
229243
)
230244
}
231245
})

0 commit comments

Comments
 (0)