Skip to content

Commit d7090f3

Browse files
committed
coverage: Use a separate counter type during counter creation
1 parent 44e4e45 commit d7090f3

File tree

1 file changed

+94
-73
lines changed

1 file changed

+94
-73
lines changed

compiler/rustc_mir_transform/src/coverage/counters.rs

+94-73
Original file line numberDiff line numberDiff line change
@@ -63,12 +63,6 @@ pub(super) struct CoverageCounters {
6363

6464
/// Coverage counters/expressions that are associated with individual BCBs.
6565
node_counters: IndexVec<BasicCoverageBlock, Option<BcbCounter>>,
66-
/// Coverage counters/expressions that are associated with the control-flow
67-
/// edge between two BCBs.
68-
///
69-
/// We currently don't iterate over this map, but if we do in the future,
70-
/// switch it back to `FxIndexMap` to avoid query stability hazards.
71-
edge_counters: FxHashMap<(BasicCoverageBlock, BasicCoverageBlock), BcbCounter>,
7266

7367
/// Table of expression data, associating each expression ID with its
7468
/// corresponding operator (+ or -) and its LHS/RHS operands.
@@ -95,7 +89,6 @@ impl CoverageCounters {
9589
Self {
9690
counter_increment_sites: IndexVec::new(),
9791
node_counters: IndexVec::from_elem_n(None, num_bcbs),
98-
edge_counters: FxHashMap::default(),
9992
expressions: IndexVec::new(),
10093
expressions_memo: FxHashMap::default(),
10194
}
@@ -191,20 +184,6 @@ impl CoverageCounters {
191184
counter
192185
}
193186

194-
fn set_edge_counter(
195-
&mut self,
196-
from_bcb: BasicCoverageBlock,
197-
to_bcb: BasicCoverageBlock,
198-
counter: BcbCounter,
199-
) -> BcbCounter {
200-
let existing = self.edge_counters.insert((from_bcb, to_bcb), counter);
201-
assert!(
202-
existing.is_none(),
203-
"edge ({from_bcb:?} -> {to_bcb:?}) already has a counter: {existing:?} => {counter:?}"
204-
);
205-
counter
206-
}
207-
208187
pub(super) fn term_for_bcb(&self, bcb: BasicCoverageBlock) -> Option<CovTerm> {
209188
self.node_counters[bcb].map(|counter| counter.as_term())
210189
}
@@ -250,22 +229,53 @@ impl CoverageCounters {
250229
}
251230
}
252231

232+
/// Symbolic representation of the coverage counter to be used for a particular
233+
/// node or edge in the coverage graph. The same site counter can be used for
234+
/// multiple sites, if they have been determined to have the same count.
235+
#[derive(Clone, Copy, Debug)]
236+
enum SiteCounter {
237+
/// A physical counter at some node/edge.
238+
Phys { site: Site },
239+
/// A counter expression for a node that takes the sum of all its in-edge
240+
/// counters.
241+
NodeSumExpr { bcb: BasicCoverageBlock },
242+
/// A counter expression for an edge that takes the counter of its source
243+
/// node, and subtracts the counters of all its sibling out-edges.
244+
EdgeDiffExpr { from_bcb: BasicCoverageBlock, to_bcb: BasicCoverageBlock },
245+
}
246+
247+
/// Yields the graph successors of `from_bcb` that aren't `to_bcb`. This is
248+
/// used when creating a counter expression for [`SiteCounter::EdgeDiffExpr`].
249+
///
250+
/// For example, in this diagram the sibling out-edge targets of edge `AC` are
251+
/// the nodes `B` and `D`.
252+
///
253+
/// ```text
254+
/// A
255+
/// / | \
256+
/// B C D
257+
/// ```
258+
fn sibling_out_edge_targets(
259+
graph: &CoverageGraph,
260+
from_bcb: BasicCoverageBlock,
261+
to_bcb: BasicCoverageBlock,
262+
) -> impl Iterator<Item = BasicCoverageBlock> + Captures<'_> {
263+
graph.successors[from_bcb].iter().copied().filter(move |&t| t != to_bcb)
264+
}
265+
253266
/// Helper struct that allows counter creation to inspect the BCB graph, and
254267
/// the set of nodes that need counters.
255268
struct CountersBuilder<'a> {
256-
counters: CoverageCounters,
257269
graph: &'a CoverageGraph,
258270
bcb_needs_counter: &'a BitSet<BasicCoverageBlock>,
271+
272+
site_counters: FxHashMap<Site, SiteCounter>,
259273
}
260274

