Skip to content

Commit 986db13

Browse files
committed
coverage: Use the sorted expansion tree to determine min/max BCBs
1 parent 7a3e5cd commit 986db13

3 files changed

Lines changed: 49 additions & 41 deletions

File tree

compiler/rustc_mir_transform/src/coverage/expansion.rs

Lines changed: 45 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use itertools::Itertools;
12
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet, IndexEntry};
23
use rustc_middle::mir;
34
use rustc_middle::mir::coverage::{BasicCoverageBlock, BranchSpan};
@@ -23,38 +24,6 @@ impl ExpnTree {
2324
pub(crate) fn get(&self, expn_id: ExpnId) -> Option<&ExpnNode> {
2425
self.nodes.get(&expn_id)
2526
}
26-
27-
/// Yields the tree node for the given expansion ID (if present), followed
28-
/// by the nodes of all of its descendants in depth-first order.
29-
pub(crate) fn iter_node_and_descendants(
30-
&self,
31-
root_expn_id: ExpnId,
32-
) -> impl Iterator<Item = &ExpnNode> {
33-
gen move {
34-
let Some(root_node) = self.get(root_expn_id) else { return };
35-
yield root_node;
36-
37-
// Stack of child-node-ID iterators that drives the depth-first traversal.
38-
let mut iter_stack = vec![root_node.child_expn_ids.iter()];
39-
40-
while let Some(curr_iter) = iter_stack.last_mut() {
41-
// Pull the next ID from the top of the stack.
42-
let Some(&curr_id) = curr_iter.next() else {
43-
iter_stack.pop();
44-
continue;
45-
};
46-
47-
// Yield this node.
48-
let Some(node) = self.get(curr_id) else { continue };
49-
yield node;
50-
51-
// Push the node's children, to be traversed next.
52-
if !node.child_expn_ids.is_empty() {
53-
iter_stack.push(node.child_expn_ids.iter());
54-
}
55-
}
56-
}
57-
}
5827
}
5928

