Skip to content

Commit f342569

Browse files
committed
Generalize Coverage Expression simplification
This extends the current simplification code to not only replace operands by `Zero`, but also to remove trivial `Counter + Zero` expressions and replace those with just `Counter`.
1 parent 8d4ba90 commit f342569

File tree

6 files changed

+387
-433
lines changed

6 files changed

+387
-433
lines changed

compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs

+38-26
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::coverageinfo::ffi::{Counter, CounterExpression, ExprKind};
22

3-
use rustc_data_structures::fx::FxIndexSet;
3+
use rustc_data_structures::fx::FxHashMap;
44
use rustc_index::IndexVec;
55
use rustc_middle::mir::coverage::{CodeRegion, CounterId, ExpressionId, Op, Operand};
66
use rustc_middle::ty::Instance;
@@ -153,37 +153,38 @@ impl<'tcx> FunctionCoverage<'tcx> {
153153
/// Perform some simplifications to make the final coverage mappings
154154
/// slightly smaller.
155155
pub(crate) fn simplify_expressions(&mut self) {
156-
// The set of expressions that either were optimized out entirely, or
157-
// have zero as both of their operands, and will therefore always have
158-
// a value of zero. Other expressions that refer to these as operands
159-
// can have those operands replaced with `Operand::Zero`.
160-
let mut zero_expressions = FxIndexSet::default();
161-
162-
// If an operand refers to an expression that is always zero, then
163-
// that operand can be replaced with `Operand::Zero`.
164-
let maybe_set_operand_to_zero =
165-
|zero_expressions: &FxIndexSet<ExpressionId>, operand: &mut Operand| match &*operand {
166-
Operand::Expression(id) if zero_expressions.contains(id) => {
167-
*operand = Operand::Zero;
156+
// The set of expressions that were simplified to either `Zero` or a
157+
// `Counter`. Other expressions that refer to these as operands
158+
// can then also be simplified.
159+
let mut simplified_expressions = FxHashMap::default();
160+
type SimplifiedExpressions = FxHashMap<ExpressionId, Operand>;
161+
162+
// If an operand refers to an expression that has been simplified, then
163+
// replace that operand with the simplified version.
164+
let maybe_simplify_operand = |simplified_expressions: &SimplifiedExpressions,
165+
operand: &mut Operand| {
166+
if let Operand::Expression(id) = &*operand {
167+
if let Some(simplified) = simplified_expressions.get(id) {
168+
*operand = *simplified;
168169
}
169-
_ => (),
170-
};
170+
}
171+
};
171172

172173
// For each expression, perform simplifications based on lower-numbered
173-
// expressions, and then update the set of always-zero expressions if
174+
// expressions, and then update the map of simplified expressions if
174175
// necessary.
175176
// (By construction, expressions can only refer to other expressions
176177
// that have lower IDs, so one simplification pass is sufficient.)
177178
for (id, maybe_expression) in self.expressions.iter_enumerated_mut() {
178179
let Some(expression) = maybe_expression else {
179180
// If an expression is missing, it must have been optimized away,
180181
// so any operand that refers to it can be replaced with zero.
181-
zero_expressions.insert(id);
182+
simplified_expressions.insert(id, Operand::Zero);
182183
continue;
183184
};
184185

185-
maybe_set_operand_to_zero(&zero_expressions, &mut expression.lhs);
186-
maybe_set_operand_to_zero(&zero_expressions, &mut expression.rhs);
186+
maybe_simplify_operand(&simplified_expressions, &mut expression.lhs);
187+
maybe_simplify_operand(&simplified_expressions, &mut expression.rhs);
187188

188189
// Coverage counter values cannot be negative, so if an expression
189190
// involves subtraction from zero, assume that its RHS must also be zero.
@@ -192,18 +193,29 @@ impl<'tcx> FunctionCoverage<'tcx> {
192193
expression.rhs = Operand::Zero;
193194
}
194195

195-
// After the above simplifications, if both operands are zero, then
196-
// we know that this expression is always zero too.
197-
if let Expression { lhs: Operand::Zero, rhs: Operand::Zero, .. } = expression {
198-
zero_expressions.insert(id);
196+
// After the above simplifications, if the right hand operand is zero,
197+
// we can replace the expression by its left hand side.
198+
if let Expression { lhs, rhs: Operand::Zero, .. } = expression {
199+
simplified_expressions.insert(id, *lhs);
199200
}
200201
}
201202

202203
// Do the same simplification for each side of a branch region.
203204
for branch in &mut self.branches {
204-
maybe_set_operand_to_zero(&zero_expressions, &mut branch.true_);
205-
maybe_set_operand_to_zero(&zero_expressions, &mut branch.false_);
205+
maybe_simplify_operand(&simplified_expressions, &mut branch.true_);
206+
maybe_simplify_operand(&simplified_expressions, &mut branch.false_);
207+
}
208+
}
209+
210+
/// This will further simplify any `Operand::Expression`,
211+
/// "inlining" the left hand side operand if the right hand side is `Zero`.
212+
fn simplified_expression(&self, id: ExpressionId) -> Counter {
213+
if let Some(expr) = &self.expressions[id] {
214+
if expr.rhs == Operand::Zero {
215+
return Counter::from_operand(expr.lhs);
216+
}
206217
}
218+
Counter::expression(id)
207219
}
208220

209221
/// Return the source hash, generated from the HIR node structure, and used to indicate whether
@@ -246,7 +258,7 @@ impl<'tcx> FunctionCoverage<'tcx> {
246258
self.expressions.iter_enumerated().filter_map(|(id, expression)| {
247259
let region = expression.as_ref()?.region.as_ref()?;
248260
Some(CoverageCounterAndRegion {
249-
kind: CoverageCounterKind::Counter(Counter::expression(id)),
261+
kind: CoverageCounterKind::Counter(self.simplified_expression(id)),
250262
region,
251263
})
252264
});

tests/coverage-map/status-quo/async2.cov-map

+15-21
Original file line numberDiff line numberDiff line change
@@ -40,15 +40,13 @@ Number of file 0 mappings: 1
4040
- Code(Counter(0)) at (prev + 31, 36) to (start + 2, 2)
4141

4242
Function name: async2::executor::block_on::<async2::async_func::{closure#0}>
43-
Raw bytes (51): 0x[01, 01, 05, 0b, 05, 01, 05, 01, 05, 02, 00, 02, 00, 07, 01, 33, 05, 0a, 36, 20, 05, 02, 0d, 14, 00, 24, 02, 00, 20, 00, 23, 0b, 00, 27, 00, 49, 0f, 01, 17, 00, 1a, 05, 01, 0e, 00, 0f, 13, 02, 05, 00, 06]
43+
Raw bytes (47): 0x[01, 01, 03, 0b, 05, 01, 05, 01, 05, 07, 01, 33, 05, 0a, 36, 20, 05, 02, 0d, 14, 00, 24, 02, 00, 20, 00, 23, 0b, 00, 27, 00, 49, 02, 01, 17, 00, 1a, 05, 01, 0e, 00, 0f, 02, 02, 05, 00, 06]
4444
Number of files: 1
4545
- file 0 => global file 1
46-
Number of expressions: 5
46+
Number of expressions: 3
4747
- expression 0 operands: lhs = Expression(2, Add), rhs = Counter(1)
4848
- expression 1 operands: lhs = Counter(0), rhs = Counter(1)
4949
- expression 2 operands: lhs = Counter(0), rhs = Counter(1)
50-
- expression 3 operands: lhs = Expression(0, Sub), rhs = Zero
51-
- expression 4 operands: lhs = Expression(0, Sub), rhs = Zero
5250
Number of file 0 mappings: 7
5351
- Code(Counter(0)) at (prev + 51, 5) to (start + 10, 54)
5452
- Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 13, 20) to (start + 0, 36)
@@ -57,22 +55,20 @@ Number of file 0 mappings: 7
5755
= ((c0 + c1) - c1)
5856
- Code(Expression(2, Add)) at (prev + 0, 39) to (start + 0, 73)
5957
= (c0 + c1)
60-
- Code(Expression(3, Add)) at (prev + 1, 23) to (start + 0, 26)
61-
= (((c0 + c1) - c1) + Zero)
58+
- Code(Expression(0, Sub)) at (prev + 1, 23) to (start + 0, 26)
59+
= ((c0 + c1) - c1)
6260
- Code(Counter(1)) at (prev + 1, 14) to (start + 0, 15)
63-
- Code(Expression(4, Add)) at (prev + 2, 5) to (start + 0, 6)
64-
= (((c0 + c1) - c1) + Zero)
61+
- Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 0, 6)
62+
= ((c0 + c1) - c1)
6563

6664
Function name: async2::executor::block_on::<async2::async_func_just_println::{closure#0}>
67-
Raw bytes (51): 0x[01, 01, 05, 0b, 05, 01, 05, 01, 05, 02, 00, 02, 00, 07, 01, 33, 05, 0a, 36, 20, 05, 02, 0d, 14, 00, 24, 02, 00, 20, 00, 23, 0b, 00, 27, 00, 49, 0f, 01, 17, 00, 1a, 05, 01, 0e, 00, 0f, 13, 02, 05, 00, 06]
65+
Raw bytes (47): 0x[01, 01, 03, 0b, 05, 01, 05, 01, 05, 07, 01, 33, 05, 0a, 36, 20, 05, 02, 0d, 14, 00, 24, 02, 00, 20, 00, 23, 0b, 00, 27, 00, 49, 02, 01, 17, 00, 1a, 05, 01, 0e, 00, 0f, 02, 02, 05, 00, 06]
6866
Number of files: 1
6967
- file 0 => global file 1
70-
Number of expressions: 5
68+
Number of expressions: 3
7169
- expression 0 operands: lhs = Expression(2, Add), rhs = Counter(1)
7270
- expression 1 operands: lhs = Counter(0), rhs = Counter(1)
7371
- expression 2 operands: lhs = Counter(0), rhs = Counter(1)
74-
- expression 3 operands: lhs = Expression(0, Sub), rhs = Zero
75-
- expression 4 operands: lhs = Expression(0, Sub), rhs = Zero
7672
Number of file 0 mappings: 7
7773
- Code(Counter(0)) at (prev + 51, 5) to (start + 10, 54)
7874
- Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 13, 20) to (start + 0, 36)
@@ -81,11 +77,11 @@ Number of file 0 mappings: 7
8177
= ((c0 + c1) - c1)
8278
- Code(Expression(2, Add)) at (prev + 0, 39) to (start + 0, 73)
8379
= (c0 + c1)
84-
- Code(Expression(3, Add)) at (prev + 1, 23) to (start + 0, 26)
85-
= (((c0 + c1) - c1) + Zero)
80+
- Code(Expression(0, Sub)) at (prev + 1, 23) to (start + 0, 26)
81+
= ((c0 + c1) - c1)
8682
- Code(Counter(1)) at (prev + 1, 14) to (start + 0, 15)
87-
- Code(Expression(4, Add)) at (prev + 2, 5) to (start + 0, 6)
88-
= (((c0 + c1) - c1) + Zero)
83+
- Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 0, 6)
84+
= ((c0 + c1) - c1)
8985

9086
Function name: async2::executor::block_on::VTABLE::{closure#0}
9187
Raw bytes (9): 0x[01, 01, 00, 01, 01, 37, 11, 00, 33]
@@ -128,16 +124,14 @@ Number of file 0 mappings: 1
128124
- Code(Counter(0)) at (prev + 35, 1) to (start + 7, 2)
129125

130126
Function name: async2::non_async_func
131-
Raw bytes (33): 0x[01, 01, 01, 05, 00, 05, 01, 09, 01, 03, 09, 20, 05, 00, 03, 08, 00, 09, 05, 00, 0a, 02, 06, 00, 02, 06, 00, 07, 03, 01, 01, 00, 02]
127+
Raw bytes (31): 0x[01, 01, 00, 05, 01, 09, 01, 03, 09, 20, 05, 00, 03, 08, 00, 09, 05, 00, 0a, 02, 06, 00, 02, 06, 00, 07, 05, 01, 01, 00, 02]
132128
Number of files: 1
133129
- file 0 => global file 1
134-
Number of expressions: 1
135-
- expression 0 operands: lhs = Counter(1), rhs = Zero
130+
Number of expressions: 0
136131
Number of file 0 mappings: 5
137132
- Code(Counter(0)) at (prev + 9, 1) to (start + 3, 9)
138133
- Branch { true: Counter(1), false: Zero } at (prev + 3, 8) to (start + 0, 9)
139134
- Code(Counter(1)) at (prev + 0, 10) to (start + 2, 6)
140135
- Code(Zero) at (prev + 2, 6) to (start + 0, 7)
141-
- Code(Expression(0, Add)) at (prev + 1, 1) to (start + 0, 2)
142-
= (c1 + Zero)
136+
- Code(Counter(1)) at (prev + 1, 1) to (start + 0, 2)
143137

0 commit comments

Comments
 (0)