Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 4170b93

Browse files
committed
coverage: Flatten top-level counter creation into plain functions
- Move `make_bcb_counters` out of `CoverageCounters` - Split out `make_node_counter_priority_list` - Flatten `Transcriber` into the function `transcribe_counters`
1 parent 4839944 commit 4170b93

File tree

2 files changed

+91
-95
lines changed

2 files changed

+91
-95
lines changed

compiler/rustc_mir_transform/src/coverage/counters.rs

Lines changed: 90 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,96 @@ mod iter_nodes;
2020
mod node_flow;
2121
mod union_find;
2222

23+
/// Ensures that each BCB node needing a counter has one, by creating physical
24+
/// counters or counter expressions for nodes as required.
25+
pub(super) fn make_bcb_counters(
26+
graph: &CoverageGraph,
27+
bcb_needs_counter: &DenseBitSet<BasicCoverageBlock>,
28+
) -> CoverageCounters {
29+
let balanced_graph = BalancedFlowGraph::for_graph(graph, |n| !graph[n].is_out_summable);
30+
let merged_graph = MergedNodeFlowGraph::for_balanced_graph(&balanced_graph);
31+
32+
let nodes = make_node_counter_priority_list(graph, balanced_graph);
33+
let node_counters = merged_graph.make_node_counters(&nodes);
34+
35+
transcribe_counters(&node_counters, bcb_needs_counter)
36+
}
37+
38+
fn make_node_counter_priority_list(
39+
graph: &CoverageGraph,
40+
balanced_graph: BalancedFlowGraph<&CoverageGraph>,
41+
) -> Vec<BasicCoverageBlock> {
42+
// A "reloop" node has exactly one out-edge, which jumps back to the top
43+
// of an enclosing loop. Reloop nodes are typically visited more times
44+
// than loop-exit nodes, so try to avoid giving them physical counters.
45+
let is_reloop_node = IndexVec::from_fn_n(
46+
|node| match graph.successors[node].as_slice() {
47+
&[succ] => graph.dominates(succ, node),
48+
_ => false,
49+
},
50+
graph.num_nodes(),
51+
);
52+
53+
let mut nodes = balanced_graph.iter_nodes().rev().collect::<Vec<_>>();
54+
// The first node is the sink, which must not get a physical counter.
55+
assert_eq!(nodes[0], balanced_graph.sink);
56+
// Sort the real nodes, such that earlier (lesser) nodes take priority
57+
// in being given a counter expression instead of a physical counter.
58+
nodes[1..].sort_by(|&a, &b| {
59+
// Start with a dummy `Equal` to make the actual tests line up nicely.
60+
Ordering::Equal
61+
// Prefer a physical counter for return/yield nodes.
62+
.then_with(|| Ord::cmp(&graph[a].is_out_summable, &graph[b].is_out_summable))
63+
// Prefer an expression for reloop nodes (see definition above).
64+
.then_with(|| Ord::cmp(&is_reloop_node[a], &is_reloop_node[b]).reverse())
65+
// Otherwise, prefer a physical counter for dominating nodes.
66+
.then_with(|| graph.cmp_in_dominator_order(a, b).reverse())
67+
});
68+
nodes
69+
}
70+
71+
fn transcribe_counters(
72+
old: &NodeCounters<BasicCoverageBlock>,
73+
bcb_needs_counter: &DenseBitSet<BasicCoverageBlock>,
74+
) -> CoverageCounters {
75+
let mut new = CoverageCounters::with_num_bcbs(bcb_needs_counter.domain_size());
76+
77+
for bcb in bcb_needs_counter.iter() {
78+
let (mut pos, mut neg): (Vec<_>, Vec<_>) =
79+
old.counter_expr(bcb).iter().partition_map(|&CounterTerm { node, op }| match op {
80+
Op::Add => Either::Left(node),
81+
Op::Subtract => Either::Right(node),
82+
});
83+
84+
if pos.is_empty() {
85+
// If we somehow end up with no positive terms, fall back to
86+
// creating a physical counter. There's no known way for this
87+
// to happen, but we can avoid an ICE if it does.
88+
debug_assert!(false, "{bcb:?} has no positive counter terms");
89+
pos = vec![bcb];
90+
neg = vec![];
91+
}
92+
93+
pos.sort();
94+
neg.sort();
95+
96+
let mut new_counters_for_sites = |sites: Vec<BasicCoverageBlock>| {
97+
sites.into_iter().map(|node| new.ensure_phys_counter(node)).collect::<Vec<_>>()
98+
};
99+
let mut pos = new_counters_for_sites(pos);
100+
let mut neg = new_counters_for_sites(neg);
101+
102+
pos.sort();
103+
neg.sort();
104+
105+
let pos_counter = new.make_sum(&pos).expect("`pos` should not be empty");
106+
let new_counter = new.make_subtracted_sum(pos_counter, &neg);
107+
new.set_node_counter(bcb, new_counter);
108+
}
109+
110+
new
111+
}
112+
23113
/// The coverage counter or counter expression associated with a particular
24114
/// BCB node or BCB edge.
25115
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
@@ -73,46 +163,6 @@ pub(super) struct CoverageCounters {
73163
}
74164