6029
#[derive(Debug)]
@@ -85,6 +54,10 @@ pub(crate) struct ExpnNode {
8554
pub(crate) spans: Vec<SpanWithBcb>,
8655
/// Expansions whose call-site is in this expansion.
8756
pub(crate) child_expn_ids: FxIndexSet<ExpnId>,
57+
/// The "minimum" and "maximum" BCBs (in dominator order) of ordinary spans
58+
/// belonging to this tree node and all of its descendants. Used when
59+
/// creating a single code mapping representing an entire child expansion.
60+
pub(crate) minmax_bcbs: Option<MinMaxBcbs>,
8861

8962
/// Branch spans (recorded during MIR building) belonging to this expansion.
9063
pub(crate) branch_spans: Vec<BranchSpan>,
@@ -114,6 +87,7 @@ impl ExpnNode {
11487

11588
spans: vec![],
11689
child_expn_ids: FxIndexSet::default(),
90+
minmax_bcbs: None,
11791

11892
branch_spans: vec![],
11993

@@ -164,6 +138,17 @@ pub(crate) fn build_expn_tree(
164138
// Sort the tree nodes into depth-first order.
165139
sort_nodes_depth_first(&mut nodes)?;
166140

141+
// For each node, determine its "minimum" and "maximum" BCBs, based on its
142+
// own spans and its immediate children. This relies on the nodes having
143+
// been sorted, so that each node's children are processed before the node
144+
// itself.
145+
for i in (0..nodes.len()).rev() {
146+
// Computing a node's min/max BCBs requires a shared ref to other nodes.
147+
let minmax_bcbs = minmax_bcbs_for_expn_tree_node(graph, &nodes, &nodes[i]);
148+
// Now we can mutate the current node to set its min/max BCBs.
149+
nodes[i].minmax_bcbs = minmax_bcbs;
150+
}
151+
167152
// If we have a span for the function signature, associate it with the
168153
// corresponding expansion tree node.
169154
if let Some(fn_sig_span) = hir_info.fn_sig_span
@@ -225,3 +210,31 @@ fn sort_nodes_depth_first(nodes: &mut FxIndexMap<ExpnId, ExpnNode>) -> Result<()
225210

226211
Ok(())
227212
}
213+
214+
#[derive(Clone, Copy, Debug)]
215+
pub(crate) struct MinMaxBcbs {
216+
pub(crate) min: BasicCoverageBlock,
217+
pub(crate) max: BasicCoverageBlock,
218+
}
219+
220+
/// For a single node in the expansion tree, compute its "minimum" and "maximum"
221+
/// BCBs (in dominator order), from among the BCBs of its immediate spans,
222+
/// and the min/max of its immediate children.
223+
fn minmax_bcbs_for_expn_tree_node(
224+
graph: &CoverageGraph,
225+
nodes: &FxIndexMap<ExpnId, ExpnNode>,
226+
node: &ExpnNode,
227+
) -> Option<MinMaxBcbs> {
228+
let immediate_span_bcbs = node.spans.iter().map(|sp: &SpanWithBcb| sp.bcb);
229+
let child_minmax_bcbs = node
230+
.child_expn_ids
231+
.iter()
232+
.flat_map(|id| nodes.get(id))
233+
.flat_map(|child| child.minmax_bcbs)
234+
.flat_map(|MinMaxBcbs { min, max }| [min, max]);
235+
236+
let (min, max) = Iterator::chain(immediate_span_bcbs, child_minmax_bcbs)
237+
.minmax_by(|&a, &b| graph.cmp_in_dominator_order(a, b))
238+
.into_option()?;
239+
Some(MinMaxBcbs { min, max })
240+
}

compiler/rustc_mir_transform/src/coverage/spans.rs

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,7 @@ pub(super) fn extract_refined_covspans<'tcx>(
3939
// For each expansion with its call-site in the body span, try to
4040
// distill a corresponding covspan.
4141
for &child_expn_id in &node.child_expn_ids {
42-
if let Some(covspan) = single_covspan_for_child_expn(tcx, graph, &expn_tree, child_expn_id)
43-
{
42+
if let Some(covspan) = single_covspan_for_child_expn(tcx, &expn_tree, child_expn_id) {
4443
covspans.push(covspan);
4544
}
4645
}
@@ -127,24 +126,21 @@ pub(super) fn extract_refined_covspans<'tcx>(
127126
/// For a single child expansion, try to distill it into a single span+BCB mapping.
128127
fn single_covspan_for_child_expn(
129128
tcx: TyCtxt<'_>,
130-
graph: &CoverageGraph,
131129
expn_tree: &ExpnTree,
132130
expn_id: ExpnId,
133131
) -> Option<Covspan> {
134132
let node = expn_tree.get(expn_id)?;
135-
136-
let bcbs =
137-
expn_tree.iter_node_and_descendants(expn_id).flat_map(|n| n.spans.iter().map(|s| s.bcb));
133+
let minmax_bcbs = node.minmax_bcbs?;
138134

139135
let bcb = match node.expn_kind {
140136
// For bang-macros (e.g. `assert!`, `trace!`) and for `await`, taking
141137
// the "first" BCB in dominator order seems to give good results.
142138
ExpnKind::Macro(MacroKind::Bang, _) | ExpnKind::Desugaring(DesugaringKind::Await) => {
143-
bcbs.min_by(|&a, &b| graph.cmp_in_dominator_order(a, b))?
139+
minmax_bcbs.min
144140
}
145141
// For other kinds of expansion, taking the "last" (most-dominated) BCB
146142
// seems to give good results.
147-
_ => bcbs.max_by(|&a, &b| graph.cmp_in_dominator_order(a, b))?,
143+
_ => minmax_bcbs.max,
148144
};
149145

150146
// For bang-macro expansions, limit the call-site span to just the macro

compiler/rustc_mir_transform/src/lib.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
#![feature(const_type_name)]
66
#![feature(cow_is_borrowed)]
77
#![feature(file_buffered)]
8-
#![feature(gen_blocks)]
98
#![feature(if_let_guard)]
109
#![feature(impl_trait_in_assoc_type)]
1110
#![feature(try_blocks)]

0 commit comments

Comments
 (0)