Skip to content

Commit c6a7d07

Browse files
committed
coverage: Simplify the injection of coverage statements
1 parent 0039d73 commit c6a7d07

File tree

3 files changed

+85
-143
lines changed

3 files changed

+85
-143
lines changed

Diff for: compiler/rustc_mir_transform/src/coverage/counters.rs

+11-13
Original file line numberDiff line numberDiff line change
@@ -169,22 +169,20 @@ impl CoverageCounters {
169169
self.bcb_counters[bcb].as_ref()
170170
}
171171

172-
pub(super) fn take_bcb_counter(&mut self, bcb: BasicCoverageBlock) -> Option<BcbCounter> {
173-
self.bcb_counters[bcb].take()
174-
}
175-
176-
pub(super) fn drain_bcb_counters(
177-
&mut self,
178-
) -> impl Iterator<Item = (BasicCoverageBlock, BcbCounter)> + '_ {
172+
pub(super) fn bcb_node_counters(
173+
&self,
174+
) -> impl Iterator<Item = (BasicCoverageBlock, &BcbCounter)> {
179175
self.bcb_counters
180-
.iter_enumerated_mut()
181-
.filter_map(|(bcb, counter)| Some((bcb, counter.take()?)))
176+
.iter_enumerated()
177+
.filter_map(|(bcb, counter_kind)| Some((bcb, counter_kind.as_ref()?)))
182178
}
183179

184-
pub(super) fn drain_bcb_edge_counters(
185-
&mut self,
186-
) -> impl Iterator<Item = ((BasicCoverageBlock, BasicCoverageBlock), BcbCounter)> + '_ {
187-
self.bcb_edge_counters.drain()
180+
pub(super) fn bcb_edge_counters(
181+
&self,
182+
) -> impl Iterator<Item = ((BasicCoverageBlock, BasicCoverageBlock), &BcbCounter)> {
183+
self.bcb_edge_counters
184+
.iter()
185+
.map(|(&(from_bcb, to_bcb), counter_kind)| ((from_bcb, to_bcb), counter_kind))
188186
}
189187

190188
pub(super) fn take_expressions(&mut self) -> IndexVec<ExpressionId, Expression> {

Diff for: compiler/rustc_mir_transform/src/coverage/mod.rs

+72-123
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ mod spans;
88
mod tests;
99

1010
use self::counters::{BcbCounter, CoverageCounters};
11-
use self::graph::{BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph};
11+
use self::graph::CoverageGraph;
1212
use self::spans::CoverageSpans;
1313

1414
use crate::MirPass;
@@ -104,7 +104,6 @@ struct Instrumentor<'a, 'tcx> {
104104
function_source_hash: u64,
105105
basic_coverage_blocks: CoverageGraph,
106106
coverage_counters: CoverageCounters,
107-
mappings: Vec<Mapping>,
108107
}
109108

110109
impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
@@ -145,7 +144,6 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
145144
function_source_hash,
146145
basic_coverage_blocks,
147146
coverage_counters,
148-
mappings: Vec::new(),
149147
}
150148
}
151149

@@ -168,145 +166,96 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
168166
// and all `Expression` dependencies (operands) are also generated, for any other
169167
// `BasicCoverageBlock`s not already associated with a coverage span.
170168
let bcb_has_coverage_spans = |bcb| coverage_spans.bcb_has_coverage_spans(bcb);
171-
let result = self
172-
.coverage_counters
173-
.make_bcb_counters(&mut self.basic_coverage_blocks, bcb_has_coverage_spans);
174-
175-
if let Ok(()) = result {
176-
////////////////////////////////////////////////////
177-
// Remove the counter or edge counter from of each coverage cpan's associated
178-
// `BasicCoverageBlock`, and inject a `Coverage` statement into the MIR.
179-
//
180-
// `Coverage` statements injected from coverage spans will include the code regions
181-
// (source code start and end positions) to be counted by the associated counter.
182-
//
183-
// These coverage-span-associated counters are removed from their associated
184-
// `BasicCoverageBlock`s so that the only remaining counters in the `CoverageGraph`
185-
// are indirect counters (to be injected next, without associated code regions).
186-
self.inject_coverage_span_counters(&coverage_spans);
187-
188-
////////////////////////////////////////////////////
189-
// For any remaining `BasicCoverageBlock` counters (that were not associated with
190-
// any coverage span), inject `Coverage` statements (_without_ code region spans)
191-
// to ensure `BasicCoverageBlock` counters that other `Expression`s may depend on
192-
// are in fact counted, even though they don't directly contribute to counting
193-
// their own independent code region's coverage.
194-
self.inject_indirect_counters();
195-
};
169+
self.coverage_counters
170+
.make_bcb_counters(&mut self.basic_coverage_blocks, bcb_has_coverage_spans)
171+
.unwrap_or_else(|e| {
172+
bug!("Error processing: {:?}: {:?}", self.mir_body.source.def_id(), e.message)
173+
});
196174

