Skip to content

Commit e45a937

Browse files
committed
Auto merge of rust-lang#119438 - Zalathar:prepare-mappings, r=cjgillot
coverage: Prepare mappings separately from injecting statements These two tasks historically needed to be interleaved, but after various recent changes (including rust-lang#116046 and rust-lang#116917) they can now be fully separated. --- `@rustbot` label +A-code-coverage
2 parents d59f06f + 3f67118 commit e45a937

File tree

4 files changed

+74
-53
lines changed

4 files changed

+74
-53
lines changed

compiler/rustc_mir_transform/src/coverage/counters.rs

+15-15
Original file line numberDiff line numberDiff line change
@@ -61,27 +61,27 @@ pub(super) struct CoverageCounters {
6161
}
6262

6363
impl CoverageCounters {
64-
pub(super) fn new(basic_coverage_blocks: &CoverageGraph) -> Self {
64+
/// Makes [`BcbCounter`] `Counter`s and `Expressions` for the `BasicCoverageBlock`s directly or
65+
/// indirectly associated with coverage spans, and accumulates additional `Expression`s
66+
/// representing intermediate values.
67+
pub(super) fn make_bcb_counters(
68+
basic_coverage_blocks: &CoverageGraph,
69+
bcb_has_coverage_spans: impl Fn(BasicCoverageBlock) -> bool,
70+
) -> Self {
6571
let num_bcbs = basic_coverage_blocks.num_nodes();
6672

67-
Self {
73+
let mut this = Self {
6874
next_counter_id: CounterId::START,
6975
bcb_counters: IndexVec::from_elem_n(None, num_bcbs),
7076
bcb_edge_counters: FxIndexMap::default(),
7177
bcb_has_incoming_edge_counters: BitSet::new_empty(num_bcbs),
7278
expressions: IndexVec::new(),
73-
}
74-
}
79+
};
7580

76-
/// Makes [`BcbCounter`] `Counter`s and `Expressions` for the `BasicCoverageBlock`s directly or
77-
/// indirectly associated with coverage spans, and accumulates additional `Expression`s
78-
/// representing intermediate values.
79-
pub fn make_bcb_counters(
80-
&mut self,
81-
basic_coverage_blocks: &CoverageGraph,
82-
bcb_has_coverage_spans: impl Fn(BasicCoverageBlock) -> bool,
83-
) {
84-
MakeBcbCounters::new(self, basic_coverage_blocks).make_bcb_counters(bcb_has_coverage_spans)
81+
MakeBcbCounters::new(&mut this, basic_coverage_blocks)
82+
.make_bcb_counters(bcb_has_coverage_spans);
83+
84+
this
8585
}
8686

8787
fn make_counter(&mut self) -> BcbCounter {
@@ -189,8 +189,8 @@ impl CoverageCounters {
189189
.map(|(&(from_bcb, to_bcb), counter_kind)| (from_bcb, to_bcb, counter_kind))
190190
}
191191

192-
pub(super) fn take_expressions(&mut self) -> IndexVec<ExpressionId, Expression> {
193-
std::mem::take(&mut self.expressions)
192+
pub(super) fn into_expressions(self) -> IndexVec<ExpressionId, Expression> {
193+
self.expressions
194194
}
195195
}
196196

compiler/rustc_mir_transform/src/coverage/mod.rs

+48-34
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::CoverageGraph;
11+
use self::graph::{BasicCoverageBlock, CoverageGraph};
1212
use self::spans::CoverageSpans;
1313

1414
use crate::MirPass;
@@ -70,7 +70,6 @@ struct Instrumentor<'a, 'tcx> {
7070
mir_body: &'a mut mir::Body<'tcx>,
7171
hir_info: ExtractedHirInfo,
7272
basic_coverage_blocks: CoverageGraph,
73-
coverage_counters: CoverageCounters,
7473
}
7574

7675
impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
@@ -80,9 +79,8 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
8079
debug!(?hir_info, "instrumenting {:?}", mir_body.source.def_id());
8180

8281
let basic_coverage_blocks = CoverageGraph::from_mir(mir_body);
83-
let coverage_counters = CoverageCounters::new(&basic_coverage_blocks);
8482

85-
Self { tcx, mir_body, hir_info, basic_coverage_blocks, coverage_counters }
83+
Self { tcx, mir_body, hir_info, basic_coverage_blocks }
8684
}
8785

8886
fn inject_counters(&'a mut self) {
@@ -103,25 +101,31 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
103101
// and all `Expression` dependencies (operands) are also generated, for any other
104102
// `BasicCoverageBlock`s not already associated with a coverage span.
105103
let bcb_has_coverage_spans = |bcb| coverage_spans.bcb_has_coverage_spans(bcb);
106-
self.coverage_counters
107-
.make_bcb_counters(&self.basic_coverage_blocks, bcb_has_coverage_spans);
104+
let coverage_counters = CoverageCounters::make_bcb_counters(
105+
&self.basic_coverage_blocks,
106+
bcb_has_coverage_spans,
107+
);
108108

109-
let mappings = self.create_mappings_and_inject_coverage_statements(&coverage_spans);
109+
let mappings = self.create_mappings(&coverage_spans, &coverage_counters);
110+
self.inject_coverage_statements(bcb_has_coverage_spans, &coverage_counters);
110111

111112
self.mir_body.function_coverage_info = Some(Box::new(FunctionCoverageInfo {
112113
function_source_hash: self.hir_info.function_source_hash,
113-
num_counters: self.coverage_counters.num_counters(),
114-
expressions: self.coverage_counters.take_expressions(),
114+
num_counters: coverage_counters.num_counters(),
115+
expressions: coverage_counters.into_expressions(),
115116
mappings,
116117
}));
117118
}
118119

119-
/// For each [`BcbCounter`] associated with a BCB node or BCB edge, create
120-
/// any corresponding mappings (for BCB nodes only), and inject any necessary
121-
/// coverage statements into MIR.
122-
fn create_mappings_and_inject_coverage_statements(
123-
&mut self,
120+
/// For each coverage span extracted from MIR, create a corresponding
121+
/// mapping.
122+
///
123+
/// Precondition: All BCBs corresponding to those spans have been given
124+
/// coverage counters.
125+
fn create_mappings(
126+
&self,
124127
coverage_spans: &CoverageSpans,
128+
coverage_counters: &CoverageCounters,
125129
) -> Vec<Mapping> {
126130
let source_map = self.tcx.sess.source_map();
127131
let body_span = self.hir_info.body_span;
@@ -131,30 +135,42 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
131135
let file_name =
132136
Symbol::intern(&source_file.name.for_codegen(self.tcx.sess).to_string_lossy());
133137

134-
let mut mappings = Vec::new();
135-
136-
// Process the counters and spans associated with BCB nodes.
137-
for (bcb, counter_kind) in self.coverage_counters.bcb_node_counters() {
138-
let spans = coverage_spans.spans_for_bcb(bcb);
139-
let has_mappings = !spans.is_empty();
140-
141-
// If this BCB has any coverage spans, add corresponding mappings to
142-
// the mappings table.
143-
if has_mappings {
144-
let term = counter_kind.as_term();
145-
mappings.extend(spans.iter().map(|&span| {
146-
let code_region = make_code_region(source_map, file_name, span, body_span);
147-
Mapping { code_region, term }
148-
}));
149-
}
138+
coverage_spans
139+
.bcbs_with_coverage_spans()
140+
// For each BCB with spans, get a coverage term for its counter.
141+
.map(|(bcb, spans)| {
142+
let term = coverage_counters
143+
.bcb_counter(bcb)
144+
.expect("all BCBs with spans were given counters")
145+
.as_term();
146+
(term, spans)
147+
})
148+
// Flatten the spans into individual term/span pairs.
149+
.flat_map(|(term, spans)| spans.iter().map(move |&span| (term, span)))
150+
// Convert each span to a code region, and create the final mapping.
151+
.map(|(term, span)| {
152+
let code_region = make_code_region(source_map, file_name, span, body_span);
153+
Mapping { term, code_region }
154+
})
155+
.collect::<Vec<_>>()
156+
}
150157

158+
/// For each BCB node or BCB edge that has an associated coverage counter,
159+
/// inject any necessary coverage statements into MIR.
160+
fn inject_coverage_statements(
161+
&mut self,
162+
bcb_has_coverage_spans: impl Fn(BasicCoverageBlock) -> bool,
163+
coverage_counters: &CoverageCounters,
164+
) {
165+
// Process the counters associated with BCB nodes.
166+
for (bcb, counter_kind) in coverage_counters.bcb_node_counters() {
151167
let do_inject = match counter_kind {
152168
// Counter-increment statements always need to be injected.
153169
BcbCounter::Counter { .. } => true,
154170
// The only purpose of expression-used statements is to detect
155171
// when a mapping is unreachable, so we only inject them for
156172
// expressions with one or more mappings.
157-
BcbCounter::Expression { .. } => has_mappings,
173+
BcbCounter::Expression { .. } => bcb_has_coverage_spans(bcb),
158174
};
159175
if do_inject {
160176
inject_statement(
@@ -166,7 +182,7 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
166182
}
167183

168184
// Process the counters associated with BCB edges.
169-
for (from_bcb, to_bcb, counter_kind) in self.coverage_counters.bcb_edge_counters() {
185+
for (from_bcb, to_bcb, counter_kind) in coverage_counters.bcb_edge_counters() {
170186
let do_inject = match counter_kind {
171187
// Counter-increment statements always need to be injected.
172188
BcbCounter::Counter { .. } => true,
@@ -192,8 +208,6 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
192208
// Inject a counter into the newly-created BB.
193209
inject_statement(self.mir_body, self.make_mir_coverage_kind(counter_kind), new_bb);
194210
}
195-
196-
mappings
197211
}
198212

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

compiler/rustc_mir_transform/src/coverage/spans.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,13 @@ impl CoverageSpans {
4848
!self.bcb_to_spans[bcb].is_empty()
4949
}
5050

51-
pub(super) fn spans_for_bcb(&self, bcb: BasicCoverageBlock) -> &[Span] {
52-
&self.bcb_to_spans[bcb]
51+
pub(super) fn bcbs_with_coverage_spans(
52+
&self,
53+
) -> impl Iterator<Item = (BasicCoverageBlock, &[Span])> {
54+
self.bcb_to_spans.iter_enumerated().filter_map(|(bcb, spans)| {
55+
// Only yield BCBs that have at least one coverage span.
56+
(!spans.is_empty()).then_some((bcb, spans.as_slice()))
57+
})
5358
}
5459
}
5560

compiler/rustc_mir_transform/src/coverage/tests.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -630,8 +630,10 @@ fn test_make_bcb_counters() {
630630
// coverage spans for BCBs 1 and 2. Now we skip that step and just tell
631631
// BCB counter construction that those BCBs have spans.
632632
let bcb_has_coverage_spans = |bcb: BasicCoverageBlock| (1..=2).contains(&bcb.as_usize());
633-
let mut coverage_counters = counters::CoverageCounters::new(&basic_coverage_blocks);
634-
coverage_counters.make_bcb_counters(&basic_coverage_blocks, bcb_has_coverage_spans);
633+
let coverage_counters = counters::CoverageCounters::make_bcb_counters(
634+
&basic_coverage_blocks,
635+
bcb_has_coverage_spans,
636+
);
635637
assert_eq!(coverage_counters.num_expressions(), 0);
636638

637639
assert_eq!(

0 commit comments

Comments
 (0)