Skip to content

Commit e2a808e

Browse files
committed
!! (WIP) Store a function's mappings in a single list
1 parent f4f9497 commit e2a808e

File tree

2 files changed

+42
-64
lines changed

2 files changed

+42
-64
lines changed

compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs

Lines changed: 40 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use crate::coverageinfo::ffi::{Counter, CounterExpression, ExprKind};
22

33
use rustc_data_structures::fx::FxIndexSet;
4+
use rustc_index::bit_set::BitSet;
45
use rustc_index::IndexVec;
56
use rustc_middle::mir::coverage::{CodeRegion, CounterId, CovTerm, ExpressionId, Op};
67
use rustc_middle::ty::Instance;
@@ -11,7 +12,6 @@ pub struct Expression {
1112
lhs: CovTerm,
1213
op: Op,
1314
rhs: CovTerm,
14-
code_regions: Vec<CodeRegion>,
1515
}
1616

1717
/// Collects all of the coverage regions associated with (a) injected counters, (b) counter
@@ -30,9 +30,10 @@ pub struct FunctionCoverage<'tcx> {
3030
instance: Instance<'tcx>,
3131
source_hash: u64,
3232
is_used: bool,
33-
counters: IndexVec<CounterId, Option<Vec<CodeRegion>>>,
33+
34+
counters_seen: BitSet<CounterId>,
3435
expressions: IndexVec<ExpressionId, Option<Expression>>,
35-
unreachable_regions: Vec<CodeRegion>,
36+
mappings: Vec<(CovTerm, CodeRegion)>,
3637
}
3738

3839
impl<'tcx> FunctionCoverage<'tcx> {
@@ -56,9 +57,9 @@ impl<'tcx> FunctionCoverage<'tcx> {
5657
instance,
5758
source_hash: 0, // will be set with the first `add_counter()`
5859
is_used,
59-
counters: IndexVec::from_elem_n(None, coverageinfo.num_counters as usize),
60+
counters_seen: BitSet::new_empty(coverageinfo.num_counters as usize),
6061
expressions: IndexVec::from_elem_n(None, coverageinfo.num_expressions as usize),
61-
unreachable_regions: Vec::new(),
62+
mappings: Vec::new(),
6263
}
6364
}
6465

