Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

coverage: Prepare mappings separately from injecting statements #119438

Merged
merged 2 commits into from
Dec 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 15 additions & 15 deletions compiler/rustc_mir_transform/src/coverage/counters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,27 +61,27 @@ pub(super) struct CoverageCounters {
}

impl CoverageCounters {
pub(super) fn new(basic_coverage_blocks: &CoverageGraph) -> Self {
/// Makes [`BcbCounter`] `Counter`s and `Expressions` for the `BasicCoverageBlock`s directly or
/// indirectly associated with coverage spans, and accumulates additional `Expression`s
/// representing intermediate values.
pub(super) fn make_bcb_counters(
basic_coverage_blocks: &CoverageGraph,
bcb_has_coverage_spans: impl Fn(BasicCoverageBlock) -> bool,
) -> Self {
let num_bcbs = basic_coverage_blocks.num_nodes();

Self {
let mut this = Self {
next_counter_id: CounterId::START,
bcb_counters: IndexVec::from_elem_n(None, num_bcbs),
bcb_edge_counters: FxIndexMap::default(),
bcb_has_incoming_edge_counters: BitSet::new_empty(num_bcbs),
expressions: IndexVec::new(),
}
}
};

/// Makes [`BcbCounter`] `Counter`s and `Expressions` for the `BasicCoverageBlock`s directly or
/// indirectly associated with coverage spans, and accumulates additional `Expression`s
/// representing intermediate values.
pub fn make_bcb_counters(
&mut self,
basic_coverage_blocks: &CoverageGraph,
bcb_has_coverage_spans: impl Fn(BasicCoverageBlock) -> bool,
) {
MakeBcbCounters::new(self, basic_coverage_blocks).make_bcb_counters(bcb_has_coverage_spans)
MakeBcbCounters::new(&mut this, basic_coverage_blocks)
.make_bcb_counters(bcb_has_coverage_spans);

this
}

fn make_counter(&mut self) -> BcbCounter {
Expand Down Expand Up @@ -189,8 +189,8 @@ impl CoverageCounters {
.map(|(&(from_bcb, to_bcb), counter_kind)| (from_bcb, to_bcb, counter_kind))
}

pub(super) fn take_expressions(&mut self) -> IndexVec<ExpressionId, Expression> {
std::mem::take(&mut self.expressions)
pub(super) fn into_expressions(self) -> IndexVec<ExpressionId, Expression> {
self.expressions
}
}

Expand Down
82 changes: 48 additions & 34 deletions compiler/rustc_mir_transform/src/coverage/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ mod spans;
mod tests;

use self::counters::{BcbCounter, CoverageCounters};
use self::graph::CoverageGraph;
use self::graph::{BasicCoverageBlock, CoverageGraph};
use self::spans::CoverageSpans;

use crate::MirPass;
Expand Down Expand Up @@ -70,7 +70,6 @@ struct Instrumentor<'a, 'tcx> {
mir_body: &'a mut mir::Body<'tcx>,
hir_info: ExtractedHirInfo,
basic_coverage_blocks: CoverageGraph,
coverage_counters: CoverageCounters,
}

impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
Expand All @@ -80,9 +79,8 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
debug!(?hir_info, "instrumenting {:?}", mir_body.source.def_id());

let basic_coverage_blocks = CoverageGraph::from_mir(mir_body);
let coverage_counters = CoverageCounters::new(&basic_coverage_blocks);

Self { tcx, mir_body, hir_info, basic_coverage_blocks, coverage_counters }
Self { tcx, mir_body, hir_info, basic_coverage_blocks }
}

fn inject_counters(&'a mut self) {
Expand All @@ -103,25 +101,31 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
// and all `Expression` dependencies (operands) are also generated, for any other
// `BasicCoverageBlock`s not already associated with a coverage span.
let bcb_has_coverage_spans = |bcb| coverage_spans.bcb_has_coverage_spans(bcb);
self.coverage_counters
.make_bcb_counters(&self.basic_coverage_blocks, bcb_has_coverage_spans);
let coverage_counters = CoverageCounters::make_bcb_counters(
&self.basic_coverage_blocks,
bcb_has_coverage_spans,
);

let mappings = self.create_mappings_and_inject_coverage_statements(&coverage_spans);
let mappings = self.create_mappings(&coverage_spans, &coverage_counters);
self.inject_coverage_statements(bcb_has_coverage_spans, &coverage_counters);

self.mir_body.function_coverage_info = Some(Box::new(FunctionCoverageInfo {
function_source_hash: self.hir_info.function_source_hash,
num_counters: self.coverage_counters.num_counters(),
expressions: self.coverage_counters.take_expressions(),
num_counters: coverage_counters.num_counters(),
expressions: coverage_counters.into_expressions(),
mappings,
}));
}

/// For each [`BcbCounter`] associated with a BCB node or BCB edge, create
/// any corresponding mappings (for BCB nodes only), and inject any necessary
/// coverage statements into MIR.
fn create_mappings_and_inject_coverage_statements(
&mut self,
/// For each coverage span extracted from MIR, create a corresponding
/// mapping.
///
/// Precondition: All BCBs corresponding to those spans have been given
/// coverage counters.
fn create_mappings(
&self,
coverage_spans: &CoverageSpans,
coverage_counters: &CoverageCounters,
) -> Vec<Mapping> {
let source_map = self.tcx.sess.source_map();
let body_span = self.hir_info.body_span;
Expand All @@ -131,30 +135,42 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
let file_name =
Symbol::intern(&source_file.name.for_codegen(self.tcx.sess).to_string_lossy());

let mut mappings = Vec::new();

// Process the counters and spans associated with BCB nodes.
for (bcb, counter_kind) in self.coverage_counters.bcb_node_counters() {
let spans = coverage_spans.spans_for_bcb(bcb);
let has_mappings = !spans.is_empty();

// If this BCB has any coverage spans, add corresponding mappings to
// the mappings table.
if has_mappings {
let term = counter_kind.as_term();
mappings.extend(spans.iter().map(|&span| {
let code_region = make_code_region(source_map, file_name, span, body_span);
Mapping { code_region, term }
}));
}
coverage_spans
.bcbs_with_coverage_spans()
// For each BCB with spans, get a coverage term for its counter.
.map(|(bcb, spans)| {
let term = coverage_counters
.bcb_counter(bcb)
.expect("all BCBs with spans were given counters")
.as_term();
(term, spans)
})
// Flatten the spans into individual term/span pairs.
.flat_map(|(term, spans)| spans.iter().map(move |&span| (term, span)))
// Convert each span to a code region, and create the final mapping.
.map(|(term, span)| {
let code_region = make_code_region(source_map, file_name, span, body_span);
Mapping { term, code_region }
})
.collect::<Vec<_>>()
}

/// For each BCB node or BCB edge that has an associated coverage counter,
/// inject any necessary coverage statements into MIR.
fn inject_coverage_statements(
&mut self,
bcb_has_coverage_spans: impl Fn(BasicCoverageBlock) -> bool,
coverage_counters: &CoverageCounters,
) {
// Process the counters associated with BCB nodes.
for (bcb, counter_kind) in coverage_counters.bcb_node_counters() {
let do_inject = match counter_kind {
// Counter-increment statements always need to be injected.
BcbCounter::Counter { .. } => true,
// The only purpose of expression-used statements is to detect
// when a mapping is unreachable, so we only inject them for
// expressions with one or more mappings.
BcbCounter::Expression { .. } => has_mappings,
BcbCounter::Expression { .. } => bcb_has_coverage_spans(bcb),
};
if do_inject {
inject_statement(
Expand All @@ -166,7 +182,7 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
}

// Process the counters associated with BCB edges.
for (from_bcb, to_bcb, counter_kind) in self.coverage_counters.bcb_edge_counters() {
for (from_bcb, to_bcb, counter_kind) in coverage_counters.bcb_edge_counters() {
let do_inject = match counter_kind {
// Counter-increment statements always need to be injected.
BcbCounter::Counter { .. } => true,
Expand All @@ -192,8 +208,6 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
// Inject a counter into the newly-created BB.
inject_statement(self.mir_body, self.make_mir_coverage_kind(counter_kind), new_bb);
}

mappings
}

fn make_mir_coverage_kind(&self, counter_kind: &BcbCounter) -> CoverageKind {
Expand Down
9 changes: 7 additions & 2 deletions compiler/rustc_mir_transform/src/coverage/spans.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,13 @@ impl CoverageSpans {
!self.bcb_to_spans[bcb].is_empty()
}

pub(super) fn spans_for_bcb(&self, bcb: BasicCoverageBlock) -> &[Span] {
&self.bcb_to_spans[bcb]
pub(super) fn bcbs_with_coverage_spans(
&self,
) -> impl Iterator<Item = (BasicCoverageBlock, &[Span])> {
self.bcb_to_spans.iter_enumerated().filter_map(|(bcb, spans)| {
// Only yield BCBs that have at least one coverage span.
(!spans.is_empty()).then_some((bcb, spans.as_slice()))
})
}
}

Expand Down
6 changes: 4 additions & 2 deletions compiler/rustc_mir_transform/src/coverage/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -630,8 +630,10 @@ fn test_make_bcb_counters() {
// coverage spans for BCBs 1 and 2. Now we skip that step and just tell
// BCB counter construction that those BCBs have spans.
let bcb_has_coverage_spans = |bcb: BasicCoverageBlock| (1..=2).contains(&bcb.as_usize());
let mut coverage_counters = counters::CoverageCounters::new(&basic_coverage_blocks);
coverage_counters.make_bcb_counters(&basic_coverage_blocks, bcb_has_coverage_spans);
let coverage_counters = counters::CoverageCounters::make_bcb_counters(
&basic_coverage_blocks,
bcb_has_coverage_spans,
);
assert_eq!(coverage_counters.num_expressions(), 0);

assert_eq!(
Expand Down
Loading