Skip to content

Commit 7cdaaf1

Browse files
Zalatharranger-ross
authored andcommitted
coverage: Represent branches as a list of arms during MIR building, too
1 parent 2de5a33 commit 7cdaaf1

File tree

6 files changed

+79
-54
lines changed

6 files changed

+79
-54
lines changed

compiler/rustc_middle/src/mir/coverage.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -274,17 +274,21 @@ pub struct CoverageInfoHi {
274274
/// injected into the MIR body. This makes it possible to allocate per-ID
275275
/// data structures without having to scan the entire body first.
276276
pub num_block_markers: usize,
277-
pub branch_spans: Vec<BranchSpan>,
277+
pub branch_arm_lists: Vec<Vec<BranchArm>>,
278278
pub mcdc_branch_spans: Vec<MCDCBranchSpan>,
279279
pub mcdc_decision_spans: Vec<MCDCDecisionSpan>,
280280
}
281281

282282
#[derive(Clone, Debug)]
283283
#[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)]
284-
pub struct BranchSpan {
284+
pub struct BranchArm {
285285
pub span: Span,
286-
pub true_marker: BlockMarkerId,
287-
pub false_marker: BlockMarkerId,
286+
/// Marks the block that is jumped to after this arm's pattern matches,
287+
/// but before its guard is checked.
288+
pub pre_guard_marker: BlockMarkerId,
289+
/// Marks the block that is jumped to after this arm's guard succeeds.
290+
/// If this is equal to `pre_guard_marker`, the arm has no guard.
291+
pub arm_taken_marker: BlockMarkerId,
288292
}
289293

290294
#[derive(Copy, Clone, Debug)]

compiler/rustc_middle/src/mir/pretty.rs

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -537,19 +537,20 @@ fn write_coverage_info_hi(
537537
) -> io::Result<()> {
538538
let coverage::CoverageInfoHi {
539539
num_block_markers: _,
540-
branch_spans,
540+
branch_arm_lists,
541541
mcdc_branch_spans,
542542
mcdc_decision_spans,
543543
} = coverage_info_hi;
544544

545545
// Only add an extra trailing newline if we printed at least one thing.
546546
let mut did_print = false;
547547

548-
for coverage::BranchSpan { span, true_marker, false_marker } in branch_spans {
549-
writeln!(
550-
w,
551-
"{INDENT}coverage branch {{ true: {true_marker:?}, false: {false_marker:?} }} => {span:?}",
552-
)?;
548+
for arms in branch_arm_lists {
549+
writeln!(w, "{INDENT}coverage branches {{")?;
550+
for coverage::BranchArm { span, pre_guard_marker, arm_taken_marker } in arms {
551+
writeln!(w, "{INDENT}{INDENT}{pre_guard_marker:?}, {arm_taken_marker:?} => {span:?}")?;
552+
}
553+
writeln!(w, "{INDENT}}}")?;
553554
did_print = true;
554555
}
555556

@@ -1739,12 +1740,13 @@ pub fn write_allocation_bytes<'tcx, Prov: Provenance, Extra, Bytes: AllocBytes>(
17391740
}
17401741
} else if let Some(prov) = alloc.provenance().get(i, &tcx) {
17411742
// Memory with provenance must be defined
1742-
assert!(
1743-
alloc.init_mask().is_range_initialized(alloc_range(i, Size::from_bytes(1))).is_ok()
1744-
);
1743+
assert!(alloc
1744+
.init_mask()
1745+
.is_range_initialized(alloc_range(i, Size::from_bytes(1)))
1746+
.is_ok());
17451747
ascii.push('━'); // HEAVY HORIZONTAL
1746-
// We have two characters to display this, which is obviously not enough.
1747-
// Format is similar to "oversized" above.
1748+
// We have two characters to display this, which is obviously not enough.
1749+
// Format is similar to "oversized" above.
17481750
let j = i.bytes_usize();
17491751
let c = alloc.inspect_with_uninit_and_ptr_outside_interpreter(j..j + 1)[0];
17501752
write!(w, "╾{c:02x}{prov:#?} (1 ptr byte)╼")?;

compiler/rustc_mir_build/src/build/coverageinfo.rs

Lines changed: 18 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::assert_matches::assert_matches;
22
use std::collections::hash_map::Entry;
33

44
use rustc_data_structures::fx::FxHashMap;
5-
use rustc_middle::mir::coverage::{BlockMarkerId, BranchSpan, CoverageInfoHi, CoverageKind};
5+
use rustc_middle::mir::coverage::{BlockMarkerId, BranchArm, CoverageInfoHi, CoverageKind};
66
use rustc_middle::mir::{self, BasicBlock, SourceInfo, UnOp};
77
use rustc_middle::thir::{ExprId, ExprKind, Pat, Thir};
88
use rustc_middle::ty::TyCtxt;
@@ -23,13 +23,14 @@ pub(crate) struct CoverageInfoBuilder {
2323

2424
/// Present if branch coverage is enabled.
2525
branch_info: Option<BranchInfo>,
26+
2627
/// Present if MC/DC coverage is enabled.
2728
mcdc_info: Option<MCDCInfoBuilder>,
2829
}
2930

3031
#[derive(Default)]
3132
struct BranchInfo {
32-
branch_spans: Vec<BranchSpan>,
33+
branch_arm_lists: Vec<Vec<BranchArm>>,
3334
}
3435

3536
#[derive(Clone, Copy)]
@@ -141,6 +142,9 @@ impl CoverageInfoBuilder {
141142
true_block: BasicBlock,
142143
false_block: BasicBlock,
143144
) {
145+
// Bail out if branch coverage is not enabled.
146+
let Some(branch_info) = self.branch_info.as_mut() else { return };
147+
144148
// Separate path for handling branches when MC/DC is enabled.
145149
if let Some(mcdc_info) = self.mcdc_info.as_mut() {
146150
let inject_block_marker =
@@ -152,37 +156,31 @@ impl CoverageInfoBuilder {
152156
false_block,
153157
inject_block_marker,
154158
);
155-
return;
159+
} else {
160+
let true_marker = self.markers.inject_block_marker(cfg, source_info, true_block);
161+
let false_marker = self.markers.inject_block_marker(cfg, source_info, false_block);
162+
163+
let arm = |marker| BranchArm {
164+
span: source_info.span,
165+
pre_guard_marker: marker,
166+
arm_taken_marker: marker,
167+
};
168+
branch_info.branch_arm_lists.push(vec![arm(true_marker), arm(false_marker)]);
156169
}
157-
158-
// Bail out if branch coverage is not enabled.
159-
let Some(branch_info) = self.branch_info.as_mut() else { return };
160-
161-
let true_marker = self.markers.inject_block_marker(cfg, source_info, true_block);
162-
let false_marker = self.markers.inject_block_marker(cfg, source_info, false_block);
163-
164-
branch_info.branch_spans.push(BranchSpan {
165-
span: source_info.span,
166-
true_marker,
167-
false_marker,
168-
});
169170
}
170171

171172
pub(crate) fn into_done(self) -> Box<CoverageInfoHi> {
172173
let Self { nots: _, markers: BlockMarkerGen { num_block_markers }, branch_info, mcdc_info } =
173174
self;
174175

175-
let branch_spans =
176-
branch_info.map(|branch_info| branch_info.branch_spans).unwrap_or_default();
177-
178176
let (mcdc_decision_spans, mcdc_branch_spans) =
179177
mcdc_info.map(MCDCInfoBuilder::into_done).unwrap_or_default();
180178

181179
// For simplicity, always return an info struct (without Option), even
182180
// if there's nothing interesting in it.
183181
Box::new(CoverageInfoHi {
184182
num_block_markers,
185-
branch_spans,
183+
branch_arm_lists: branch_info.map(|i| i.branch_arm_lists).unwrap_or_default(),
186184
mcdc_branch_spans,
187185
mcdc_decision_spans,
188186
})
@@ -255,7 +253,7 @@ impl<'tcx> Builder<'_, 'tcx> {
255253
}
256254

257255
/// If branch coverage is enabled, inject marker statements into `then_block`
258-
/// and `else_block`, and record their IDs in the table of branch spans.
256+
/// and `else_block`, and record their IDs in the branch table.
259257
pub(crate) fn visit_coverage_branch_condition(
260258
&mut self,
261259
mut expr_id: ExprId,

compiler/rustc_mir_transform/src/coverage/mappings.rs

Lines changed: 30 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use rustc_data_structures::graph::DirectedGraph;
44
use rustc_index::IndexVec;
55
use rustc_index::bit_set::BitSet;
66
use rustc_middle::mir::coverage::{
7-
BlockMarkerId, BranchSpan, ConditionInfo, CoverageInfoHi, CoverageKind,
7+
BlockMarkerId, ConditionInfo, CoverageInfoHi, CoverageKind,
88
};
99
use rustc_middle::mir::{self, BasicBlock, StatementKind};
1010
use rustc_middle::ty::TyCtxt;
@@ -206,24 +206,39 @@ pub(super) fn extract_branch_arm_lists(
206206
let block_markers = resolve_block_markers(coverage_info_hi, mir_body);
207207

208208
coverage_info_hi
209-
.branch_spans
209+
.branch_arm_lists
210210
.iter()
211-
.filter_map(|&BranchSpan { span: raw_span, true_marker, false_marker }| {
212-
// For now, ignore any branch span that was introduced by
213-
// expansion. This makes things like assert macros less noisy.
214-
if !raw_span.ctxt().outer_expn_data().is_root() {
215-
return None;
211+
.filter_map(|arms| {
212+
let mut bcb_arms = Vec::with_capacity(arms.len());
213+
214+
// If any arm can't be resolved, return None to skip the entire list
215+
// of arms that contains it.
216+
for &mir::coverage::BranchArm { span: raw_span, pre_guard_marker, arm_taken_marker } in
217+
arms
218+
{
219+
// For now, ignore any branch span that was introduced by
220+
// expansion. This makes things like assert macros less noisy.
221+
if !raw_span.ctxt().outer_expn_data().is_root() {
222+
return None;
223+
}
224+
225+
let span = unexpand_into_body_span(raw_span, hir_info.body_span)?;
226+
227+
let pre_guard_bcb =
228+
basic_coverage_blocks.bcb_from_bb(block_markers[pre_guard_marker]?)?;
229+
let arm_taken_bcb =
230+
basic_coverage_blocks.bcb_from_bb(block_markers[arm_taken_marker]?)?;
231+
232+
bcb_arms.push(BranchArm { span, pre_guard_bcb, arm_taken_bcb });
216233
}
217-
let span = unexpand_into_body_span(raw_span, hir_info.body_span)?;
218-
219-
let bcb_from_marker =
220-
|marker: BlockMarkerId| basic_coverage_blocks.bcb_from_bb(block_markers[marker]?);
234+
assert_eq!(arms.len(), bcb_arms.len());
221235

222-
let true_bcb = bcb_from_marker(true_marker)?;
223-
let false_bcb = bcb_from_marker(false_marker)?;
236+
if bcb_arms.len() < 2 {
237+
debug_assert!(false, "MIR building shouldn't create branches with <2 arms");
238+
return None;
239+
}
224240

225-
let arm = |bcb| BranchArm { span, pre_guard_bcb: bcb, arm_taken_bcb: bcb };
226-
Some(vec![arm(true_bcb), arm(false_bcb)])
241+
Some(bcb_arms)
227242
})
228243
.collect::<Vec<_>>()
229244
}

tests/mir-opt/coverage/instrument_coverage_cleanup.main.CleanupPostBorrowck.diff

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,17 @@
55
let mut _0: ();
66
let mut _1: bool;
77

8-
coverage branch { true: BlockMarkerId(0), false: BlockMarkerId(1) } => $DIR/instrument_coverage_cleanup.rs:14:8: 14:36 (#0)
8+
coverage branches {
9+
BlockMarkerId(0), BlockMarkerId(0) => $DIR/instrument_coverage_cleanup.rs:14:8: 14:36 (#0)
10+
BlockMarkerId(1), BlockMarkerId(1) => $DIR/instrument_coverage_cleanup.rs:14:8: 14:36 (#0)
11+
}
912

1013
coverage ExpressionId(0) => Expression { lhs: Counter(0), op: Subtract, rhs: Counter(1) };
14+
coverage Branch { true_term: Expression(0), false_term: Counter(1) } => $DIR/instrument_coverage_cleanup.rs:14:8 - 14:36;
1115
coverage Code(Counter(0)) => $DIR/instrument_coverage_cleanup.rs:13:1 - 14:36;
1216
coverage Code(Expression(0)) => $DIR/instrument_coverage_cleanup.rs:14:37 - 14:39;
1317
coverage Code(Counter(1)) => $DIR/instrument_coverage_cleanup.rs:14:39 - 14:40;
1418
coverage Code(Counter(0)) => $DIR/instrument_coverage_cleanup.rs:15:1 - 15:2;
15-
coverage Branch { true_term: Expression(0), false_term: Counter(1) } => $DIR/instrument_coverage_cleanup.rs:14:8 - 14:36;
1619

1720
bb0: {
1821
Coverage::CounterIncrement(0);

tests/mir-opt/coverage/instrument_coverage_cleanup.main.InstrumentCoverage.diff

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,17 @@
55
let mut _0: ();
66
let mut _1: bool;
77

8-
coverage branch { true: BlockMarkerId(0), false: BlockMarkerId(1) } => $DIR/instrument_coverage_cleanup.rs:14:8: 14:36 (#0)
8+
coverage branches {
9+
BlockMarkerId(0), BlockMarkerId(0) => $DIR/instrument_coverage_cleanup.rs:14:8: 14:36 (#0)
10+
BlockMarkerId(1), BlockMarkerId(1) => $DIR/instrument_coverage_cleanup.rs:14:8: 14:36 (#0)
11+
}
912

1013
+ coverage ExpressionId(0) => Expression { lhs: Counter(0), op: Subtract, rhs: Counter(1) };
14+
+ coverage Branch { true_term: Expression(0), false_term: Counter(1) } => $DIR/instrument_coverage_cleanup.rs:14:8 - 14:36;
1115
+ coverage Code(Counter(0)) => $DIR/instrument_coverage_cleanup.rs:13:1 - 14:36;
1216
+ coverage Code(Expression(0)) => $DIR/instrument_coverage_cleanup.rs:14:37 - 14:39;
1317
+ coverage Code(Counter(1)) => $DIR/instrument_coverage_cleanup.rs:14:39 - 14:40;
1418
+ coverage Code(Counter(0)) => $DIR/instrument_coverage_cleanup.rs:15:1 - 15:2;
15-
+ coverage Branch { true_term: Expression(0), false_term: Counter(1) } => $DIR/instrument_coverage_cleanup.rs:14:8 - 14:36;
1619
+
1720
bb0: {
1821
+ Coverage::CounterIncrement(0);

0 commit comments

Comments
 (0)