197-
if let Err(e) = result {
198-
bug!("Error processing: {:?}: {:?}", self.mir_body.source.def_id(), e.message)
199-
};
175+
let mappings = self.create_mappings_and_inject_coverage_statements(&coverage_spans);
200176

201177
self.mir_body.function_coverage_info = Some(Box::new(FunctionCoverageInfo {
202178
function_source_hash: self.function_source_hash,
203179
num_counters: self.coverage_counters.num_counters(),
204180
expressions: self.coverage_counters.take_expressions(),
205-
mappings: std::mem::take(&mut self.mappings),
181+
mappings,
206182
}));
207183
}
208184

209-
/// Injects a single [`StatementKind::Coverage`] for each BCB that has one
210-
/// or more coverage spans.
211-
fn inject_coverage_span_counters(&mut self, coverage_spans: &CoverageSpans) {
212-
let tcx = self.tcx;
213-
let source_map = tcx.sess.source_map();
185+
/// For each [`BcbCounter`] associated with a BCB node or BCB edge, create
186+
/// any corresponding mappings (for BCB nodes only), and inject any necessary
187+
/// coverage statements into MIR.
188+
fn create_mappings_and_inject_coverage_statements(
189+
&mut self,
190+
coverage_spans: &CoverageSpans,
191+
) -> Vec<Mapping> {
192+
let source_map = self.tcx.sess.source_map();
214193
let body_span = self.body_span;
215194
let file_name = Symbol::intern(&self.source_file.name.prefer_remapped().to_string_lossy());
216195

217-
for (bcb, spans) in coverage_spans.bcbs_with_coverage_spans() {
218-
let counter_kind = self.coverage_counters.take_bcb_counter(bcb).unwrap_or_else(|| {
219-
bug!("Every BasicCoverageBlock should have a Counter or Expression");
220-
});
221-
222-
let term = counter_kind.as_term();
223-
self.mappings.extend(spans.iter().map(|&span| {
224-
let code_region = make_code_region(source_map, file_name, span, body_span);
225-
Mapping { code_region, term }
226-
}));
227-
228-
inject_statement(
229-
self.mir_body,
230-
self.make_mir_coverage_kind(&counter_kind),
231-
self.bcb_leader_bb(bcb),
232-
);
233-
}
234-
}
196+
let mut mappings = Vec::new();
197+
198+
// Process the counters and spans associated with BCB nodes.
199+
for (bcb, counter_kind) in self.coverage_counters.bcb_node_counters() {
200+
let spans = coverage_spans.spans_for_bcb(bcb);
201+
let has_mappings = !spans.is_empty();
202+
203+
// If this BCB has any coverage spans, add corresponding mappings to
204+
// the mappings table.
205+
if has_mappings {
206+
let term = counter_kind.as_term();
207+
mappings.extend(spans.iter().map(|&span| {
208+
let code_region = make_code_region(source_map, file_name, span, body_span);
209+
Mapping { code_region, term }
210+
}));
211+
}
235212

236-
/// At this point, any BCB with coverage counters has already had its counter injected
237-
/// into MIR, and had its counter removed from `coverage_counters` (via `take_counter()`).
238-
///
239-
/// Any other counter associated with a `BasicCoverageBlock`, or its incoming edge, but not
240-
/// associated with a coverage span, should only exist if the counter is an `Expression`
241-
/// dependency (one of the expression operands). Collect them, and inject the additional
242-
/// counters into the MIR, without a reportable coverage span.
243-
fn inject_indirect_counters(&mut self) {
244-
let mut bcb_counters_without_direct_coverage_spans = Vec::new();
245-
for (target_bcb, counter_kind) in self.coverage_counters.drain_bcb_counters() {
246-
bcb_counters_without_direct_coverage_spans.push((None, target_bcb, counter_kind));
247-
}
248-
for ((from_bcb, target_bcb), counter_kind) in
249-
self.coverage_counters.drain_bcb_edge_counters()
250-
{
251-
bcb_counters_without_direct_coverage_spans.push((
252-
Some(from_bcb),
253-
target_bcb,
254-
counter_kind,
255-
));
213+
let do_inject = match counter_kind {
214+
// Counter-increment statements always need to be injected.
215+
BcbCounter::Counter { .. } => true,
216+
// The only purpose of expression-used statements is to detect
217+
// when a mapping is unreachable, so we only inject them for
218+
// expressions with one or more mappings.
219+
BcbCounter::Expression { .. } => has_mappings,
220+
};
221+
if do_inject {
222+
inject_statement(
223+
self.mir_body,
224+
self.make_mir_coverage_kind(counter_kind),
225+
self.basic_coverage_blocks[bcb].leader_bb(),
226+
);
227+
}
256228
}
257229

258-
for (edge_from_bcb, target_bcb, counter_kind) in bcb_counters_without_direct_coverage_spans
259-
{
260-
match counter_kind {
261-
BcbCounter::Counter { .. } => {
262-
let inject_to_bb = if let Some(from_bcb) = edge_from_bcb {
263-
// The MIR edge starts `from_bb` (the outgoing / last BasicBlock in
264-
// `from_bcb`) and ends at `to_bb` (the incoming / first BasicBlock in the
265-
// `target_bcb`; also called the `leader_bb`).
266-
let from_bb = self.bcb_last_bb(from_bcb);
267-
let to_bb = self.bcb_leader_bb(target_bcb);
268-
269-
let new_bb = inject_edge_counter_basic_block(self.mir_body, from_bb, to_bb);
270-
debug!(
271-
"Edge {:?} (last {:?}) -> {:?} (leader {:?}) requires a new MIR \
272-
BasicBlock {:?}, for unclaimed edge counter {:?}",
273-
edge_from_bcb, from_bb, target_bcb, to_bb, new_bb, counter_kind,
274-
);
275-
new_bb
276-
} else {
277-
let target_bb = self.bcb_last_bb(target_bcb);
278-
debug!(
279-
"{:?} ({:?}) gets a new Coverage statement for unclaimed counter {:?}",
280-
target_bcb, target_bb, counter_kind,
281-
);
282-
target_bb
283-
};
284-
285-
inject_statement(
286-
self.mir_body,
287-
self.make_mir_coverage_kind(&counter_kind),
288-
inject_to_bb,
289-
);
290-
}
291-
// Experessions with no associated spans don't need to inject a statement.
292-
BcbCounter::Expression { .. } => {}
230+
// Process the counters associated with BCB edges.
231+
for ((from_bcb, to_bcb), counter_kind) in self.coverage_counters.bcb_edge_counters() {
232+
let do_inject = match counter_kind {
233+
// Counter-increment statements always need to be injected.
234+
BcbCounter::Counter { .. } => true,
235+
// BCB-edge expressions never have mappings, so they never need
236+
// a corresponding statement.
237+
BcbCounter::Expression { .. } => false,
238+
};
239+
if !do_inject {
240+
continue;
293241
}
294-
}
295-
}
296242

297-
#[inline]
298-
fn bcb_leader_bb(&self, bcb: BasicCoverageBlock) -> BasicBlock {
299-
self.bcb_data(bcb).leader_bb()
300-
}
243+
// We need to inject a coverage statement into a new BB between the
244+
// last BB of `from_bcb` and the first BB of `to_bcb`.
245+
let from_bb = self.basic_coverage_blocks[from_bcb].last_bb();
246+
let to_bb = self.basic_coverage_blocks[to_bcb].leader_bb();
301247

302-
#[inline]
303-
fn bcb_last_bb(&self, bcb: BasicCoverageBlock) -> BasicBlock {
304-
self.bcb_data(bcb).last_bb()
305-
}
248+
let new_bb = inject_edge_counter_basic_block(self.mir_body, from_bb, to_bb);
249+
debug!(
250+
"Edge {from_bcb:?} (last {from_bb:?}) -> {to_bcb:?} (leader {to_bb:?}) \
251+
requires a new MIR BasicBlock {new_bb:?} for edge counter {counter_kind:?}",
252+
);
253+
254+
// Inject a counter into the newly-created BB.
255+
inject_statement(self.mir_body, self.make_mir_coverage_kind(&counter_kind), new_bb);
256+
}
306257

307-
#[inline]
308-
fn bcb_data(&self, bcb: BasicCoverageBlock) -> &BasicCoverageBlockData {
309-
&self.basic_coverage_blocks[bcb]
258+
mappings
310259
}
311260

312261
fn make_mir_coverage_kind(&self, counter_kind: &BcbCounter) -> CoverageKind {

Diff for: compiler/rustc_mir_transform/src/coverage/spans.rs

+2-7
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,8 @@ impl CoverageSpans {
4141
!self.bcb_to_spans[bcb].is_empty()
4242
}
4343

44-
pub(super) fn bcbs_with_coverage_spans(
45-
&self,
46-
) -> impl Iterator<Item = (BasicCoverageBlock, &[Span])> {
47-
self.bcb_to_spans.iter_enumerated().filter_map(|(bcb, spans)| {
48-
// Only yield BCBs that have at least one coverage span.
49-
(!spans.is_empty()).then_some((bcb, spans.as_slice()))
50-
})
44+
pub(super) fn spans_for_bcb(&self, bcb: BasicCoverageBlock) -> &[Span] {
45+
&self.bcb_to_spans[bcb]
5146
}
5247
}
5348

0 commit comments

Comments
 (0)