Skip to content

Commit b7f85f7

Browse files
authored
Rollup merge of rust-lang#124615 - Zalathar:extracted-mappings, r=davidtwco
coverage: Further simplify extraction of mapping info from MIR This is another round of rearrangement and simplification that builds on top of the changes made to mapping-extraction by rust-lang#124603. The overall theme is to take the computation of `bcb_has_mappings` and `test_vector_bitmap_bytes` out of the main body of `generate_coverage_spans`, which then lets us perform a few other small changes that had previously been held up by the need to work around those computations.
2 parents f7b1501 + 0c12a3b commit b7f85f7

File tree

2 files changed

+118
-107
lines changed

2 files changed

+118
-107
lines changed

compiler/rustc_mir_transform/src/coverage/mappings.rs

+76-74
Original file line numberDiff line numberDiff line change
@@ -52,104 +52,104 @@ pub(super) struct MCDCDecision {
5252
pub(super) decision_depth: u16,
5353
}
5454

55-
pub(super) struct CoverageSpans {
56-
bcb_has_mappings: BitSet<BasicCoverageBlock>,
55+
#[derive(Default)]
56+
pub(super) struct ExtractedMappings {
5757
pub(super) code_mappings: Vec<CodeMapping>,
5858
pub(super) branch_pairs: Vec<BranchPair>,
59-
test_vector_bitmap_bytes: u32,
59+
pub(super) mcdc_bitmap_bytes: u32,
6060
pub(super) mcdc_branches: Vec<MCDCBranch>,
6161
pub(super) mcdc_decisions: Vec<MCDCDecision>,
6262
}
6363

64-
impl CoverageSpans {
65-
pub(super) fn bcb_has_coverage_spans(&self, bcb: BasicCoverageBlock) -> bool {
66-
self.bcb_has_mappings.contains(bcb)
67-
}
68-
69-
pub(super) fn test_vector_bitmap_bytes(&self) -> u32 {
70-
self.test_vector_bitmap_bytes
71-
}
72-
}
73-
7464
/// Extracts coverage-relevant spans from MIR, and associates them with
7565
/// their corresponding BCBs.
76-
///
77-
/// Returns `None` if no coverage-relevant spans could be extracted.
78-
pub(super) fn generate_coverage_spans(
66+
pub(super) fn extract_all_mapping_info_from_mir(
7967
mir_body: &mir::Body<'_>,
8068
hir_info: &ExtractedHirInfo,
8169
basic_coverage_blocks: &CoverageGraph,
82-
) -> Option<CoverageSpans> {
83-
let mut code_mappings = vec![];
84-
let mut branch_pairs = vec![];
85-
let mut mcdc_branches = vec![];
86-
let mut mcdc_decisions = vec![];
87-
70+
) -> ExtractedMappings {
8871
if hir_info.is_async_fn {
8972
// An async function desugars into a function that returns a future,
9073
// with the user code wrapped in a closure. Any spans in the desugared
9174
// outer function will be unhelpful, so just keep the signature span
9275
// and ignore all of the spans in the MIR body.
76+
let mut mappings = ExtractedMappings::default();
9377
if let Some(span) = hir_info.fn_sig_span_extended {
94-
code_mappings.push(CodeMapping { span, bcb: START_BCB });
78+
mappings.code_mappings.push(CodeMapping { span, bcb: START_BCB });
9579
}
96-
} else {
97-
extract_refined_covspans(mir_body, hir_info, basic_coverage_blocks, &mut code_mappings);
98-
99-
branch_pairs.extend(extract_branch_pairs(mir_body, hir_info, basic_coverage_blocks));
100-
101-
extract_mcdc_mappings(
102-
mir_body,
103-
hir_info.body_span,
104-
basic_coverage_blocks,
105-
&mut mcdc_branches,
106-
&mut mcdc_decisions,
107-
);
80+
return mappings;
10881
}
10982

110-
if code_mappings.is_empty()
111-
&& branch_pairs.is_empty()
112-
&& mcdc_branches.is_empty()
113-
&& mcdc_decisions.is_empty()
114-
{
115-
return None;
116-
}
83+
let mut code_mappings = vec![];
84+
let mut branch_pairs = vec![];
85+
let mut mcdc_bitmap_bytes = 0;
86+
let mut mcdc_branches = vec![];
87+
let mut mcdc_decisions = vec![];
11788

118-
// Identify which BCBs have one or more mappings.
119-
let mut bcb_has_mappings = BitSet::new_empty(basic_coverage_blocks.num_nodes());
120-
let mut insert = |bcb| {
121-
bcb_has_mappings.insert(bcb);
122-
};
89+
extract_refined_covspans(mir_body, hir_info, basic_coverage_blocks, &mut code_mappings);
12390

124-
for &CodeMapping { span: _, bcb } in &code_mappings {
125-
insert(bcb);
126-
}
127-
for &BranchPair { true_bcb, false_bcb, .. } in &branch_pairs {
128-
insert(true_bcb);
129-
insert(false_bcb);
130-
}
131-
for &MCDCBranch { true_bcb, false_bcb, .. } in &mcdc_branches {
132-
insert(true_bcb);
133-
insert(false_bcb);
134-
}
91+
branch_pairs.extend(extract_branch_pairs(mir_body, hir_info, basic_coverage_blocks));
13592

136-
// Determine the length of the test vector bitmap.
137-
let test_vector_bitmap_bytes = mcdc_decisions
138-
.iter()
139-
.map(|&MCDCDecision { bitmap_idx, conditions_num, .. }| {
140-
bitmap_idx + (1_u32 << u32::from(conditions_num)).div_ceil(8)
141-
})
142-
.max()
143-
.unwrap_or(0);
93+
extract_mcdc_mappings(
94+
mir_body,
95+
hir_info.body_span,
96+
basic_coverage_blocks,
97+
&mut mcdc_bitmap_bytes,
98+
&mut mcdc_branches,
99+
&mut mcdc_decisions,
100+
);
144101

145-
Some(CoverageSpans {
146-
bcb_has_mappings,
102+
ExtractedMappings {
147103
code_mappings,
148104
branch_pairs,
149-
test_vector_bitmap_bytes,
105+
mcdc_bitmap_bytes,
150106
mcdc_branches,
151107
mcdc_decisions,
152-
})
108+
}
109+
}
110+
111+
impl ExtractedMappings {
112+
pub(super) fn all_bcbs_with_counter_mappings(
113+
&self,
114+
basic_coverage_blocks: &CoverageGraph, // Only used for allocating a correctly-sized set
115+
) -> BitSet<BasicCoverageBlock> {
116+
// Fully destructure self to make sure we don't miss any fields that have mappings.
117+
let Self {
118+
code_mappings,
119+
branch_pairs,
120+
mcdc_bitmap_bytes: _,
121+
mcdc_branches,
122+
mcdc_decisions,
123+
} = self;
124+
125+
// Identify which BCBs have one or more mappings.
126+
let mut bcbs_with_counter_mappings = BitSet::new_empty(basic_coverage_blocks.num_nodes());
127+
let mut insert = |bcb| {
128+
bcbs_with_counter_mappings.insert(bcb);
129+
};
130+
131+
for &CodeMapping { span: _, bcb } in code_mappings {
132+
insert(bcb);
133+
}
134+
for &BranchPair { true_bcb, false_bcb, .. } in branch_pairs {
135+
insert(true_bcb);
136+
insert(false_bcb);
137+
}
138+
for &MCDCBranch { true_bcb, false_bcb, .. } in mcdc_branches {
139+
insert(true_bcb);
140+
insert(false_bcb);
141+
}
142+
143+
// MC/DC decisions refer to BCBs, but don't require those BCBs to have counters.
144+
if bcbs_with_counter_mappings.is_empty() {
145+
debug_assert!(
146+
mcdc_decisions.is_empty(),
147+
"A function with no counter mappings shouldn't have any decisions: {mcdc_decisions:?}",
148+
);
149+
}
150+
151+
bcbs_with_counter_mappings
152+
}
153153
}
154154

155155
fn resolve_block_markers(
@@ -215,6 +215,7 @@ pub(super) fn extract_mcdc_mappings(
215215
mir_body: &mir::Body<'_>,
216216
body_span: Span,
217217
basic_coverage_blocks: &CoverageGraph,
218+
mcdc_bitmap_bytes: &mut u32,
218219
mcdc_branches: &mut impl Extend<MCDCBranch>,
219220
mcdc_decisions: &mut impl Extend<MCDCDecision>,
220221
) {
@@ -253,8 +254,6 @@ pub(super) fn extract_mcdc_mappings(
253254
},
254255
));
255256

256-
let mut next_bitmap_idx = 0;
257-
258257
mcdc_decisions.extend(branch_info.mcdc_decision_spans.iter().filter_map(
259258
|decision: &mir::coverage::MCDCDecisionSpan| {
260259
let (span, _) = unexpand_into_body_span_with_visible_macro(decision.span, body_span)?;
@@ -265,8 +264,11 @@ pub(super) fn extract_mcdc_mappings(
265264
.map(|&marker| bcb_from_marker(marker))
266265
.collect::<Option<_>>()?;
267266

268-
let bitmap_idx = next_bitmap_idx;
269-
next_bitmap_idx += (1_u32 << decision.conditions_num).div_ceil(8);
267+
// Each decision containing N conditions needs 2^N bits of space in
268+
// the bitmap, rounded up to a whole number of bytes.
269+
// The decision's "bitmap index" points to its first byte in the bitmap.
270+
let bitmap_idx = *mcdc_bitmap_bytes;
271+
*mcdc_bitmap_bytes += (1_u32 << decision.conditions_num).div_ceil(8);
270272

271273
Some(MCDCDecision {
272274
span,

compiler/rustc_mir_transform/src/coverage/mod.rs

+42-33
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,9 @@ mod spans;
77
#[cfg(test)]
88
mod tests;
99

10-
use self::counters::{CounterIncrementSite, CoverageCounters};
11-
use self::graph::{BasicCoverageBlock, CoverageGraph};
12-
use self::mappings::CoverageSpans;
13-
14-
use crate::MirPass;
15-
16-
use rustc_middle::mir::coverage::*;
10+
use rustc_middle::mir::coverage::{
11+
CodeRegion, CoverageKind, DecisionInfo, FunctionCoverageInfo, Mapping, MappingKind,
12+
};
1713
use rustc_middle::mir::{
1814
self, BasicBlock, BasicBlockData, SourceInfo, Statement, StatementKind, Terminator,
1915
TerminatorKind,
@@ -23,6 +19,11 @@ use rustc_span::def_id::LocalDefId;
2319
use rustc_span::source_map::SourceMap;
2420
use rustc_span::{BytePos, Pos, RelativeBytePos, Span, Symbol};
2521

22+
use crate::coverage::counters::{CounterIncrementSite, CoverageCounters};
23+
use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph};
24+
use crate::coverage::mappings::ExtractedMappings;
25+
use crate::MirPass;
26+
2627
/// Inserts `StatementKind::Coverage` statements that either instrument the binary with injected
2728
/// counters, via intrinsic `llvm.instrprof.increment`, and/or inject metadata used during codegen
2829
/// to construct the coverage map.
@@ -69,24 +70,27 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir:
6970
let basic_coverage_blocks = CoverageGraph::from_mir(mir_body);
7071

7172
////////////////////////////////////////////////////
72-
// Compute coverage spans from the `CoverageGraph`.
73-
let Some(coverage_spans) =
74-
mappings::generate_coverage_spans(mir_body, &hir_info, &basic_coverage_blocks)
75-
else {
76-
// No relevant spans were found in MIR, so skip instrumenting this function.
77-
return;
78-
};
73+
// Extract coverage spans and other mapping info from MIR.
74+
let extracted_mappings =
75+
mappings::extract_all_mapping_info_from_mir(mir_body, &hir_info, &basic_coverage_blocks);
7976

8077
////////////////////////////////////////////////////
8178
// Create an optimized mix of `Counter`s and `Expression`s for the `CoverageGraph`. Ensure
8279
// every coverage span has a `Counter` or `Expression` assigned to its `BasicCoverageBlock`
8380
// and all `Expression` dependencies (operands) are also generated, for any other
8481
// `BasicCoverageBlock`s not already associated with a coverage span.
85-
let bcb_has_coverage_spans = |bcb| coverage_spans.bcb_has_coverage_spans(bcb);
82+
let bcbs_with_counter_mappings =
83+
extracted_mappings.all_bcbs_with_counter_mappings(&basic_coverage_blocks);
84+
if bcbs_with_counter_mappings.is_empty() {
85+
// No relevant spans were found in MIR, so skip instrumenting this function.
86+
return;
87+
}
88+
89+
let bcb_has_counter_mappings = |bcb| bcbs_with_counter_mappings.contains(bcb);
8690
let coverage_counters =
87-
CoverageCounters::make_bcb_counters(&basic_coverage_blocks, bcb_has_coverage_spans);
91+
CoverageCounters::make_bcb_counters(&basic_coverage_blocks, bcb_has_counter_mappings);
8892

89-
let mappings = create_mappings(tcx, &hir_info, &coverage_spans, &coverage_counters);
93+
let mappings = create_mappings(tcx, &hir_info, &extracted_mappings, &coverage_counters);
9094
if mappings.is_empty() {
9195
// No spans could be converted into valid mappings, so skip this function.
9296
debug!("no spans could be converted into valid mappings; skipping");
@@ -96,13 +100,13 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir:
96100
inject_coverage_statements(
97101
mir_body,
98102
&basic_coverage_blocks,
99-
bcb_has_coverage_spans,
103+
bcb_has_counter_mappings,
100104
&coverage_counters,
101105
);
102106

103-
inject_mcdc_statements(mir_body, &basic_coverage_blocks, &coverage_spans);
107+
inject_mcdc_statements(mir_body, &basic_coverage_blocks, &extracted_mappings);
104108

105-
let mcdc_num_condition_bitmaps = coverage_spans
109+
let mcdc_num_condition_bitmaps = extracted_mappings
106110
.mcdc_decisions
107111
.iter()
108112
.map(|&mappings::MCDCDecision { decision_depth, .. }| decision_depth)
@@ -112,7 +116,7 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir:
112116
mir_body.function_coverage_info = Some(Box::new(FunctionCoverageInfo {
113117
function_source_hash: hir_info.function_source_hash,
114118
num_counters: coverage_counters.num_counters(),
115-
mcdc_bitmap_bytes: coverage_spans.test_vector_bitmap_bytes(),
119+
mcdc_bitmap_bytes: extracted_mappings.mcdc_bitmap_bytes,
116120
expressions: coverage_counters.into_expressions(),
117121
mappings,
118122
mcdc_num_condition_bitmaps,
@@ -127,7 +131,7 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir:
127131
fn create_mappings<'tcx>(
128132
tcx: TyCtxt<'tcx>,
129133
hir_info: &ExtractedHirInfo,
130-
coverage_spans: &CoverageSpans,
134+
extracted_mappings: &ExtractedMappings,
131135
coverage_counters: &CoverageCounters,
132136
) -> Vec<Mapping> {
133137
let source_map = tcx.sess.source_map();
@@ -148,17 +152,26 @@ fn create_mappings<'tcx>(
148152
};
149153
let region_for_span = |span: Span| make_code_region(source_map, file_name, span, body_span);
150154

155+
// Fully destructure the mappings struct to make sure we don't miss any kinds.
156+
let ExtractedMappings {
157+
code_mappings,
158+
branch_pairs,
159+
mcdc_bitmap_bytes: _,
160+
mcdc_branches,
161+
mcdc_decisions,
162+
} = extracted_mappings;
151163
let mut mappings = Vec::new();
152164

153-
mappings.extend(coverage_spans.code_mappings.iter().filter_map(
165+
mappings.extend(code_mappings.iter().filter_map(
166+
// Ordinary code mappings are the simplest kind.
154167
|&mappings::CodeMapping { span, bcb }| {
155168
let code_region = region_for_span(span)?;
156169
let kind = MappingKind::Code(term_for_bcb(bcb));
157170
Some(Mapping { kind, code_region })
158171
},
159172
));
160173

161-
mappings.extend(coverage_spans.branch_pairs.iter().filter_map(
174+
mappings.extend(branch_pairs.iter().filter_map(
162175
|&mappings::BranchPair { span, true_bcb, false_bcb }| {
163176
let true_term = term_for_bcb(true_bcb);
164177
let false_term = term_for_bcb(false_bcb);
@@ -168,7 +181,7 @@ fn create_mappings<'tcx>(
168181
},
169182
));
170183

171-
mappings.extend(coverage_spans.mcdc_branches.iter().filter_map(
184+
mappings.extend(mcdc_branches.iter().filter_map(
172185
|&mappings::MCDCBranch { span, true_bcb, false_bcb, condition_info, decision_depth: _ }| {
173186
let code_region = region_for_span(span)?;
174187
let true_term = term_for_bcb(true_bcb);
@@ -181,7 +194,7 @@ fn create_mappings<'tcx>(
181194
},
182195
));
183196

184-
mappings.extend(coverage_spans.mcdc_decisions.iter().filter_map(
197+
mappings.extend(mcdc_decisions.iter().filter_map(
185198
|&mappings::MCDCDecision { span, bitmap_idx, conditions_num, .. }| {
186199
let code_region = region_for_span(span)?;
187200
let kind = MappingKind::MCDCDecision(DecisionInfo { bitmap_idx, conditions_num });
@@ -249,20 +262,16 @@ fn inject_coverage_statements<'tcx>(
249262
fn inject_mcdc_statements<'tcx>(
250263
mir_body: &mut mir::Body<'tcx>,
251264
basic_coverage_blocks: &CoverageGraph,
252-
coverage_spans: &CoverageSpans,
265+
extracted_mappings: &ExtractedMappings,
253266
) {
254-
if coverage_spans.test_vector_bitmap_bytes() == 0 {
255-
return;
256-
}
257-
258267
// Inject test vector update first because `inject_statement` always insert new statement at head.
259268
for &mappings::MCDCDecision {
260269
span: _,
261270
ref end_bcbs,
262271
bitmap_idx,
263272
conditions_num: _,
264273
decision_depth,
265-
} in &coverage_spans.mcdc_decisions
274+
} in &extracted_mappings.mcdc_decisions
266275
{
267276
for end in end_bcbs {
268277
let end_bb = basic_coverage_blocks[*end].leader_bb();
@@ -275,7 +284,7 @@ fn inject_mcdc_statements<'tcx>(
275284
}
276285

277286
for &mappings::MCDCBranch { span: _, true_bcb, false_bcb, condition_info, decision_depth } in
278-
&coverage_spans.mcdc_branches
287+
&extracted_mappings.mcdc_branches
279288
{
280289
let Some(condition_info) = condition_info else { continue };
281290
let id = condition_info.condition_id;

0 commit comments

Comments
 (0)