coverage: Don't create counters for code that was removed by MIR opts

This commit is contained in:
Zalathar 2025-01-25 18:24:02 +11:00
parent 20d051ec87
commit bf1f254b13
10 changed files with 103 additions and 134 deletions

View file

@ -80,28 +80,30 @@ fn make_node_flow_priority_list(
pub(crate) fn transcribe_counters(
old: &NodeCounters<BasicCoverageBlock>,
bcb_needs_counter: &DenseBitSet<BasicCoverageBlock>,
bcbs_seen: &DenseBitSet<BasicCoverageBlock>,
) -> CoverageCounters {
let mut new = CoverageCounters::with_num_bcbs(bcb_needs_counter.domain_size());
for bcb in bcb_needs_counter.iter() {
if !bcbs_seen.contains(bcb) {
// This BCB's code was removed by MIR opts, so its counter is always zero.
new.set_node_counter(bcb, CovTerm::Zero);
continue;
}
// Our counter-creation algorithm doesn't guarantee that a node's list
// of terms starts or ends with a positive term, so partition the
// counters into "positive" and "negative" lists for easier handling.
let (mut pos, mut neg): (Vec<_>, Vec<_>) =
old.counter_terms[bcb].iter().partition_map(|&CounterTerm { node, op }| match op {
let (mut pos, mut neg): (Vec<_>, Vec<_>) = old.counter_terms[bcb]
.iter()
// Filter out any BCBs that were removed by MIR opts;
// this treats them as having an execution count of 0.
.filter(|term| bcbs_seen.contains(term.node))
.partition_map(|&CounterTerm { node, op }| match op {
Op::Add => Either::Left(node),
Op::Subtract => Either::Right(node),
});
if pos.is_empty() {
// If we somehow end up with no positive terms, fall back to
// creating a physical counter. There's no known way for this
// to happen, but we can avoid an ICE if it does.
debug_assert!(false, "{bcb:?} has no positive counter terms");
pos = vec![bcb];
neg = vec![];
}
// These intermediate sorts are not strictly necessary, but were helpful
// in reducing churn when switching to the current counter-creation scheme.
// They also help to slightly decrease the overall size of the expression
@ -119,7 +121,7 @@ pub(crate) fn transcribe_counters(
pos.sort();
neg.sort();
let pos_counter = new.make_sum(&pos).expect("`pos` should not be empty");
let pos_counter = new.make_sum(&pos).unwrap_or(CovTerm::Zero);
let new_counter = new.make_subtracted_sum(pos_counter, &neg);
new.set_node_counter(bcb, new_counter);
}

View file

@ -127,8 +127,12 @@ fn coverage_ids_info<'tcx>(
}
}
// FIXME(Zalathar): It should be possible to sort `priority_list[1..]` by
// `!bcbs_seen.contains(bcb)` to simplify the mappings even further, at the
// expense of some churn in the tests. When doing so, also consider removing
// the sorts in `transcribe_counters`.
let node_counters = make_node_counters(&fn_cov_info.node_flow_data, &fn_cov_info.priority_list);
let coverage_counters = transcribe_counters(&node_counters, &bcb_needs_counter);
let coverage_counters = transcribe_counters(&node_counters, &bcb_needs_counter, &bcbs_seen);
let mut counters_seen = DenseBitSet::new_empty(coverage_counters.node_counters.len());
let mut expressions_seen = DenseBitSet::new_filled(coverage_counters.expressions.len());