Skip to content

Commit 5cee303

Browse files
committed
coverage: Data structures for recording branch info during MIR building
1 parent 7422880 commit 5cee303

File tree

6 files changed

+94
-4
lines changed

6 files changed

+94
-4
lines changed

compiler/rustc_middle/src/mir/coverage.rs

+17-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
33
use rustc_index::IndexVec;
44
use rustc_macros::HashStable;
5-
use rustc_span::Symbol;
5+
use rustc_span::{Span, Symbol};
66

77
use std::fmt::{self, Debug, Formatter};
88

@@ -93,7 +93,7 @@ pub enum CoverageKind {
9393
SpanMarker,
9494

9595
/// Marks its enclosing basic block with an ID that can be referred to by
96-
/// other data in the MIR body.
96+
/// side data in [`HirBranchInfo`].
9797
///
9898
/// Has no effect during codegen.
9999
BlockMarker { id: BlockMarkerId },
@@ -218,3 +218,18 @@ pub struct FunctionCoverageInfo {
218218
pub expressions: IndexVec<ExpressionId, Expression>,
219219
pub mappings: Vec<Mapping>,
220220
}
221+
222+
#[derive(Clone, Debug)]
223+
#[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)]
224+
pub struct HirBranchInfo {
225+
pub num_block_markers: usize,
226+
pub branch_spans: Vec<BranchSpan>,
227+
}
228+
229+
#[derive(Clone, Debug)]
230+
#[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)]
231+
pub struct BranchSpan {
232+
pub span: Span,
233+
pub true_marker: BlockMarkerId,
234+
pub false_marker: BlockMarkerId,
235+
}

compiler/rustc_middle/src/mir/mod.rs

+8
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,12 @@ pub struct Body<'tcx> {
401401

402402
pub tainted_by_errors: Option<ErrorGuaranteed>,
403403

404+
/// Branch coverage information collected during MIR building, to be used by
405+
/// the `InstrumentCoverage` pass.
406+
///
407+
/// Only present if branch coverage is enabled and this function is eligible.
408+
pub coverage_hir_branch_info: Option<Box<coverage::HirBranchInfo>>,
409+
404410
/// Per-function coverage information added by the `InstrumentCoverage`
405411
/// pass, to be used in conjunction with the coverage statements injected
406412
/// into this body's blocks.
@@ -448,6 +454,7 @@ impl<'tcx> Body<'tcx> {
448454
is_polymorphic: false,
449455
injection_phase: None,
450456
tainted_by_errors,
457+
coverage_hir_branch_info: None,
451458
function_coverage_info: None,
452459
};
453460
body.is_polymorphic = body.has_non_region_param();
@@ -477,6 +484,7 @@ impl<'tcx> Body<'tcx> {
477484
is_polymorphic: false,
478485
injection_phase: None,
479486
tainted_by_errors: None,
487+
coverage_hir_branch_info: None,
480488
function_coverage_info: None,
481489
};
482490
body.is_polymorphic = body.has_non_region_param();

compiler/rustc_middle/src/mir/pretty.rs

+22
Original file line numberDiff line numberDiff line change
@@ -461,13 +461,35 @@ pub fn write_mir_intro<'tcx>(
461461
// Add an empty line before the first block is printed.
462462
writeln!(w)?;
463463

464+
if let Some(coverage_hir_branch_info) = &body.coverage_hir_branch_info {
465+
write_coverage_hir_branch_info(coverage_hir_branch_info, w)?;
466+
}
464467
if let Some(function_coverage_info) = &body.function_coverage_info {
465468
write_function_coverage_info(function_coverage_info, w)?;
466469
}
467470

468471
Ok(())
469472
}
470473