75165
impl CoverageCounters {
76-
/// Ensures that each BCB node needing a counter has one, by creating physical
77-
/// counters or counter expressions for nodes and edges as required.
78-
pub(super) fn make_bcb_counters(
79-
graph: &CoverageGraph,
80-
bcb_needs_counter: &DenseBitSet<BasicCoverageBlock>,
81-
) -> Self {
82-
let balanced_graph = BalancedFlowGraph::for_graph(graph, |n| !graph[n].is_out_summable);
83-
let merged_graph = MergedNodeFlowGraph::for_balanced_graph(&balanced_graph);
84-
85-
// A "reloop" node has exactly one out-edge, which jumps back to the top
86-
// of an enclosing loop. Reloop nodes are typically visited more times
87-
// than loop-exit nodes, so try to avoid giving them physical counters.
88-
let is_reloop_node = IndexVec::from_fn_n(
89-
|node| match graph.successors[node].as_slice() {
90-
&[succ] => graph.dominates(succ, node),
91-
_ => false,
92-
},
93-
graph.num_nodes(),
94-
);
95-
96-
let mut nodes = balanced_graph.iter_nodes().rev().collect::<Vec<_>>();
97-
// The first node is the sink, which must not get a physical counter.
98-
assert_eq!(nodes[0], balanced_graph.sink);
99-
// Sort the real nodes, such that earlier (lesser) nodes take priority
100-
// in being given a counter expression instead of a physical counter.
101-
nodes[1..].sort_by(|&a, &b| {
102-
// Start with a dummy `Equal` to make the actual tests line up nicely.
103-
Ordering::Equal
104-
// Prefer a physical counter for return/yield nodes.
105-
.then_with(|| Ord::cmp(&graph[a].is_out_summable, &graph[b].is_out_summable))
106-
// Prefer an expression for reloop nodes (see definition above).
107-
.then_with(|| Ord::cmp(&is_reloop_node[a], &is_reloop_node[b]).reverse())
108-
// Otherwise, prefer a physical counter for dominating nodes.
109-
.then_with(|| graph.cmp_in_dominator_order(a, b).reverse())
110-
});
111-
let node_counters = merged_graph.make_node_counters(&nodes);
112-
113-
Transcriber::new(graph.num_nodes(), node_counters).transcribe_counters(bcb_needs_counter)
114-
}
115-
116166
fn with_num_bcbs(num_bcbs: usize) -> Self {
117167
Self {
118168
phys_counter_for_node: FxIndexMap::default(),
@@ -216,56 +266,3 @@ impl CoverageCounters {
216266
expressions
217267
}
218268
}
219-
220-
struct Transcriber {
221-
old: NodeCounters<BasicCoverageBlock>,
222-
new: CoverageCounters,
223-
}
224-
225-
impl Transcriber {
226-
fn new(num_nodes: usize, old: NodeCounters<BasicCoverageBlock>) -> Self {
227-
Self { old, new: CoverageCounters::with_num_bcbs(num_nodes) }
228-
}
229-
230-
fn transcribe_counters(
231-
mut self,
232-
bcb_needs_counter: &DenseBitSet<BasicCoverageBlock>,
233-
) -> CoverageCounters {
234-
for bcb in bcb_needs_counter.iter() {
235-
let (mut pos, mut neg): (Vec<_>, Vec<_>) =
236-
self.old.counter_expr(bcb).iter().partition_map(
237-
|&CounterTerm { node, op }| match op {
238-
Op::Add => Either::Left(node),
239-
Op::Subtract => Either::Right(node),
240-
},
241-
);
242-
243-
if pos.is_empty() {
244-
// If we somehow end up with no positive terms, fall back to
245-
// creating a physical counter. There's no known way for this
246-
// to happen, but we can avoid an ICE if it does.
247-
debug_assert!(false, "{bcb:?} has no positive counter terms");
248-
pos = vec![bcb];
249-
neg = vec![];
250-
}
251-
252-
pos.sort();
253-
neg.sort();
254-
255-
let mut new_counters_for_sites = |sites: Vec<BasicCoverageBlock>| {
256-
sites.into_iter().map(|node| self.new.ensure_phys_counter(node)).collect::<Vec<_>>()
257-
};
258-
let mut pos = new_counters_for_sites(pos);
259-
let mut neg = new_counters_for_sites(neg);
260-
261-
pos.sort();
262-
neg.sort();
263-
264-
let pos_counter = self.new.make_sum(&pos).expect("`pos` should not be empty");
265-
let new_counter = self.new.make_subtracted_sum(pos_counter, &neg);
266-
self.new.set_node_counter(bcb, new_counter);
267-
}
268-
269-
self.new
270-
}
271-
}

compiler/rustc_mir_transform/src/coverage/mod.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,8 +89,7 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir:
8989
return;
9090
}
9191

92-
let coverage_counters =
93-
CoverageCounters::make_bcb_counters(&graph, &bcbs_with_counter_mappings);
92+
let coverage_counters = counters::make_bcb_counters(&graph, &bcbs_with_counter_mappings);
9493

9594
let mappings = create_mappings(&extracted_mappings, &coverage_counters);
9695
if mappings.is_empty() {

0 commit comments

Comments
 (0)