1
Fork 0

coverage: Dismantle Instrumentor into ordinary functions

This commit is contained in:
Zalathar 2024-01-24 12:57:11 +11:00
parent 0b7730105f
commit 83ef18cd6c

View file

@ -59,38 +59,22 @@ impl<'tcx> MirPass<'tcx> for InstrumentCoverage {
_ => {} _ => {}
} }
trace!("InstrumentCoverage starting for {def_id:?}"); instrument_function_for_coverage(tcx, mir_body);
Instrumentor::new(tcx, mir_body).inject_counters();
trace!("InstrumentCoverage done for {def_id:?}");
} }
} }
struct Instrumentor<'a, 'tcx> { fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir::Body<'tcx>) {
tcx: TyCtxt<'tcx>, let def_id = mir_body.source.def_id();
mir_body: &'a mut mir::Body<'tcx>, let _span = debug_span!("instrument_function_for_coverage", ?def_id).entered();
hir_info: ExtractedHirInfo,
basic_coverage_blocks: CoverageGraph,
}
impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
fn new(tcx: TyCtxt<'tcx>, mir_body: &'a mut mir::Body<'tcx>) -> Self {
let hir_info = extract_hir_info(tcx, mir_body.source.def_id().expect_local());
debug!(?hir_info, "instrumenting {:?}", mir_body.source.def_id());
let hir_info = extract_hir_info(tcx, def_id.expect_local());
let basic_coverage_blocks = CoverageGraph::from_mir(mir_body); let basic_coverage_blocks = CoverageGraph::from_mir(mir_body);
Self { tcx, mir_body, hir_info, basic_coverage_blocks }
}
fn inject_counters(&'a mut self) {
//////////////////////////////////////////////////// ////////////////////////////////////////////////////
// Compute coverage spans from the `CoverageGraph`. // Compute coverage spans from the `CoverageGraph`.
let Some(coverage_spans) = CoverageSpans::generate_coverage_spans( let Some(coverage_spans) =
self.mir_body, CoverageSpans::generate_coverage_spans(mir_body, &hir_info, &basic_coverage_blocks)
&self.hir_info, else {
&self.basic_coverage_blocks,
) else {
// No relevant spans were found in MIR, so skip instrumenting this function. // No relevant spans were found in MIR, so skip instrumenting this function.
return; return;
}; };
@ -101,45 +85,48 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
// and all `Expression` dependencies (operands) are also generated, for any other // and all `Expression` dependencies (operands) are also generated, for any other
// `BasicCoverageBlock`s not already associated with a coverage span. // `BasicCoverageBlock`s not already associated with a coverage span.
let bcb_has_coverage_spans = |bcb| coverage_spans.bcb_has_coverage_spans(bcb); let bcb_has_coverage_spans = |bcb| coverage_spans.bcb_has_coverage_spans(bcb);
let coverage_counters = CoverageCounters::make_bcb_counters( let coverage_counters =
&self.basic_coverage_blocks, CoverageCounters::make_bcb_counters(&basic_coverage_blocks, bcb_has_coverage_spans);
bcb_has_coverage_spans,
);
let mappings = self.create_mappings(&coverage_spans, &coverage_counters); let mappings = create_mappings(tcx, &hir_info, &coverage_spans, &coverage_counters);
if mappings.is_empty() { if mappings.is_empty() {
// No spans could be converted into valid mappings, so skip this function. // No spans could be converted into valid mappings, so skip this function.
debug!("no spans could be converted into valid mappings; skipping"); debug!("no spans could be converted into valid mappings; skipping");
return; return;
} }
self.inject_coverage_statements(bcb_has_coverage_spans, &coverage_counters); inject_coverage_statements(
mir_body,
&basic_coverage_blocks,
bcb_has_coverage_spans,
&coverage_counters,
);
self.mir_body.function_coverage_info = Some(Box::new(FunctionCoverageInfo { mir_body.function_coverage_info = Some(Box::new(FunctionCoverageInfo {
function_source_hash: self.hir_info.function_source_hash, function_source_hash: hir_info.function_source_hash,
num_counters: coverage_counters.num_counters(), num_counters: coverage_counters.num_counters(),
expressions: coverage_counters.into_expressions(), expressions: coverage_counters.into_expressions(),
mappings, mappings,
})); }));
} }
/// For each coverage span extracted from MIR, create a corresponding /// For each coverage span extracted from MIR, create a corresponding
/// mapping. /// mapping.
/// ///
/// Precondition: All BCBs corresponding to those spans have been given /// Precondition: All BCBs corresponding to those spans have been given
/// coverage counters. /// coverage counters.
fn create_mappings( fn create_mappings<'tcx>(
&self, tcx: TyCtxt<'tcx>,
hir_info: &ExtractedHirInfo,
coverage_spans: &CoverageSpans, coverage_spans: &CoverageSpans,
coverage_counters: &CoverageCounters, coverage_counters: &CoverageCounters,
) -> Vec<Mapping> { ) -> Vec<Mapping> {
let source_map = self.tcx.sess.source_map(); let source_map = tcx.sess.source_map();
let body_span = self.hir_info.body_span; let body_span = hir_info.body_span;
let source_file = source_map.lookup_source_file(body_span.lo()); let source_file = source_map.lookup_source_file(body_span.lo());
use rustc_session::RemapFileNameExt; use rustc_session::RemapFileNameExt;
let file_name = let file_name = Symbol::intern(&source_file.name.for_codegen(tcx.sess).to_string_lossy());
Symbol::intern(&source_file.name.for_codegen(self.tcx.sess).to_string_lossy());
let term_for_bcb = |bcb| { let term_for_bcb = |bcb| {
coverage_counters coverage_counters
@ -158,15 +145,16 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
Some(Mapping { kind, code_region }) Some(Mapping { kind, code_region })
}) })
.collect::<Vec<_>>() .collect::<Vec<_>>()
} }
/// For each BCB node or BCB edge that has an associated coverage counter, /// For each BCB node or BCB edge that has an associated coverage counter,
/// inject any necessary coverage statements into MIR. /// inject any necessary coverage statements into MIR.
fn inject_coverage_statements( fn inject_coverage_statements<'tcx>(
&mut self, mir_body: &mut mir::Body<'tcx>,
basic_coverage_blocks: &CoverageGraph,
bcb_has_coverage_spans: impl Fn(BasicCoverageBlock) -> bool, bcb_has_coverage_spans: impl Fn(BasicCoverageBlock) -> bool,
coverage_counters: &CoverageCounters, coverage_counters: &CoverageCounters,
) { ) {
// Process the counters associated with BCB nodes. // Process the counters associated with BCB nodes.
for (bcb, counter_kind) in coverage_counters.bcb_node_counters() { for (bcb, counter_kind) in coverage_counters.bcb_node_counters() {
let do_inject = match counter_kind { let do_inject = match counter_kind {
@ -179,9 +167,9 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
}; };
if do_inject { if do_inject {
inject_statement( inject_statement(
self.mir_body, mir_body,
self.make_mir_coverage_kind(counter_kind), make_mir_coverage_kind(counter_kind),
self.basic_coverage_blocks[bcb].leader_bb(), basic_coverage_blocks[bcb].leader_bb(),
); );
} }
} }
@ -201,26 +189,25 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
// We need to inject a coverage statement into a new BB between the // We need to inject a coverage statement into a new BB between the
// last BB of `from_bcb` and the first BB of `to_bcb`. // last BB of `from_bcb` and the first BB of `to_bcb`.
let from_bb = self.basic_coverage_blocks[from_bcb].last_bb(); let from_bb = basic_coverage_blocks[from_bcb].last_bb();
let to_bb = self.basic_coverage_blocks[to_bcb].leader_bb(); let to_bb = basic_coverage_blocks[to_bcb].leader_bb();
let new_bb = inject_edge_counter_basic_block(self.mir_body, from_bb, to_bb); let new_bb = inject_edge_counter_basic_block(mir_body, from_bb, to_bb);
debug!( debug!(
"Edge {from_bcb:?} (last {from_bb:?}) -> {to_bcb:?} (leader {to_bb:?}) \ "Edge {from_bcb:?} (last {from_bb:?}) -> {to_bcb:?} (leader {to_bb:?}) \
requires a new MIR BasicBlock {new_bb:?} for edge counter {counter_kind:?}", requires a new MIR BasicBlock {new_bb:?} for edge counter {counter_kind:?}",
); );
// Inject a counter into the newly-created BB. // Inject a counter into the newly-created BB.
inject_statement(self.mir_body, self.make_mir_coverage_kind(counter_kind), new_bb); inject_statement(mir_body, make_mir_coverage_kind(counter_kind), new_bb);
}
} }
}
fn make_mir_coverage_kind(&self, counter_kind: &BcbCounter) -> CoverageKind { fn make_mir_coverage_kind(counter_kind: &BcbCounter) -> CoverageKind {
match *counter_kind { match *counter_kind {
BcbCounter::Counter { id } => CoverageKind::CounterIncrement { id }, BcbCounter::Counter { id } => CoverageKind::CounterIncrement { id },
BcbCounter::Expression { id } => CoverageKind::ExpressionUsed { id }, BcbCounter::Expression { id } => CoverageKind::ExpressionUsed { id },
} }
}
} }
fn inject_edge_counter_basic_block( fn inject_edge_counter_basic_block(