@@ -80,20 +81,10 @@ impl<'tcx> FunctionCoverage<'tcx> {
8081
/// Adds code regions to be counted by an injected counter intrinsic.
8182
#[instrument(level = "debug", skip(self))]
8283
pub(crate) fn add_counter(&mut self, id: CounterId, code_regions: &[CodeRegion]) {
83-
if code_regions.is_empty() {
84+
if !self.counters_seen.insert(id) {
8485
return;
8586
}
86-
87-
let slot = &mut self.counters[id];
88-
match slot {
89-
None => *slot = Some(code_regions.to_owned()),
90-
// If this counter ID slot has already been filled, it should
91-
// contain identical information.
92-
Some(ref previous_regions) => assert_eq!(
93-
previous_regions, code_regions,
94-
"add_counter: code regions for id changed"
95-
),
96-
}
87+
self.add_mappings(CovTerm::Counter(id), code_regions);
9788
}
9889

9990
/// Adds information about a coverage expression, along with zero or more
@@ -120,24 +111,45 @@ impl<'tcx> FunctionCoverage<'tcx> {
120111
self,
121112
);
122113

123-
let expression = Expression { lhs, op, rhs, code_regions: code_regions.to_owned() };
114+
let expression = Expression { lhs, op, rhs };
124115
let slot = &mut self.expressions[expression_id];
125116
match slot {
126117
None => *slot = Some(expression),
127118
// If this expression ID slot has already been filled, it should
128119
// contain identical information.
129-
Some(ref previous_expression) => assert_eq!(
130-
previous_expression, &expression,
131-
"add_counter_expression: expression for id changed"
132-
),
120+
Some(ref previous_expression) => {
121+
assert_eq!(
122+
previous_expression, &expression,
123+
"add_counter_expression: expression for id changed"
124+
);
125+
return;
126+
}
133127
}
128+
129+
self.add_mappings(CovTerm::Expression(expression_id), code_regions);
134130
}
135131

136132
/// Adds regions that will be marked as "unreachable", with a constant "zero counter".
137133
#[instrument(level = "debug", skip(self))]
138134
pub(crate) fn add_unreachable_regions(&mut self, code_regions: &[CodeRegion]) {
139135
assert!(!code_regions.is_empty(), "unreachable regions always have code regions");
140-
self.unreachable_regions.extend_from_slice(code_regions);
136+
self.add_mappings(CovTerm::Zero, code_regions);
137+
}
138+
139+
fn add_mappings(&mut self, kind: CovTerm, code_regions: &[CodeRegion]) {
140+
self.mappings
141+
.extend(code_regions.iter().cloned().map(move |code_region| (kind, code_region)));
142+
}
143+
144+
pub(crate) fn finalize(&mut self) {
145+
self.simplify_expressions();
146+
147+
let mapping_kind_sort_key = |mapping_kind: &CovTerm| match mapping_kind {
148+
CovTerm::Counter(_) => 0,
149+
CovTerm::Expression(_) => 1,
150+
CovTerm::Zero => u8::MAX,
151+
};
152+
self.mappings.sort_by_key(|(mapping_kind, _)| mapping_kind_sort_key(mapping_kind));
141153
}
142154

143155
/// Perform some simplifications to make the final coverage mappings
@@ -146,7 +158,7 @@ impl<'tcx> FunctionCoverage<'tcx> {
146158
/// This method mainly exists to preserve the simplifications that were
147159
/// already being performed by the Rust-side expression renumbering, so that
148160
/// the resulting coverage mappings don't get worse.
149-
pub(crate) fn simplify_expressions(&mut self) {
161+
fn simplify_expressions(&mut self) {
150162
// The set of expressions that either were optimized out entirely, or
151163
// have zero as both of their operands, and will therefore always have
152164
// a value of zero. Other expressions that refer to these as operands
@@ -216,28 +228,14 @@ impl<'tcx> FunctionCoverage<'tcx> {
216228
// the two vectors should correspond 1:1.
217229
assert_eq!(self.expressions.len(), counter_expressions.len());
218230

219-
let counter_regions = self.counter_regions();
220-
let expression_regions = self.expression_regions();
221-
let unreachable_regions = self.unreachable_regions();
231+
let counter_regions = self.mappings.iter().map(|(mapping_kind, code_region)| {
232+
let counter = Counter::from_term(*mapping_kind);
233+
(counter, code_region)
234+
});
222235

223-
let counter_regions =
224-
counter_regions.chain(expression_regions.into_iter().chain(unreachable_regions));
225236
(counter_expressions, counter_regions)
226237
}
227238

228-
fn counter_regions(&self) -> impl Iterator<Item = (Counter, &CodeRegion)> {
229-
self.counters
230-
.iter_enumerated()
231-
// Filter out counter IDs that we never saw during MIR traversal.
232-
// This can happen if a counter was optimized out by MIR transforms
233-
// (and replaced with `CoverageKind::Unreachable` instead).
234-
.filter_map(|(id, maybe_code_regions)| Some((id, maybe_code_regions.as_ref()?)))
235-
.flat_map(|(id, code_regions)| {
236-
let counter = Counter::counter_value_reference(id);
237-
code_regions.iter().map(move |region| (counter, region))
238-
})
239-
}
240-
241239
/// Convert this function's coverage expression data into a form that can be
242240
/// passed through FFI to LLVM.
243241
fn counter_expressions(&self) -> Vec<CounterExpression> {
@@ -267,25 +265,4 @@ impl<'tcx> FunctionCoverage<'tcx> {
267265
})
268266
.collect::<Vec<_>>()
269267
}
270-
271-
fn expression_regions(&self) -> Vec<(Counter, &CodeRegion)> {
272-
// Find all of the expression IDs that weren't optimized out AND have
273-
// one or more attached code regions, and return the corresponding
274-
// mappings as counter/region pairs.
275-
self.expressions
276-
.iter_enumerated()
277-
.filter_map(|(id, maybe_expression)| {
278-
let code_regions = &maybe_expression.as_ref()?.code_regions;
279-
Some((id, code_regions))
280-
})
281-
.flat_map(|(id, code_regions)| {
282-
let counter = Counter::expression(id);
283-
code_regions.iter().map(move |code_region| (counter, code_region))
284-
})
285-
.collect::<Vec<_>>()
286-
}
287-
288-
fn unreachable_regions(&self) -> impl Iterator<Item = (Counter, &CodeRegion)> {
289-
self.unreachable_regions.iter().map(|region| (Counter::ZERO, region))
290-
}
291268
}

compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,8 @@ pub fn finalize(cx: &CodegenCx<'_, '_>) {
6161
let mut function_data = Vec::new();
6262
for (instance, mut function_coverage) in function_coverage_map {
6363
debug!("Generate function coverage for {}, {:?}", cx.codegen_unit.name(), instance);
64-
function_coverage.simplify_expressions();
64+
function_coverage.finalize();
65+
let function_coverage = function_coverage;
6566

6667
let mangled_function_name = tcx.symbol_name(instance).name;
6768
let source_hash = function_coverage.source_hash();

0 commit comments

Comments
 (0)