Skip to content

Commit 1f6a5ee

Browse files
committed
coverage: Include recorded branch info in coverage instrumentation/codegen
1 parent c459504 commit 1f6a5ee

File tree

5 files changed

+84
-4
lines changed

5 files changed

+84
-4
lines changed

compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs

+9
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,15 @@ impl CounterMappingRegion {
164164
end_line,
165165
end_col,
166166
),
167+
MappingKind::Branch { true_term, false_term } => Self::branch_region(
168+
Counter::from_term(true_term),
169+
Counter::from_term(false_term),
170+
local_file_id,
171+
start_line,
172+
start_col,
173+
end_line,
174+
end_col,
175+
),
167176
}
168177
}
169178

compiler/rustc_middle/src/mir/coverage.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -179,14 +179,18 @@ pub struct Expression {
179179
pub enum MappingKind {
180180
/// Associates a normal region of code with a counter/expression/zero.
181181
Code(CovTerm),
182+
/// Associates a branch region with separate counters for true and false.
183+
Branch { true_term: CovTerm, false_term: CovTerm },
182184
}
183185

184186
impl MappingKind {
185187
/// Iterator over all coverage terms in this mapping kind.
186188
pub fn terms(&self) -> impl Iterator<Item = CovTerm> {
187-
let one = |a| std::iter::once(a);
189+
let one = |a| std::iter::once(a).chain(None);
190+
let two = |a, b| std::iter::once(a).chain(Some(b));
188191
match *self {
189192
Self::Code(term) => one(term),
193+
Self::Branch { true_term, false_term } => two(true_term, false_term),
190194
}
191195
}
192196

@@ -195,6 +199,9 @@ impl MappingKind {
195199
pub fn map_terms(&self, map_fn: impl Fn(CovTerm) -> CovTerm) -> Self {
196200
match *self {
197201
Self::Code(term) => Self::Code(map_fn(term)),
202+
Self::Branch { true_term, false_term } => {
203+
Self::Branch { true_term: map_fn(true_term), false_term: map_fn(false_term) }
204+
}
198205
}
199206
}
200207
}

compiler/rustc_mir_transform/src/coverage/mod.rs

+4
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,10 @@ fn create_mappings<'tcx>(
139139
.filter_map(|&BcbMapping { kind: bcb_mapping_kind, span }| {
140140
let kind = match bcb_mapping_kind {
141141
BcbMappingKind::Code(bcb) => MappingKind::Code(term_for_bcb(bcb)),
142+
BcbMappingKind::Branch { true_bcb, false_bcb } => MappingKind::Branch {
143+
true_term: term_for_bcb(true_bcb),
144+
false_term: term_for_bcb(false_bcb),
145+
},
142146
};
143147
let code_region = make_code_region(source_map, file_name, span, body_span)?;
144148
Some(Mapping { kind, code_region })

compiler/rustc_mir_transform/src/coverage/spans.rs

+12
Original file line numberDiff line numberDiff line change
@@ -13,6 +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 },
1618
}
1719

1820
#[derive(Debug)]
@@ -66,6 +68,12 @@ pub(super) fn generate_coverage_spans(
6668
// Each span produced by the generator represents an ordinary code region.
6769
BcbMapping { kind: BcbMappingKind::Code(bcb), span }
6870
}));
71+
72+
mappings.extend(from_mir::extract_branch_mappings(
73+
mir_body,
74+
hir_info.body_span,
75+
basic_coverage_blocks,
76+
));
6977
}
7078

7179
if mappings.is_empty() {
@@ -80,6 +88,10 @@ pub(super) fn generate_coverage_spans(
8088
for &BcbMapping { kind, span: _ } in &mappings {
8189
match kind {
8290
BcbMappingKind::Code(bcb) => insert(bcb),
91+
BcbMappingKind::Branch { true_bcb, false_bcb } => {
92+
insert(true_bcb);
93+
insert(false_bcb);
94+
}
8395
}
8496
}
8597

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

+51-3
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
use rustc_data_structures::captures::Captures;
22
use rustc_data_structures::fx::FxHashSet;
3+
use rustc_index::IndexVec;
4+
use rustc_middle::mir::coverage::{BlockMarkerId, BranchSpan, CoverageKind};
35
use rustc_middle::mir::{
4-
self, AggregateKind, FakeReadCause, Rvalue, Statement, StatementKind, Terminator,
6+
self, AggregateKind, BasicBlock, FakeReadCause, Rvalue, Statement, StatementKind, Terminator,
57
TerminatorKind,
68
};
79
use rustc_span::{ExpnKind, MacroKind, Span, Symbol};
810

911
use crate::coverage::graph::{
1012
BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph, START_BCB,
1113
};
14+
use crate::coverage::spans::{BcbMapping, BcbMappingKind};
1215
use crate::coverage::ExtractedHirInfo;
1316

1417
/// Traverses the MIR body to produce an initial collection of coverage-relevant
@@ -179,8 +182,6 @@ fn is_closure_like(statement: &Statement<'_>) -> bool {
179182
/// If the MIR `Statement` has a span contributive to computing coverage spans,
180183
/// return it; otherwise return `None`.
181184
fn filtered_statement_span(statement: &Statement<'_>) -> Option<Span> {
182-
use mir::coverage::CoverageKind;
183-
184185
match statement.kind {
185186
// These statements have spans that are often outside the scope of the executed source code
186187
// for their parent `BasicBlock`.
@@ -363,3 +364,50 @@ impl SpanFromMir {
363364
Self { span, visible_macro, bcb, is_hole }
364365
}
365366
}
367+
368+
pub(super) fn extract_branch_mappings(
369+
mir_body: &mir::Body<'_>,
370+
body_span: Span,
371+
basic_coverage_blocks: &CoverageGraph,
372+
) -> Vec<BcbMapping> {
373+
let Some(hir_branch_info) = mir_body.coverage_hir_branch_info.as_deref() else {
374+
return vec![];
375+
};
376+
377+
let mut block_markers = IndexVec::<BlockMarkerId, Option<BasicBlock>>::from_elem_n(
378+
None,
379+
hir_branch_info.num_block_markers,
380+
);
381+
382+
for (bb, data) in mir_body.basic_blocks.iter_enumerated() {
383+
for statement in &data.statements {
384+
if let StatementKind::Coverage(coverage) = &statement.kind {
385+
if let CoverageKind::BlockMarker { id } = coverage.kind {
386+
block_markers[id] = Some(bb);
387+
}
388+
}
389+
}
390+
}
391+
392+
hir_branch_info
393+
.branch_spans
394+
.iter()
395+
.filter_map(|&BranchSpan { span: raw_span, true_marker, false_marker }| {
396+
// For now, ignore any branch span that was introduced by
397+
// expansion. This makes things like assert macros less noisy.
398+
if !raw_span.ctxt().outer_expn_data().is_root() {
399+
return None;
400+
}
401+
let (span, _) = unexpand_into_body_span_with_visible_macro(raw_span, body_span)?;
402+
403+
let bcb_from_marker = |marker: BlockMarkerId| {
404+
Some(basic_coverage_blocks.bcb_from_bb(block_markers[marker]?)?)
405+
};
406+
407+
let true_bcb = bcb_from_marker(true_marker)?;
408+
let false_bcb = bcb_from_marker(false_marker)?;
409+
410+
Some(BcbMapping { kind: BcbMappingKind::Branch { true_bcb, false_bcb }, span })
411+
})
412+
.collect::<Vec<_>>()
413+
}

0 commit comments

Comments
 (0)