Skip to content

Commit 572d7e9

Browse files
committed
coverage: Flatten the functions for extracting/refining coverage spans
Consolidating this code into flatter functions reduces the amount of pointer-chasing required to read and modify it.
1 parent 83ef18c commit 572d7e9

File tree

3 files changed

+53
-74
lines changed

3 files changed

+53
-74
lines changed

compiler/rustc_mir_transform/src/coverage/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir:
7373
////////////////////////////////////////////////////
7474
// Compute coverage spans from the `CoverageGraph`.
7575
let Some(coverage_spans) =
76-
CoverageSpans::generate_coverage_spans(mir_body, &hir_info, &basic_coverage_blocks)
76+
spans::generate_coverage_spans(mir_body, &hir_info, &basic_coverage_blocks)
7777
else {
7878
// No relevant spans were found in MIR, so skip instrumenting this function.
7979
return;

compiler/rustc_mir_transform/src/coverage/spans.rs

+46-73
Original file line numberDiff line numberDiff line change
@@ -26,45 +26,6 @@ pub(super) struct CoverageSpans {
2626
}
2727

2828
impl CoverageSpans {
29-
/// Extracts coverage-relevant spans from MIR, and associates them with
30-
/// their corresponding BCBs.
31-
///
32-
/// Returns `None` if no coverage-relevant spans could be extracted.
33-
pub(super) fn generate_coverage_spans(
34-
mir_body: &mir::Body<'_>,
35-
hir_info: &ExtractedHirInfo,
36-
basic_coverage_blocks: &CoverageGraph,
37-
) -> Option<Self> {
38-
let mut mappings = vec![];
39-
40-
let coverage_spans = CoverageSpansGenerator::generate_coverage_spans(
41-
mir_body,
42-
hir_info,
43-
basic_coverage_blocks,
44-
);
45-
mappings.extend(coverage_spans.into_iter().map(|CoverageSpan { bcb, span, .. }| {
46-
// Each span produced by the generator represents an ordinary code region.
47-
BcbMapping { kind: BcbMappingKind::Code(bcb), span }
48-
}));
49-
50-
if mappings.is_empty() {
51-
return None;
52-
}
53-
54-
// Identify which BCBs have one or more mappings.
55-
let mut bcb_has_mappings = BitSet::new_empty(basic_coverage_blocks.num_nodes());
56-
let mut insert = |bcb| {
57-
bcb_has_mappings.insert(bcb);
58-
};
59-
for &BcbMapping { kind, span: _ } in &mappings {
60-
match kind {
61-
BcbMappingKind::Code(bcb) => insert(bcb),
62-
}
63-
}
64-
65-
Some(Self { bcb_has_mappings, mappings })
66-
}
67-
6829
pub(super) fn bcb_has_coverage_spans(&self, bcb: BasicCoverageBlock) -> bool {
6930
self.bcb_has_mappings.contains(bcb)
7031
}
@@ -74,6 +35,43 @@ impl CoverageSpans {
7435
}
7536
}
7637

38+
/// Extracts coverage-relevant spans from MIR, and associates them with
39+
/// their corresponding BCBs.
40+
///
41+
/// Returns `None` if no coverage-relevant spans could be extracted.
42+
pub(super) fn generate_coverage_spans(
43+
mir_body: &mir::Body<'_>,
44+
hir_info: &ExtractedHirInfo,
45+
basic_coverage_blocks: &CoverageGraph,
46+
) -> Option<CoverageSpans> {
47+
let mut mappings = vec![];
48+
49+
let sorted_spans =
50+
from_mir::mir_to_initial_sorted_coverage_spans(mir_body, hir_info, basic_coverage_blocks);
51+
let coverage_spans = SpansRefiner::refine_sorted_spans(basic_coverage_blocks, sorted_spans);
52+
mappings.extend(coverage_spans.into_iter().map(|CoverageSpan { bcb, span, .. }| {
53+
// Each span produced by the generator represents an ordinary code region.
54+
BcbMapping { kind: BcbMappingKind::Code(bcb), span }
55+
}));
56+
57+
if mappings.is_empty() {
58+
return None;
59+
}
60+
61+
// Identify which BCBs have one or more mappings.
62+
let mut bcb_has_mappings = BitSet::new_empty(basic_coverage_blocks.num_nodes());
63+
let mut insert = |bcb| {
64+
bcb_has_mappings.insert(bcb);
65+
};
66+
for &BcbMapping { kind, span: _ } in &mappings {
67+
match kind {
68+
BcbMappingKind::Code(bcb) => insert(bcb),
69+
}
70+
}
71+
72+
Some(CoverageSpans { bcb_has_mappings, mappings })
73+
}
74+
7775
/// A BCB is deconstructed into one or more `Span`s. Each `Span` maps to a `CoverageSpan` that
7876
/// references the originating BCB and one or more MIR `Statement`s and/or `Terminator`s.
7977
/// Initially, the `Span`s come from the `Statement`s and `Terminator`s, but subsequent
@@ -130,7 +128,7 @@ impl CoverageSpan {
130128
/// * Merge spans that represent continuous (both in source code and control flow), non-branching
131129
/// execution
132130
/// * Carve out (leave uncovered) any span that will be counted by another MIR (notably, closures)
133-
struct CoverageSpansGenerator<'a> {
131+
struct SpansRefiner<'a> {
134132
/// The BasicCoverageBlock Control Flow Graph (BCB CFG).
135133
basic_coverage_blocks: &'a CoverageGraph,
136134

@@ -173,40 +171,15 @@ struct CoverageSpansGenerator<'a> {
173171
refined_spans: Vec<CoverageSpan>,
174172
}
175173

176-
impl<'a> CoverageSpansGenerator<'a> {
177-
/// Generate a minimal set of `CoverageSpan`s, each representing a contiguous code region to be
178-
/// counted.
179-
///
180-
/// The basic steps are:
181-
///
182-
/// 1. Extract an initial set of spans from the `Statement`s and `Terminator`s of each
183-
/// `BasicCoverageBlockData`.
184-
/// 2. Sort the spans by span.lo() (starting position). Spans that start at the same position
185-
/// are sorted with longer spans before shorter spans; and equal spans are sorted
186-
/// (deterministically) based on "dominator" relationship (if any).
187-
/// 3. Traverse the spans in sorted order to identify spans that can be dropped (for instance,
188-
/// if another span or spans are already counting the same code region), or should be merged
189-
/// into a broader combined span (because it represents a contiguous, non-branching, and
190-
/// uninterrupted region of source code).
191-
///
192-
/// Closures are exposed in their enclosing functions as `Assign` `Rvalue`s, and since
193-
/// closures have their own MIR, their `Span` in their enclosing function should be left
194-
/// "uncovered".
195-
///
196-
/// Note the resulting vector of `CoverageSpan`s may not be fully sorted (and does not need
197-
/// to be).
198-
pub(super) fn generate_coverage_spans(
199-
mir_body: &mir::Body<'_>,
200-
hir_info: &ExtractedHirInfo,
174+
impl<'a> SpansRefiner<'a> {
175+
/// Takes the initial list of (sorted) spans extracted from MIR, and "refines"
176+
/// them by merging compatible adjacent spans, removing redundant spans,
177+
/// and carving holes in spans when they overlap in unwanted ways.
178+
fn refine_sorted_spans(
201179
basic_coverage_blocks: &'a CoverageGraph,
180+
sorted_spans: Vec<CoverageSpan>,
202181
) -> Vec<CoverageSpan> {
203-
let sorted_spans = from_mir::mir_to_initial_sorted_coverage_spans(
204-
mir_body,
205-
hir_info,
206-
basic_coverage_blocks,
207-
);
208-
209-
let coverage_spans = Self {
182+
let this = Self {
210183
basic_coverage_blocks,
211184
sorted_spans_iter: sorted_spans.into_iter(),
212185
some_curr: None,
@@ -217,7 +190,7 @@ impl<'a> CoverageSpansGenerator<'a> {
217190
refined_spans: Vec::with_capacity(basic_coverage_blocks.num_nodes() * 2),
218191
};
219192

220-
coverage_spans.to_refined_spans()
193+
this.to_refined_spans()
221194
}
222195

223196
/// Iterate through the sorted `CoverageSpan`s, and return the refined list of merged and

compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs

+6
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,12 @@ use crate::coverage::graph::{
1212
use crate::coverage::spans::CoverageSpan;
1313
use crate::coverage::ExtractedHirInfo;
1414

15+
/// Traverses the MIR body to produce an initial collection of coverage-relevant
16+
/// spans, each associated with a node in the coverage graph (BCB) and possibly
17+
/// other metadata.
18+
///
19+
/// The returned spans are sorted in a specific order that is expected by the
20+
/// subsequent span-refinement step.
1521
pub(super) fn mir_to_initial_sorted_coverage_spans(
1622
mir_body: &mir::Body<'_>,
1723
hir_info: &ExtractedHirInfo,

0 commit comments

Comments
 (0)