Skip to content

Commit 4184f25

Browse files
committed
coverage: Represent branches as a list of arms
Within the `InstrumentCoverage` pass, we now represent branches as a list of arms, instead of a true/false pair, until we prepare the final table of mappings to be attached to the MIR body. (We then flatten the list into two-way branches by treating each arm as a branch between its success block, and the total of all later arms.) Currently all of the branches produced by MIR building are still two-way, but this is a step towards allowing many-way branches.
1 parent c163cec commit 4184f25

File tree

4 files changed

+69
-37
lines changed

4 files changed

+69
-37
lines changed

compiler/rustc_mir_transform/src/coverage/counters.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,12 @@ impl CoverageCounters {
8888
BcbCounter::Counter { id }
8989
}
9090

91-
fn make_expression(&mut self, lhs: BcbCounter, op: Op, rhs: BcbCounter) -> BcbCounter {
91+
pub(super) fn make_expression(
92+
&mut self,
93+
lhs: BcbCounter,
94+
op: Op,
95+
rhs: BcbCounter,
96+
) -> BcbCounter {
9297
let expression = Expression { lhs: lhs.as_term(), op, rhs: rhs.as_term() };
9398
let id = self.expressions.push(expression);
9499
BcbCounter::Expression { id }

compiler/rustc_mir_transform/src/coverage/mod.rs

+39-13
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ mod tests;
99

1010
use self::counters::{CounterIncrementSite, CoverageCounters};
1111
use self::graph::{BasicCoverageBlock, CoverageGraph};
12-
use self::spans::{BcbMapping, BcbMappingKind, CoverageSpans};
12+
use self::spans::{BcbBranchArm, BcbMapping, BcbMappingKind, CoverageSpans};
1313

1414
use crate::MirPass;
1515

@@ -83,10 +83,10 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir:
8383
// and all `Expression` dependencies (operands) are also generated, for any other
8484
// `BasicCoverageBlock`s not already associated with a coverage span.
8585
let bcb_has_coverage_spans = |bcb| coverage_spans.bcb_has_coverage_spans(bcb);
86-
let coverage_counters =
86+
let mut coverage_counters =
8787
CoverageCounters::make_bcb_counters(&basic_coverage_blocks, bcb_has_coverage_spans);
8888

89-
let mappings = create_mappings(tcx, &hir_info, &coverage_spans, &coverage_counters);
89+
let mappings = create_mappings(tcx, &hir_info, &coverage_spans, &mut coverage_counters);
9090
if mappings.is_empty() {
9191
// No spans could be converted into valid mappings, so skip this function.
9292
debug!("no spans could be converted into valid mappings; skipping");
@@ -117,7 +117,7 @@ fn create_mappings<'tcx>(
117117
tcx: TyCtxt<'tcx>,
118118
hir_info: &ExtractedHirInfo,
119119
coverage_spans: &CoverageSpans,
120-
coverage_counters: &CoverageCounters,
120+
coverage_counters: &mut CoverageCounters,
121121
) -> Vec<Mapping> {
122122
let source_map = tcx.sess.source_map();
123123
let body_span = hir_info.body_span;
@@ -136,20 +136,46 @@ fn create_mappings<'tcx>(
136136
.as_term()
137137
};
138138

139-
coverage_spans
140-
.all_bcb_mappings()
141-
.filter_map(|&BcbMapping { kind: bcb_mapping_kind, span }| {
139+
let mut mappings = vec![];
140+
141+
mappings.extend(coverage_spans.all_bcb_mappings().filter_map(
142+
|&BcbMapping { kind: bcb_mapping_kind, span }| {
142143
let kind = match bcb_mapping_kind {
143144
BcbMappingKind::Code(bcb) => MappingKind::Code(term_for_bcb(bcb)),
144-
BcbMappingKind::Branch { true_bcb, false_bcb } => MappingKind::Branch {
145-
true_term: term_for_bcb(true_bcb),
146-
false_term: term_for_bcb(false_bcb),
147-
},
148145
};
149146
let code_region = make_code_region(source_map, file_name, span, body_span)?;
150147
Some(Mapping { kind, code_region })
151-
})
152-
.collect::<Vec<_>>()
148+
},
149+
));
150+
151+
for arm_list in &coverage_spans.branch_arm_lists {
152+
let mut arms_rev = arm_list.iter().rev();
153+
154+
let mut rest_counter = {
155+
// The last arm's span is ignored, because its BCB is only used as the
156+
// false branch of the second-last arm; it's not a branch of its own.
157+
let Some(&BcbBranchArm { span: _, bcb }) = arms_rev.next() else { continue };
158+
coverage_counters.bcb_counter(bcb).expect("all relevant BCBs have counters")
159+
};
160+
161+
for &BcbBranchArm { span, bcb } in arms_rev {
162+
let true_counter =
163+
coverage_counters.bcb_counter(bcb).expect("all relevant BCBs have counters");
164+
let kind = MappingKind::Branch {
165+
true_term: true_counter.as_term(),
166+
false_term: rest_counter.as_term(),
167+
};
168+
169+
if let Some(code_region) = make_code_region(source_map, file_name, span, body_span) {
170+
mappings.push(Mapping { kind, code_region });
171+
}
172+
173+
// FIXME: Avoid creating an unused expression on the last iteration.
174+
rest_counter = coverage_counters.make_expression(true_counter, Op::Add, rest_counter);
175+
}
176+
}
177+
178+
mappings
153179
}
154180

155181
/// For each BCB node or BCB edge that has an associated coverage counter,

compiler/rustc_mir_transform/src/coverage/spans.rs

+16-13
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ mod from_mir;
1313
pub(super) enum BcbMappingKind {
1414
/// Associates an ordinary executable code span with its corresponding BCB.
1515
Code(BasicCoverageBlock),
16-
/// Associates a branch span with BCBs for its true and false arms.
17-
Branch { true_bcb: BasicCoverageBlock, false_bcb: BasicCoverageBlock },
16+
// Branches have additional structure that can't be represented here, so
17+
// they are handled separately.
1818
}
1919

2020
#[derive(Debug)]
@@ -23,9 +23,15 @@ pub(super) struct BcbMapping {
2323
pub(super) span: Span,
2424
}
2525

26+
pub(super) struct BcbBranchArm {
27+
pub(super) span: Span,
28+
pub(super) bcb: BasicCoverageBlock,
29+
}
30+
2631
pub(super) struct CoverageSpans {
2732
bcb_has_mappings: BitSet<BasicCoverageBlock>,
2833
mappings: Vec<BcbMapping>,
34+
pub(super) branch_arm_lists: Vec<Vec<BcbBranchArm>>,
2935
}
3036

3137
impl CoverageSpans {
@@ -48,6 +54,7 @@ pub(super) fn generate_coverage_spans(
4854
basic_coverage_blocks: &CoverageGraph,
4955
) -> Option<CoverageSpans> {
5056
let mut mappings = vec![];
57+
let mut branch_arm_lists = vec![];
5158

5259
if hir_info.is_async_fn {
5360
// An async function desugars into a function that returns a future,
@@ -69,14 +76,11 @@ pub(super) fn generate_coverage_spans(
6976
BcbMapping { kind: BcbMappingKind::Code(bcb), span }
7077
}));
7178

72-
mappings.extend(from_mir::extract_branch_mappings(
73-
mir_body,
74-
hir_info.body_span,
75-
basic_coverage_blocks,
76-
));
79+
branch_arm_lists =
80+
from_mir::extract_branch_arm_lists(mir_body, hir_info, basic_coverage_blocks);
7781
}
7882

79-
if mappings.is_empty() {
83+
if mappings.is_empty() && branch_arm_lists.is_empty() {
8084
return None;
8185
}
8286

@@ -88,14 +92,13 @@ pub(super) fn generate_coverage_spans(
8892
for &BcbMapping { kind, span: _ } in &mappings {
8993
match kind {
9094
BcbMappingKind::Code(bcb) => insert(bcb),
91-
BcbMappingKind::Branch { true_bcb, false_bcb } => {
92-
insert(true_bcb);
93-
insert(false_bcb);
94-
}
9595
}
9696
}
97+
for &BcbBranchArm { bcb, .. } in branch_arm_lists.iter().flatten() {
98+
insert(bcb);
99+
}
97100

98-
Some(CoverageSpans { bcb_has_mappings, mappings })
101+
Some(CoverageSpans { bcb_has_mappings, mappings, branch_arm_lists })
99102
}
100103

101104
#[derive(Debug)]

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

+8-10
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use rustc_span::{ExpnKind, MacroKind, Span, Symbol};
1111
use crate::coverage::graph::{
1212
BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph, START_BCB,
1313
};
14-
use crate::coverage::spans::{BcbMapping, BcbMappingKind};
14+
use crate::coverage::spans::BcbBranchArm;
1515
use crate::coverage::ExtractedHirInfo;
1616

1717
/// Traverses the MIR body to produce an initial collection of coverage-relevant
@@ -361,20 +361,17 @@ impl SpanFromMir {
361361
}
362362
}
363363

364-
pub(super) fn extract_branch_mappings(
364+
pub(super) fn extract_branch_arm_lists(
365365
mir_body: &mir::Body<'_>,
366-
body_span: Span,
366+
hir_info: &ExtractedHirInfo,
367367
basic_coverage_blocks: &CoverageGraph,
368-
) -> Vec<BcbMapping> {
369-
let Some(branch_info) = mir_body.coverage_branch_info.as_deref() else {
370-
return vec![];
371-
};
368+
) -> Vec<Vec<BcbBranchArm>> {
369+
let Some(branch_info) = mir_body.coverage_branch_info.as_deref() else { return vec![] };
372370

373371
let mut block_markers = IndexVec::<BlockMarkerId, Option<BasicBlock>>::from_elem_n(
374372
None,
375373
branch_info.num_block_markers,
376374
);
377-
378375
// Fill out the mapping from block marker IDs to their enclosing blocks.
379376
for (bb, data) in mir_body.basic_blocks.iter_enumerated() {
380377
for statement in &data.statements {
@@ -393,15 +390,16 @@ pub(super) fn extract_branch_mappings(
393390
if !raw_span.ctxt().outer_expn_data().is_root() {
394391
return None;
395392
}
396-
let (span, _) = unexpand_into_body_span_with_visible_macro(raw_span, body_span)?;
393+
let (span, _) =
394+
unexpand_into_body_span_with_visible_macro(raw_span, hir_info.body_span)?;
397395

398396
let bcb_from_marker =
399397
|marker: BlockMarkerId| basic_coverage_blocks.bcb_from_bb(block_markers[marker]?);
400398

401399
let true_bcb = bcb_from_marker(true_marker)?;
402400
let false_bcb = bcb_from_marker(false_marker)?;
403401

404-
Some(BcbMapping { kind: BcbMappingKind::Branch { true_bcb, false_bcb }, span })
402+
Some(vec![BcbBranchArm { span, bcb: true_bcb }, BcbBranchArm { span, bcb: false_bcb }])
405403
})
406404
.collect::<Vec<_>>()
407405
}

0 commit comments

Comments
 (0)