474+
fn write_coverage_hir_branch_info(
475+
coverage_hir_branch_info: &coverage::HirBranchInfo,
476+
w: &mut dyn io::Write,
477+
) -> io::Result<()> {
478+
let coverage::HirBranchInfo { branch_spans, .. } = coverage_hir_branch_info;
479+
480+
for coverage::BranchSpan { span, true_marker, false_marker } in branch_spans {
481+
writeln!(
482+
w,
483+
"{INDENT}coverage branch {{ true: {true_marker:?}, false: {false_marker:?} }} => {span:?}",
484+
)?;
485+
}
486+
if !branch_spans.is_empty() {
487+
writeln!(w)?;
488+
}
489+
490+
Ok(())
491+
}
492+
471493
fn write_function_coverage_info(
472494
function_coverage_info: &coverage::FunctionCoverageInfo,
473495
w: &mut dyn io::Write,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
use rustc_middle::mir;
2+
use rustc_middle::mir::coverage::BranchSpan;
3+
use rustc_middle::ty::TyCtxt;
4+
use rustc_span::def_id::LocalDefId;
5+
6+
pub(crate) struct HirBranchInfoBuilder {
7+
num_block_markers: usize,
8+
branch_spans: Vec<BranchSpan>,
9+
}
10+
11+
impl HirBranchInfoBuilder {
12+
/// Creates a new branch info builder, but only if branch coverage instrumentation
13+
/// is enabled and `def_id` represents a function that is eligible for coverage.
14+
pub(crate) fn new_if_enabled(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<Self> {
15+
if tcx.sess.instrument_coverage_branch() && tcx.is_eligible_for_coverage(def_id) {
16+
Some(Self {
17+
// (placeholder)
18+
num_block_markers: 0,
19+
branch_spans: vec![],
20+
})
21+
} else {
22+
None
23+
}
24+
}
25+
26+
pub(crate) fn into_done(self) -> Option<Box<mir::coverage::HirBranchInfo>> {
27+
let Self { num_block_markers, branch_spans } = self;
28+
29+
if num_block_markers == 0 {
30+
assert!(branch_spans.is_empty());
31+
return None;
32+
}
33+
34+
Some(Box::new(mir::coverage::HirBranchInfo { num_block_markers, branch_spans }))
35+
}
36+
}

compiler/rustc_mir_build/src/build/custom/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ pub(super) fn build_custom_mir<'tcx>(
6060
tainted_by_errors: None,
6161
injection_phase: None,
6262
pass_count: 0,
63+
coverage_hir_branch_info: None,
6364
function_coverage_info: None,
6465
};
6566

compiler/rustc_mir_build/src/build/mod.rs

+10-2
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,10 @@ struct Builder<'a, 'tcx> {
234234
// the root (most of them do) and saves us from retracing many sub-paths
235235
// many times, and rechecking many nodes.
236236
lint_level_roots_cache: GrowableBitSet<hir::ItemLocalId>,
237+
238+
/// Collects additional coverage information during MIR building.
239+
/// Only present if branch coverage is enabled and this function is eligible.
240+
coverage_branch_info: Option<coverageinfo::HirBranchInfoBuilder>,
237241
}
238242

239243
type CaptureMap<'tcx> = SortedIndexMultiMap<usize, hir::HirId, Capture<'tcx>>;
@@ -807,6 +811,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
807811
unit_temp: None,
808812
var_debug_info: vec![],
809813
lint_level_roots_cache: GrowableBitSet::new_empty(),
814+
coverage_branch_info: coverageinfo::HirBranchInfoBuilder::new_if_enabled(tcx, def),
810815
};
811816

812817
assert_eq!(builder.cfg.start_new_block(), START_BLOCK);
@@ -826,7 +831,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
826831
}
827832
}
828833

829-
Body::new(
834+
let mut body = Body::new(
830835
MirSource::item(self.def_id.to_def_id()),
831836
self.cfg.basic_blocks,
832837
self.source_scopes,
@@ -837,7 +842,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
837842
self.fn_span,
838843
self.coroutine,
839844
None,
840-
)
845+
);
846+
body.coverage_hir_branch_info = self.coverage_branch_info.and_then(|b| b.into_done());
847+
body
841848
}
842849

843850
fn insert_upvar_arg(&mut self) {
@@ -1111,6 +1118,7 @@ pub(crate) fn parse_float_into_scalar(
11111118

11121119
mod block;
11131120
mod cfg;
1121+
mod coverageinfo;
11141122
mod custom;
11151123
mod expr;
11161124
mod matches;

0 commit comments

Comments
 (0)