Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 18a0b36

Browse files
authoredMay 20, 2024··
Unrolled build for rust-lang#125106
Rollup merge of rust-lang#125106 - Zalathar:expressions, r=davidtwco coverage: Memoize and simplify counter expressions When creating coverage counter expressions as part of coverage instrumentation, we often end up creating obviously-redundant expressions like `c1 + (c0 - c1)`, which is equivalent to just `c0`. To avoid doing so, this PR checks when we would create an expression matching one of 5 patterns, and uses the simplified form instead: - `(a - b) + b` → `a`. - `(a + b) - b` → `a`. - `(a + b) - a` → `b`. - `a + (b - a)` → `b`. - `a - (a - b)` → `b`. Of all the different ways to combine 3 operands and 2 operators, these are the patterns that allow simplification. (Some of those patterns currently don't occur in practice, but are included anyway for completeness, to avoid having to add them later as branch coverage and MC/DC coverage support expands.) --- This PR also adds memoization for newly-created (or newly-simplified) counter expressions, to avoid creating duplicates. This currently makes no difference to the final mappings, but is expected to be useful for MC/DC coverage of match expressions, as proposed by rust-lang#124278 (comment).
2 parents 474bee7 + d01df6f commit 18a0b36

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+890
-1322
lines changed
 

‎compiler/rustc_middle/src/mir/coverage.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -181,8 +181,8 @@ impl Debug for CodeRegion {
181181
}
182182
}
183183

184-
#[derive(Copy, Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)]
185-
#[derive(TypeFoldable, TypeVisitable)]
184+
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable)]
185+
#[derive(TyEncodable, TyDecodable, TypeFoldable, TypeVisitable)]
186186
pub enum Op {
187187
Subtract,
188188
Add,

‎compiler/rustc_mir_transform/src/coverage/counters.rs

+80-5
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph, TraverseCoverage
1111

1212
/// The coverage counter or counter expression associated with a particular
1313
/// BCB node or BCB edge.
14-
#[derive(Clone, Copy)]
14+
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
1515
pub(super) enum BcbCounter {
1616
Counter { id: CounterId },
1717
Expression { id: ExpressionId },
@@ -35,6 +35,13 @@ impl Debug for BcbCounter {
3535
}
3636
}
3737

38+
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
39+
struct BcbExpression {
40+
lhs: BcbCounter,
41+
op: Op,
42+
rhs: BcbCounter,
43+
}
44+
3845
#[derive(Debug)]
3946
pub(super) enum CounterIncrementSite {
4047
Node { bcb: BasicCoverageBlock },
@@ -56,9 +63,13 @@ pub(super) struct CoverageCounters {
5663
/// We currently don't iterate over this map, but if we do in the future,
5764
/// switch it back to `FxIndexMap` to avoid query stability hazards.
5865
bcb_edge_counters: FxHashMap<(BasicCoverageBlock, BasicCoverageBlock), BcbCounter>,
66+
5967
/// Table of expression data, associating each expression ID with its
6068
/// corresponding operator (+ or -) and its LHS/RHS operands.
61-
expressions: IndexVec<ExpressionId, Expression>,
69+
expressions: IndexVec<ExpressionId, BcbExpression>,
70+
/// Remember expressions that have already been created (or simplified),
71+
/// so that we don't create unnecessary duplicates.
72+
expressions_memo: FxHashMap<BcbExpression, BcbCounter>,
6273
}
6374

6475
impl CoverageCounters {
@@ -76,6 +87,7 @@ impl CoverageCounters {
7687
bcb_counters: IndexVec::from_elem_n(None, num_bcbs),
7788
bcb_edge_counters: FxHashMap::default(),
7889
expressions: IndexVec::new(),
90+
expressions_memo: FxHashMap::default(),
7991
};
8092

8193
MakeBcbCounters::new(&mut this, basic_coverage_blocks)
@@ -90,8 +102,57 @@ impl CoverageCounters {
90102
}
91103

92104
fn make_expression(&mut self, lhs: BcbCounter, op: Op, rhs: BcbCounter) -> BcbCounter {
93-
let expression = Expression { lhs: lhs.as_term(), op, rhs: rhs.as_term() };
94-
let id = self.expressions.push(expression);
105+
let new_expr = BcbExpression { lhs, op, rhs };
106+
*self
107+
.expressions_memo
108+
.entry(new_expr)
109+
.or_insert_with(|| Self::make_expression_inner(&mut self.expressions, new_expr))
110+
}
111+
112+
/// This is an associated function so that we can call it while borrowing
113+
/// `&mut self.expressions_memo`.
114+
fn make_expression_inner(
115+
expressions: &mut IndexVec<ExpressionId, BcbExpression>,
116+
new_expr: BcbExpression,
117+
) -> BcbCounter {
118+
// Simplify expressions using basic algebra.
119+
//
120+
// Some of these cases might not actually occur in practice, depending
121+
// on the details of how the instrumentor builds expressions.
122+
let BcbExpression { lhs, op, rhs } = new_expr;
123+
124+
if let BcbCounter::Expression { id } = lhs {
125+
let lhs_expr = &expressions[id];
126+
127+
// Simplify `(a - b) + b` to `a`.
128+
if lhs_expr.op == Op::Subtract && op == Op::Add && lhs_expr.rhs == rhs {
129+
return lhs_expr.lhs;
130+
}
131+
// Simplify `(a + b) - b` to `a`.
132+
if lhs_expr.op == Op::Add && op == Op::Subtract && lhs_expr.rhs == rhs {
133+
return lhs_expr.lhs;
134+
}
135+
// Simplify `(a + b) - a` to `b`.
136+
if lhs_expr.op == Op::Add && op == Op::Subtract && lhs_expr.lhs == rhs {
137+
return lhs_expr.rhs;
138+
}
139+
}
140+
141+
if let BcbCounter::Expression { id } = rhs {
142+
let rhs_expr = &expressions[id];
143+
144+
// Simplify `a + (b - a)` to `b`.
145+
if op == Op::Add && rhs_expr.op == Op::Subtract && lhs == rhs_expr.rhs {
146+
return rhs_expr.lhs;
147+
}
148+
// Simplify `a - (a - b)` to `b`.
149+
if op == Op::Subtract && rhs_expr.op == Op::Subtract && lhs == rhs_expr.lhs {
150+
return rhs_expr.rhs;
151+
}
152+
}
153+
154+
// Simplification failed, so actually create the new expression.
155+
let id = expressions.push(new_expr);
95156
BcbCounter::Expression { id }
96157
}
97158

@@ -166,7 +227,21 @@ impl CoverageCounters {
166227
}
167228

168229
pub(super) fn into_expressions(self) -> IndexVec<ExpressionId, Expression> {
169-
self.expressions
230+
let old_len = self.expressions.len();
231+
let expressions = self
232+
.expressions
233+
.into_iter()
234+
.map(|BcbExpression { lhs, op, rhs }| Expression {
235+
lhs: lhs.as_term(),
236+
op,
237+
rhs: rhs.as_term(),
238+
})
239+
.collect::<IndexVec<ExpressionId, _>>();
240+
241+
// Expression IDs are indexes into this vector, so make sure we didn't
242+
// accidentally invalidate them by changing its length.
243+
assert_eq!(old_len, expressions.len());
244+
expressions
170245
}
171246
}
172247

0 commit comments

Comments
 (0)
Please sign in to comment.