coverage: Replace bcb_has_multiple_in_edges
with sole_predecessor
This does a better job of expressing the special cases that occur when a node in the coverage graph has exactly one in-edge.
This commit is contained in:
parent
e24310b07c
commit
669327f575
2 changed files with 29 additions and 34 deletions
|
@ -364,10 +364,13 @@ impl<'a> MakeBcbCounters<'a> {
|
||||||
);
|
);
|
||||||
|
|
||||||
debug!("{expression_to_bcb:?} gets an expression: {expression:?}");
|
debug!("{expression_to_bcb:?} gets an expression: {expression:?}");
|
||||||
if self.basic_coverage_blocks.bcb_has_multiple_in_edges(expression_to_bcb) {
|
if let Some(sole_pred) = self.basic_coverage_blocks.sole_predecessor(expression_to_bcb) {
|
||||||
self.coverage_counters.set_bcb_edge_counter(from_bcb, expression_to_bcb, expression);
|
// This edge normally wouldn't get its own counter, so attach the expression
|
||||||
} else {
|
// to its target node instead, so that `edge_has_no_counter` can see it.
|
||||||
|
assert_eq!(sole_pred, from_bcb);
|
||||||
self.coverage_counters.set_bcb_counter(expression_to_bcb, expression);
|
self.coverage_counters.set_bcb_counter(expression_to_bcb, expression);
|
||||||
|
} else {
|
||||||
|
self.coverage_counters.set_bcb_edge_counter(from_bcb, expression_to_bcb, expression);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -413,10 +416,12 @@ impl<'a> MakeBcbCounters<'a> {
|
||||||
from_bcb: BasicCoverageBlock,
|
from_bcb: BasicCoverageBlock,
|
||||||
to_bcb: BasicCoverageBlock,
|
to_bcb: BasicCoverageBlock,
|
||||||
) -> BcbCounter {
|
) -> BcbCounter {
|
||||||
// If the target BCB has only one in-edge (i.e. this one), then create
|
// If the target node has exactly one in-edge (i.e. this one), then just
|
||||||
// a node counter instead, since it will have the same value.
|
// use the node's counter, since it will have the same value.
|
||||||
if !self.basic_coverage_blocks.bcb_has_multiple_in_edges(to_bcb) {
|
if let Some(sole_pred) = self.basic_coverage_blocks.sole_predecessor(to_bcb) {
|
||||||
assert_eq!([from_bcb].as_slice(), self.basic_coverage_blocks.predecessors[to_bcb]);
|
assert_eq!(sole_pred, from_bcb);
|
||||||
|
// This call must take care not to invoke `get_or_make_edge` for
|
||||||
|
// this edge, since that would result in infinite recursion!
|
||||||
return self.get_or_make_node_counter(to_bcb);
|
return self.get_or_make_node_counter(to_bcb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -508,18 +513,14 @@ impl<'a> MakeBcbCounters<'a> {
|
||||||
from_bcb: BasicCoverageBlock,
|
from_bcb: BasicCoverageBlock,
|
||||||
to_bcb: BasicCoverageBlock,
|
to_bcb: BasicCoverageBlock,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
self.edge_counter(from_bcb, to_bcb).is_none()
|
let edge_counter =
|
||||||
}
|
if let Some(sole_pred) = self.basic_coverage_blocks.sole_predecessor(to_bcb) {
|
||||||
|
assert_eq!(sole_pred, from_bcb);
|
||||||
fn edge_counter(
|
self.coverage_counters.bcb_counters[to_bcb]
|
||||||
&self,
|
|
||||||
from_bcb: BasicCoverageBlock,
|
|
||||||
to_bcb: BasicCoverageBlock,
|
|
||||||
) -> Option<&BcbCounter> {
|
|
||||||
if self.basic_coverage_blocks.bcb_has_multiple_in_edges(to_bcb) {
|
|
||||||
self.coverage_counters.bcb_edge_counters.get(&(from_bcb, to_bcb))
|
|
||||||
} else {
|
} else {
|
||||||
self.coverage_counters.bcb_counters[to_bcb].as_ref()
|
self.coverage_counters.bcb_edge_counters.get(&(from_bcb, to_bcb)).copied()
|
||||||
}
|
};
|
||||||
|
|
||||||
|
edge_counter.is_none()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -165,21 +165,15 @@ impl CoverageGraph {
|
||||||
self.dominators.as_ref().unwrap().cmp_in_dominator_order(a, b)
|
self.dominators.as_ref().unwrap().cmp_in_dominator_order(a, b)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if the given node has 2 or more in-edges, i.e. 2 or more
|
/// Returns the source of this node's sole in-edge, if it has exactly one.
|
||||||
/// predecessors.
|
/// That edge can be assumed to have the same execution count as the node
|
||||||
///
|
/// itself (in the absence of panics).
|
||||||
/// This property is interesting to code that assigns counters to nodes and
|
pub(crate) fn sole_predecessor(
|
||||||
/// edges, because if a node _doesn't_ have multiple in-edges, then there's
|
&self,
|
||||||
/// no benefit in having a separate counter for its in-edge, because it
|
to_bcb: BasicCoverageBlock,
|
||||||
/// would have the same value as the node's own counter.
|
) -> Option<BasicCoverageBlock> {
|
||||||
#[inline(always)]
|
// Unlike `simple_successor`, there is no need for extra checks here.
|
||||||
pub(crate) fn bcb_has_multiple_in_edges(&self, bcb: BasicCoverageBlock) -> bool {
|
if let &[from_bcb] = self.predecessors[to_bcb].as_slice() { Some(from_bcb) } else { None }
|
||||||
// Even though bcb0 conceptually has an extra virtual in-edge due to
|
|
||||||
// being the entry point, we've already asserted that it has no _other_
|
|
||||||
// in-edges, so there's no possibility of it having _multiple_ in-edges.
|
|
||||||
// (And since its virtual in-edge doesn't exist in the graph, that edge
|
|
||||||
// can't have a separate counter anyway.)
|
|
||||||
self.predecessors[bcb].len() > 1
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the target of this node's sole out-edge, if it has exactly
|
/// Returns the target of this node's sole out-edge, if it has exactly
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue