Skip to content

Commit bb040e6

Browse files
committed
coverage: Data structures for recording branch info during MIR building
1 parent 44006f4 commit bb040e6

File tree

6 files changed

+90
-4
lines changed

6 files changed

+90
-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

@@ -84,7 +84,7 @@ pub enum CoverageKind {
8484
SpanMarker,
8585

8686
/// Marks its enclosing basic block with an ID that can be referred to by
87-
/// other data in the MIR body.
87+
/// side data in [`HirBranchInfo`].
8888
///
8989
/// Has no effect during codegen.
9090
BlockMarker { id: BlockMarkerId },
@@ -210,9 +210,24 @@ pub struct FunctionCoverageInfo {
210210
pub mappings: Vec<Mapping>,
211211
}
212212

213+
#[derive(Clone, Debug)]
214+
#[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)]
215+
pub struct HirBranchInfo {
216+
pub num_block_markers: usize,
217+
pub branch_spans: Vec<BranchSpan>,
218+
}
219+
213220
rustc_index::newtype_index! {
214221
#[derive(HashStable)]
215222
#[encodable]
216223
#[debug_format = "BlockMarkerId({})"]
217224
pub struct BlockMarkerId {}
218225
}
226+
227+
#[derive(Clone, Debug)]
228+
#[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)]
229+
pub struct BranchSpan {
230+
pub span: Span,
231+
pub true_marker: BlockMarkerId,
232+
pub false_marker: BlockMarkerId,
233+
}

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,30 @@
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+
pub(crate) fn new_if_enabled_and_eligible(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<Self> {
13+
if tcx.sess.instrument_coverage_branch() && tcx.is_eligible_for_coverage(def_id) {
14+
Some(Self { num_block_markers: 0, branch_spans: vec![] })
15+
} else {
16+
None
17+
}
18+
}
19+
20+
pub(crate) fn into_done(self) -> Option<Box<mir::coverage::HirBranchInfo>> {
21+
let Self { num_block_markers, branch_spans } = self;
22+
23+
if num_block_markers == 0 {
24+
assert!(branch_spans.is_empty());
25+
return None;
26+
}
27+
28+
Some(Box::new(mir::coverage::HirBranchInfo { num_block_markers, branch_spans }))
29+
}
30+
}

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

+12-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,9 @@ 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_and_eligible(
815+
tcx, def,
816+
),
810817
};
811818

812819
assert_eq!(builder.cfg.start_new_block(), START_BLOCK);
@@ -826,7 +833,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
826833
}
827834
}
828835

829-
Body::new(
836+
let mut body = Body::new(
830837
MirSource::item(self.def_id.to_def_id()),
831838
self.cfg.basic_blocks,
832839
self.source_scopes,
@@ -837,7 +844,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
837844
self.fn_span,
838845
self.coroutine,
839846
None,
840-
)
847+
);
848+
body.coverage_hir_branch_info = self.coverage_branch_info.and_then(|b| b.into_done());
849+
body
841850
}
842851

843852
fn insert_upvar_arg(&mut self) {
@@ -1111,6 +1120,7 @@ pub(crate) fn parse_float_into_scalar(
11111120

11121121
mod block;
11131122
mod cfg;
1123+
mod coverageinfo;
11141124
mod custom;
11151125
mod expr;
11161126
mod matches;

0 commit comments

Comments
 (0)