Skip to content

Commit

Permalink
coverage: Data structures for recording branch info during MIR building
Browse files Browse the repository at this point in the history
  • Loading branch information
Zalathar committed Mar 13, 2024
1 parent c921ab1 commit 28c7545
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 4 deletions.
19 changes: 17 additions & 2 deletions compiler/rustc_middle/src/mir/coverage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

use rustc_index::IndexVec;
use rustc_macros::HashStable;
use rustc_span::Symbol;
use rustc_span::{Span, Symbol};

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

Expand Down Expand Up @@ -93,7 +93,7 @@ pub enum CoverageKind {
SpanMarker,

/// Marks its enclosing basic block with an ID that can be referred to by
/// other data in the MIR body.
/// side data in [`HirBranchInfo`].
///
/// Has no effect during codegen.
BlockMarker { id: BlockMarkerId },
Expand Down Expand Up @@ -218,3 +218,18 @@ pub struct FunctionCoverageInfo {
pub expressions: IndexVec<ExpressionId, Expression>,
pub mappings: Vec<Mapping>,
}

#[derive(Clone, Debug)]
#[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)]
pub struct HirBranchInfo {
pub num_block_markers: usize,
pub branch_spans: Vec<BranchSpan>,
}

#[derive(Clone, Debug)]
#[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)]
pub struct BranchSpan {
pub span: Span,
pub true_marker: BlockMarkerId,
pub false_marker: BlockMarkerId,
}
8 changes: 8 additions & 0 deletions compiler/rustc_middle/src/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,12 @@ pub struct Body<'tcx> {

pub tainted_by_errors: Option<ErrorGuaranteed>,

/// Branch coverage information collected during MIR building, to be used by
/// the `InstrumentCoverage` pass.
///
/// Only present if branch coverage is enabled and this function is eligible.
pub coverage_hir_branch_info: Option<Box<coverage::HirBranchInfo>>,

/// Per-function coverage information added by the `InstrumentCoverage`
/// pass, to be used in conjunction with the coverage statements injected
/// into this body's blocks.
Expand Down Expand Up @@ -450,6 +456,7 @@ impl<'tcx> Body<'tcx> {
is_polymorphic: false,
injection_phase: None,
tainted_by_errors,
coverage_hir_branch_info: None,
function_coverage_info: None,
};
body.is_polymorphic = body.has_non_region_param();
Expand Down Expand Up @@ -479,6 +486,7 @@ impl<'tcx> Body<'tcx> {
is_polymorphic: false,
injection_phase: None,
tainted_by_errors: None,
coverage_hir_branch_info: None,
function_coverage_info: None,
};
body.is_polymorphic = body.has_non_region_param();
Expand Down
22 changes: 22 additions & 0 deletions compiler/rustc_middle/src/mir/pretty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -461,13 +461,35 @@ pub fn write_mir_intro<'tcx>(
// Add an empty line before the first block is printed.
writeln!(w)?;

if let Some(coverage_hir_branch_info) = &body.coverage_hir_branch_info {
write_coverage_hir_branch_info(coverage_hir_branch_info, w)?;
}
if let Some(function_coverage_info) = &body.function_coverage_info {
write_function_coverage_info(function_coverage_info, w)?;
}

Ok(())
}

fn write_coverage_hir_branch_info(
coverage_hir_branch_info: &coverage::HirBranchInfo,
w: &mut dyn io::Write,
) -> io::Result<()> {
let coverage::HirBranchInfo { branch_spans, .. } = coverage_hir_branch_info;

for coverage::BranchSpan { span, true_marker, false_marker } in branch_spans {
writeln!(
w,
"{INDENT}coverage branch {{ true: {true_marker:?}, false: {false_marker:?} }} => {span:?}",
)?;
}
if !branch_spans.is_empty() {
writeln!(w)?;
}

Ok(())
}

fn write_function_coverage_info(
function_coverage_info: &coverage::FunctionCoverageInfo,
w: &mut dyn io::Write,
Expand Down
32 changes: 32 additions & 0 deletions compiler/rustc_mir_build/src/build/coverageinfo.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
use rustc_middle::mir;
use rustc_middle::mir::coverage::BranchSpan;
use rustc_middle::ty::TyCtxt;
use rustc_span::def_id::LocalDefId;

pub(crate) struct HirBranchInfoBuilder {
num_block_markers: usize,
branch_spans: Vec<BranchSpan>,
}

impl HirBranchInfoBuilder {
/// Creates a new branch info builder, but only if branch coverage instrumentation
/// is enabled and `def_id` represents a function that is eligible for coverage.
pub(crate) fn new_if_enabled(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<Self> {
if tcx.sess.instrument_coverage_branch() && tcx.is_eligible_for_coverage(def_id) {
Some(Self { num_block_markers: 0, branch_spans: vec![] })
} else {
None
}
}

pub(crate) fn into_done(self) -> Option<Box<mir::coverage::HirBranchInfo>> {
let Self { num_block_markers, branch_spans } = self;

if num_block_markers == 0 {
assert!(branch_spans.is_empty());
return None;
}

Some(Box::new(mir::coverage::HirBranchInfo { num_block_markers, branch_spans }))
}
}
1 change: 1 addition & 0 deletions compiler/rustc_mir_build/src/build/custom/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ pub(super) fn build_custom_mir<'tcx>(
tainted_by_errors: None,
injection_phase: None,
pass_count: 0,
coverage_hir_branch_info: None,
function_coverage_info: None,
};

Expand Down
12 changes: 10 additions & 2 deletions compiler/rustc_mir_build/src/build/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,10 @@ struct Builder<'a, 'tcx> {
// the root (most of them do) and saves us from retracing many sub-paths
// many times, and rechecking many nodes.
lint_level_roots_cache: GrowableBitSet<hir::ItemLocalId>,

/// Collects additional coverage information during MIR building.
/// Only present if branch coverage is enabled and this function is eligible.
coverage_branch_info: Option<coverageinfo::HirBranchInfoBuilder>,
}

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

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

Body::new(
let mut body = Body::new(
MirSource::item(self.def_id.to_def_id()),
self.cfg.basic_blocks,
self.source_scopes,
Expand All @@ -837,7 +842,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
self.fn_span,
self.coroutine,
None,
)
);
body.coverage_hir_branch_info = self.coverage_branch_info.and_then(|b| b.into_done());
body
}

fn insert_upvar_arg(&mut self) {
Expand Down Expand Up @@ -1111,6 +1118,7 @@ pub(crate) fn parse_float_into_scalar(

mod block;
mod cfg;
mod coverageinfo;
mod custom;
mod expr;
mod matches;
Expand Down

0 comments on commit 28c7545

Please sign in to comment.