261275
impl<'a> CountersBuilder<'a> {
262276
fn new(graph: &'a CoverageGraph, bcb_needs_counter: &'a BitSet<BasicCoverageBlock>) -> Self {
263277
assert_eq!(graph.num_nodes(), bcb_needs_counter.domain_size());
264-
Self {
265-
counters: CoverageCounters::with_num_bcbs(graph.num_nodes()),
266-
graph,
267-
bcb_needs_counter,
268-
}
278+
Self { graph, bcb_needs_counter, site_counters: FxHashMap::default() }
269279
}
270280

271281
fn make_bcb_counters(&mut self) {
@@ -298,9 +308,7 @@ impl<'a> CountersBuilder<'a> {
298308
fn make_node_counter_and_out_edge_counters(&mut self, from_bcb: BasicCoverageBlock) {
299309
// First, ensure that this node has a counter of some kind.
300310
// We might also use that counter to compute one of the out-edge counters.
301-
let node_counter = self.get_or_make_node_counter(from_bcb);
302-
303-
let successors = self.graph.successors[from_bcb].as_slice();
311+
self.get_or_make_node_counter(from_bcb);
304312

305313
// If this node's out-edges won't sum to the node's counter,
306314
// then there's no reason to create edge counters here.
@@ -311,11 +319,11 @@ impl<'a> CountersBuilder<'a> {
311319
// When choosing which out-edge should be given a counter expression, ignore edges that
312320
// already have counters, or could use the existing counter of their target node.
313321
let out_edge_has_counter = |to_bcb| {
314-
if self.counters.edge_counters.contains_key(&(from_bcb, to_bcb)) {
322+
if self.site_counters.contains_key(&Site::Edge { from_bcb, to_bcb }) {
315323
return true;
316324
}
317325
self.graph.sole_predecessor(to_bcb) == Some(from_bcb)
318-
&& self.counters.node_counters[to_bcb].is_some()
326+
&& self.site_counters.contains_key(&Site::Node { bcb: to_bcb })
319327
};
320328

321329
// Determine the set of out-edges that could benefit from being given an expression.
@@ -328,45 +336,41 @@ impl<'a> CountersBuilder<'a> {
328336

329337
// If there are out-edges without counters, choose one to be given an expression
330338
// (computed from this node and the other out-edges) instead of a physical counter.
331-
let Some(target_bcb) = self.choose_out_edge_for_expression(from_bcb, &candidate_successors)
339+
let Some(to_bcb) = self.choose_out_edge_for_expression(from_bcb, &candidate_successors)
332340
else {
333341
return;
334342
};
335343

336344
// For each out-edge other than the one that was chosen to get an expression,
337345
// ensure that it has a counter (existing counter/expression or a new counter).
338-
let other_out_edge_counters = successors
339-
.iter()
340-
.copied()
341-
// Skip the chosen edge, since we'll calculate its count from this sum.
342-
.filter(|&edge_target_bcb| edge_target_bcb != target_bcb)
343-
.map(|to_bcb| self.get_or_make_edge_counter(from_bcb, to_bcb))
344-
.collect::<Vec<_>>();
346+
for target in sibling_out_edge_targets(self.graph, from_bcb, to_bcb) {
347+
self.get_or_make_edge_counter(from_bcb, target);
348+
}
345349

346350
// Now create an expression for the chosen edge, by taking the counter
347351
// for its source node and subtracting the sum of its sibling out-edges.
348-
let expression = self.counters.make_subtracted_sum(node_counter, &other_out_edge_counters);
349-
350-
debug!("{target_bcb:?} gets an expression: {expression:?}");
351-
self.counters.set_edge_counter(from_bcb, target_bcb, expression);
352+
let counter = SiteCounter::EdgeDiffExpr { from_bcb, to_bcb };
353+
self.site_counters.insert(Site::Edge { from_bcb, to_bcb }, counter);
352354
}
353355

354356
#[instrument(level = "debug", skip(self))]
355-
fn get_or_make_node_counter(&mut self, bcb: BasicCoverageBlock) -> BcbCounter {
357+
fn get_or_make_node_counter(&mut self, bcb: BasicCoverageBlock) -> SiteCounter {
356358
// If the BCB already has a counter, return it.
357-
if let Some(counter) = self.counters.node_counters[bcb] {
359+
if let Some(&counter) = self.site_counters.get(&Site::Node { bcb }) {
358360
debug!("{bcb:?} already has a counter: {counter:?}");
359361
return counter;
360362
}
361363

362364
let counter = self.make_node_counter_inner(bcb);
363-
self.counters.set_node_counter(bcb, counter)
365+
self.site_counters.insert(Site::Node { bcb }, counter);
366+
counter
364367
}
365368

366-
fn make_node_counter_inner(&mut self, bcb: BasicCoverageBlock) -> BcbCounter {
369+
fn make_node_counter_inner(&mut self, bcb: BasicCoverageBlock) -> SiteCounter {
367370
// If the node's sole in-edge already has a counter, use that.
368371
if let Some(sole_pred) = self.graph.sole_predecessor(bcb)
369-
&& let Some(&edge_counter) = self.counters.edge_counters.get(&(sole_pred, bcb))
372+
&& let Some(&edge_counter) =
373+
self.site_counters.get(&Site::Edge { from_bcb: sole_pred, to_bcb: bcb })
370374
{
371375
return edge_counter;
372376
}
@@ -380,20 +384,17 @@ impl<'a> CountersBuilder<'a> {
380384
// leading to infinite recursion.
381385
if predecessors.len() <= 1 || predecessors.contains(&bcb) {
382386
debug!(?bcb, ?predecessors, "node has <=1 predecessors or is its own predecessor");
383-
let counter = self.counters.make_phys_counter(Site::Node { bcb });
387+
let counter = SiteCounter::Phys { site: Site::Node { bcb } };
384388
debug!(?bcb, ?counter, "node gets a physical counter");
385389
return counter;
386390
}
387391

388392
// A BCB with multiple incoming edges can compute its count by ensuring that counters
389393
// exist for each of those edges, and then adding them up to get a total count.
390-
let in_edge_counters = predecessors
391-
.iter()
392-
.copied()
393-
.map(|from_bcb| self.get_or_make_edge_counter(from_bcb, bcb))
394-
.collect::<Vec<_>>();
395-
let sum_of_in_edges: BcbCounter =
396-
self.counters.make_sum(&in_edge_counters).expect("there must be at least one in-edge");
394+
for &from_bcb in predecessors {
395+
self.get_or_make_edge_counter(from_bcb, bcb);
396+
}
397+
let sum_of_in_edges = SiteCounter::NodeSumExpr { bcb };
397398

398399
debug!("{bcb:?} gets a new counter (sum of predecessor counters): {sum_of_in_edges:?}");
399400
sum_of_in_edges
@@ -404,22 +405,23 @@ impl<'a> CountersBuilder<'a> {
404405
&mut self,
405406
from_bcb: BasicCoverageBlock,
406407
to_bcb: BasicCoverageBlock,
407-
) -> BcbCounter {
408+
) -> SiteCounter {
408409
// If the edge already has a counter, return it.
409-
if let Some(&counter) = self.counters.edge_counters.get(&(from_bcb, to_bcb)) {
410+
if let Some(&counter) = self.site_counters.get(&Site::Edge { from_bcb, to_bcb }) {
410411
debug!("Edge {from_bcb:?}->{to_bcb:?} already has a counter: {counter:?}");
411412
return counter;
412413
}
413414

414415
let counter = self.make_edge_counter_inner(from_bcb, to_bcb);
415-
self.counters.set_edge_counter(from_bcb, to_bcb, counter)
416+
self.site_counters.insert(Site::Edge { from_bcb, to_bcb }, counter);
417+
counter
416418
}
417419

418420
fn make_edge_counter_inner(
419421
&mut self,
420422
from_bcb: BasicCoverageBlock,
421423
to_bcb: BasicCoverageBlock,
422-
) -> BcbCounter {
424+
) -> SiteCounter {
423425
// If the target node has exactly one in-edge (i.e. this one), then just
424426
// use the node's counter, since it will have the same value.
425427
if let Some(sole_pred) = self.graph.sole_predecessor(to_bcb) {
@@ -437,7 +439,7 @@ impl<'a> CountersBuilder<'a> {
437439
}
438440

439441
// Make a new counter to count this edge.
440-
let counter = self.counters.make_phys_counter(Site::Edge { from_bcb, to_bcb });
442+
let counter = SiteCounter::Phys { site: Site::Edge { from_bcb, to_bcb } };
441443
debug!(?from_bcb, ?to_bcb, ?counter, "edge gets a physical counter");
442444
counter
443445
}
@@ -525,14 +527,14 @@ impl<'a> Transcriber<'a> {
525527
fn transcribe_counters(mut self) -> CoverageCounters {
526528
for bcb in self.old.bcb_needs_counter.iter() {
527529
let site = Site::Node { bcb };
528-
let Some(old_counter) = self.old.counters.node_counters[bcb] else { continue };
530+
let site_counter = self.site_counter(site);
529531

530-
// Resolve the old counter into flat lists of nodes/edges whose
532+
// Resolve the site counter into flat lists of nodes/edges whose
531533
// physical counts contribute to the counter for this node.
532534
// Distinguish between counts that will be added vs subtracted.
533535
let mut pos = vec![];
534536
let mut neg = vec![];
535-
self.push_resolved_sites(old_counter, &mut pos, &mut neg);
537+
self.push_resolved_sites(site_counter, &mut pos, &mut neg);
536538

537539
// Simplify by cancelling out sites that appear on both sides.
538540
let (mut pos, mut neg) = sort_and_cancel(pos, neg);
@@ -566,22 +568,41 @@ impl<'a> Transcriber<'a> {
566568
self.new
567569
}
568570

571+
fn site_counter(&self, site: Site) -> SiteCounter {
572+
self.old.site_counters.get(&site).copied().unwrap_or_else(|| {
573+
// We should have already created all necessary site counters.
574+
// But if we somehow didn't, avoid crashing in release builds,
575+
// and just use an extra physical counter instead.
576+
debug_assert!(false, "{site:?} should have a counter");
577+
SiteCounter::Phys { site }
578+
})
579+
}
580+
569581
fn ensure_phys_counter(&mut self, site: Site) -> BcbCounter {
570582
*self.phys_counter_for_site.entry(site).or_insert_with(|| self.new.make_phys_counter(site))
571583
}
572584

573585
/// Resolves the given counter into flat lists of nodes/edges, whose counters
574586
/// will then be added and subtracted to form a counter expression.
575-
fn push_resolved_sites(&self, counter: BcbCounter, pos: &mut Vec<Site>, neg: &mut Vec<Site>) {
587+
fn push_resolved_sites(&self, counter: SiteCounter, pos: &mut Vec<Site>, neg: &mut Vec<Site>) {
576588
match counter {
577-
BcbCounter::Counter { id } => pos.push(self.old.counters.counter_increment_sites[id]),
578-
BcbCounter::Expression { id } => {
579-
let BcbExpression { lhs, op, rhs } = self.old.counters.expressions[id];
580-
self.push_resolved_sites(lhs, pos, neg);
581-
match op {
582-
Op::Add => self.push_resolved_sites(rhs, pos, neg),
589+
SiteCounter::Phys { site } => pos.push(site),
590+
SiteCounter::NodeSumExpr { bcb } => {
591+
for &from_bcb in &self.old.graph.predecessors[bcb] {
592+
let edge_counter = self.site_counter(Site::Edge { from_bcb, to_bcb: bcb });
593+
self.push_resolved_sites(edge_counter, pos, neg);
594+
}
595+
}
596+
SiteCounter::EdgeDiffExpr { from_bcb, to_bcb } => {
597+
// First, add the count for `from_bcb`.
598+
let node_counter = self.site_counter(Site::Node { bcb: from_bcb });
599+
self.push_resolved_sites(node_counter, pos, neg);
600+
601+
// Then subtract the counts for the other out-edges.
602+
for target in sibling_out_edge_targets(self.old.graph, from_bcb, to_bcb) {
603+
let edge_counter = self.site_counter(Site::Edge { from_bcb, to_bcb: target });
583604
// Swap `neg` and `pos` so that the counter is subtracted.
584-
Op::Subtract => self.push_resolved_sites(rhs, neg, pos),
605+
self.push_resolved_sites(edge_counter, neg, pos);
585606
}
586607
}
587608
}

0 commit comments

Comments
 (0)