summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_mir_transform/src/coverage/counters.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-07 05:48:48 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-07 05:48:48 +0000
commitef24de24a82fe681581cc130f342363c47c0969a (patch)
tree0d494f7e1a38b95c92426f58fe6eaa877303a86c /compiler/rustc_mir_transform/src/coverage/counters.rs
parentReleasing progress-linux version 1.74.1+dfsg1-1~progress7.99u1. (diff)
downloadrustc-ef24de24a82fe681581cc130f342363c47c0969a.tar.xz
rustc-ef24de24a82fe681581cc130f342363c47c0969a.zip
Merging upstream version 1.75.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_mir_transform/src/coverage/counters.rs')
-rw-r--r--compiler/rustc_mir_transform/src/coverage/counters.rs437
1 files changed, 153 insertions, 284 deletions
diff --git a/compiler/rustc_mir_transform/src/coverage/counters.rs b/compiler/rustc_mir_transform/src/coverage/counters.rs
index d56d4ad4f..b34ec95b4 100644
--- a/compiler/rustc_mir_transform/src/coverage/counters.rs
+++ b/compiler/rustc_mir_transform/src/coverage/counters.rs
@@ -1,10 +1,6 @@
-use super::Error;
-
use super::graph;
-use super::spans;
use graph::{BasicCoverageBlock, BcbBranch, CoverageGraph, TraverseCoverageGraphWithLoops};
-use spans::CoverageSpan;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::graph::WithNumNodes;
@@ -14,14 +10,12 @@ use rustc_middle::mir::coverage::*;
use std::fmt::{self, Debug};
-const NESTED_INDENT: &str = " ";
-
/// The coverage counter or counter expression associated with a particular
/// BCB node or BCB edge.
#[derive(Clone)]
pub(super) enum BcbCounter {
Counter { id: CounterId },
- Expression { id: ExpressionId, lhs: Operand, op: Op, rhs: Operand },
+ Expression { id: ExpressionId },
}
impl BcbCounter {
@@ -29,10 +23,10 @@ impl BcbCounter {
matches!(self, Self::Expression { .. })
}
- pub(super) fn as_operand(&self) -> Operand {
+ pub(super) fn as_term(&self) -> CovTerm {
match *self {
- BcbCounter::Counter { id, .. } => Operand::Counter(id),
- BcbCounter::Expression { id, .. } => Operand::Expression(id),
+ BcbCounter::Counter { id, .. } => CovTerm::Counter(id),
+ BcbCounter::Expression { id, .. } => CovTerm::Expression(id),
}
}
}
@@ -41,17 +35,7 @@ impl Debug for BcbCounter {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Counter { id, .. } => write!(fmt, "Counter({:?})", id.index()),
- Self::Expression { id, lhs, op, rhs } => write!(
- fmt,
- "Expression({:?}) = {:?} {} {:?}",
- id.index(),
- lhs,
- match op {
- Op::Add => "+",
- Op::Subtract => "-",
- },
- rhs,
- ),
+ Self::Expression { id } => write!(fmt, "Expression({:?})", id.index()),
}
}
}
@@ -60,7 +44,6 @@ impl Debug for BcbCounter {
/// associated with nodes/edges in the BCB graph.
pub(super) struct CoverageCounters {
next_counter_id: CounterId,
- next_expression_id: ExpressionId,
/// Coverage counters/expressions that are associated with individual BCBs.
bcb_counters: IndexVec<BasicCoverageBlock, Option<BcbCounter>>,
@@ -68,13 +51,12 @@ pub(super) struct CoverageCounters {
/// edge between two BCBs.
bcb_edge_counters: FxHashMap<(BasicCoverageBlock, BasicCoverageBlock), BcbCounter>,
/// Tracks which BCBs have a counter associated with some incoming edge.
- /// Only used by debug assertions, to verify that BCBs with incoming edge
+ /// Only used by assertions, to verify that BCBs with incoming edge
/// counters do not have their own physical counters (expressions are allowed).
bcb_has_incoming_edge_counters: BitSet<BasicCoverageBlock>,
- /// Expression nodes that are not directly associated with any particular
- /// BCB/edge, but are needed as operands to more complex expressions.
- /// These are always [`BcbCounter::Expression`].
- pub(super) intermediate_expressions: Vec<BcbCounter>,
+ /// Table of expression data, associating each expression ID with its
+ /// corresponding operator (+ or -) and its LHS/RHS operands.
+ expressions: IndexVec<ExpressionId, Expression>,
}
impl CoverageCounters {
@@ -83,24 +65,22 @@ impl CoverageCounters {
Self {
next_counter_id: CounterId::START,
- next_expression_id: ExpressionId::START,
-
bcb_counters: IndexVec::from_elem_n(None, num_bcbs),
bcb_edge_counters: FxHashMap::default(),
bcb_has_incoming_edge_counters: BitSet::new_empty(num_bcbs),
- intermediate_expressions: Vec::new(),
+ expressions: IndexVec::new(),
}
}
/// Makes [`BcbCounter`] `Counter`s and `Expressions` for the `BasicCoverageBlock`s directly or
- /// indirectly associated with `CoverageSpans`, and accumulates additional `Expression`s
+ /// indirectly associated with coverage spans, and accumulates additional `Expression`s
/// representing intermediate values.
pub fn make_bcb_counters(
&mut self,
basic_coverage_blocks: &CoverageGraph,
- coverage_spans: &[CoverageSpan],
- ) -> Result<(), Error> {
- MakeBcbCounters::new(self, basic_coverage_blocks).make_bcb_counters(coverage_spans)
+ bcb_has_coverage_spans: impl Fn(BasicCoverageBlock) -> bool,
+ ) {
+ MakeBcbCounters::new(self, basic_coverage_blocks).make_bcb_counters(bcb_has_coverage_spans)
}
fn make_counter(&mut self) -> BcbCounter {
@@ -108,50 +88,44 @@ impl CoverageCounters {
BcbCounter::Counter { id }
}
- fn make_expression(&mut self, lhs: Operand, op: Op, rhs: Operand) -> BcbCounter {
- let id = self.next_expression();
- BcbCounter::Expression { id, lhs, op, rhs }
- }
-
- pub fn make_identity_counter(&mut self, counter_operand: Operand) -> BcbCounter {
- self.make_expression(counter_operand, Op::Add, Operand::Zero)
+ fn make_expression(&mut self, lhs: CovTerm, op: Op, rhs: CovTerm) -> BcbCounter {
+ let id = self.expressions.push(Expression { lhs, op, rhs });
+ BcbCounter::Expression { id }
}
/// Counter IDs start from one and go up.
fn next_counter(&mut self) -> CounterId {
let next = self.next_counter_id;
- self.next_counter_id = next.next_id();
+ self.next_counter_id = self.next_counter_id + 1;
next
}
- /// Expression IDs start from 0 and go up.
- /// (Counter IDs and Expression IDs are distinguished by the `Operand` enum.)
- fn next_expression(&mut self) -> ExpressionId {
- let next = self.next_expression_id;
- self.next_expression_id = next.next_id();
- next
+ pub(super) fn num_counters(&self) -> usize {
+ self.next_counter_id.as_usize()
}
- fn set_bcb_counter(
- &mut self,
- bcb: BasicCoverageBlock,
- counter_kind: BcbCounter,
- ) -> Result<Operand, Error> {
- debug_assert!(
+ #[cfg(test)]
+ pub(super) fn num_expressions(&self) -> usize {
+ self.expressions.len()
+ }
+
+ fn set_bcb_counter(&mut self, bcb: BasicCoverageBlock, counter_kind: BcbCounter) -> CovTerm {
+ assert!(
// If the BCB has an edge counter (to be injected into a new `BasicBlock`), it can also
// have an expression (to be injected into an existing `BasicBlock` represented by this
// `BasicCoverageBlock`).
counter_kind.is_expression() || !self.bcb_has_incoming_edge_counters.contains(bcb),
"attempt to add a `Counter` to a BCB target with existing incoming edge counters"
);
- let operand = counter_kind.as_operand();
+
+ let term = counter_kind.as_term();
if let Some(replaced) = self.bcb_counters[bcb].replace(counter_kind) {
- Error::from_string(format!(
+ bug!(
"attempt to set a BasicCoverageBlock coverage counter more than once; \
{bcb:?} already had counter {replaced:?}",
- ))
+ );
} else {
- Ok(operand)
+ term
}
}
@@ -160,27 +134,26 @@ impl CoverageCounters {
from_bcb: BasicCoverageBlock,
to_bcb: BasicCoverageBlock,
counter_kind: BcbCounter,
- ) -> Result<Operand, Error> {
- if level_enabled!(tracing::Level::DEBUG) {
- // If the BCB has an edge counter (to be injected into a new `BasicBlock`), it can also
- // have an expression (to be injected into an existing `BasicBlock` represented by this
- // `BasicCoverageBlock`).
- if self.bcb_counter(to_bcb).is_some_and(|c| !c.is_expression()) {
- return Error::from_string(format!(
- "attempt to add an incoming edge counter from {from_bcb:?} when the target BCB already \
- has a `Counter`"
- ));
- }
+ ) -> CovTerm {
+ // If the BCB has an edge counter (to be injected into a new `BasicBlock`), it can also
+ // have an expression (to be injected into an existing `BasicBlock` represented by this
+ // `BasicCoverageBlock`).
+ if let Some(node_counter) = self.bcb_counter(to_bcb) && !node_counter.is_expression() {
+ bug!(
+ "attempt to add an incoming edge counter from {from_bcb:?} \
+ when the target BCB already has {node_counter:?}"
+ );
}
+
self.bcb_has_incoming_edge_counters.insert(to_bcb);
- let operand = counter_kind.as_operand();
+ let term = counter_kind.as_term();
if let Some(replaced) = self.bcb_edge_counters.insert((from_bcb, to_bcb), counter_kind) {
- Error::from_string(format!(
+ bug!(
"attempt to set an edge counter more than once; from_bcb: \
{from_bcb:?} already had counter {replaced:?}",
- ))
+ );
} else {
- Ok(operand)
+ term
}
}
@@ -188,27 +161,31 @@ impl CoverageCounters {
self.bcb_counters[bcb].as_ref()
}
- pub(super) fn take_bcb_counter(&mut self, bcb: BasicCoverageBlock) -> Option<BcbCounter> {
- self.bcb_counters[bcb].take()
+ pub(super) fn bcb_node_counters(
+ &self,
+ ) -> impl Iterator<Item = (BasicCoverageBlock, &BcbCounter)> {
+ self.bcb_counters
+ .iter_enumerated()
+ .filter_map(|(bcb, counter_kind)| Some((bcb, counter_kind.as_ref()?)))
}
- pub(super) fn drain_bcb_counters(
- &mut self,
- ) -> impl Iterator<Item = (BasicCoverageBlock, BcbCounter)> + '_ {
- self.bcb_counters
- .iter_enumerated_mut()
- .filter_map(|(bcb, counter)| Some((bcb, counter.take()?)))
+ /// For each edge in the BCB graph that has an associated counter, yields
+ /// that edge's *from* and *to* nodes, and its counter.
+ pub(super) fn bcb_edge_counters(
+ &self,
+ ) -> impl Iterator<Item = (BasicCoverageBlock, BasicCoverageBlock, &BcbCounter)> {
+ self.bcb_edge_counters
+ .iter()
+ .map(|(&(from_bcb, to_bcb), counter_kind)| (from_bcb, to_bcb, counter_kind))
}
- pub(super) fn drain_bcb_edge_counters(
- &mut self,
- ) -> impl Iterator<Item = ((BasicCoverageBlock, BasicCoverageBlock), BcbCounter)> + '_ {
- self.bcb_edge_counters.drain()
+ pub(super) fn take_expressions(&mut self) -> IndexVec<ExpressionId, Expression> {
+ std::mem::take(&mut self.expressions)
}
}
/// Traverse the `CoverageGraph` and add either a `Counter` or `Expression` to every BCB, to be
-/// injected with `CoverageSpan`s. `Expressions` have no runtime overhead, so if a viable expression
+/// injected with coverage spans. `Expressions` have no runtime overhead, so if a viable expression
/// (adding or subtracting two other counters or expressions) can compute the same result as an
/// embedded counter, an `Expression` should be used.
struct MakeBcbCounters<'a> {
@@ -230,21 +207,11 @@ impl<'a> MakeBcbCounters<'a> {
/// One way to predict which branch executes the least is by considering loops. A loop is exited
/// at a branch, so the branch that jumps to a `BasicCoverageBlock` outside the loop is almost
/// always executed less than the branch that does not exit the loop.
- ///
- /// Returns any non-code-span expressions created to represent intermediate values (such as to
- /// add two counters so the result can be subtracted from another counter), or an Error with
- /// message for subsequent debugging.
- fn make_bcb_counters(&mut self, coverage_spans: &[CoverageSpan]) -> Result<(), Error> {
+ fn make_bcb_counters(&mut self, bcb_has_coverage_spans: impl Fn(BasicCoverageBlock) -> bool) {
debug!("make_bcb_counters(): adding a counter or expression to each BasicCoverageBlock");
- let num_bcbs = self.basic_coverage_blocks.num_nodes();
-
- let mut bcbs_with_coverage = BitSet::new_empty(num_bcbs);
- for covspan in coverage_spans {
- bcbs_with_coverage.insert(covspan.bcb);
- }
// Walk the `CoverageGraph`. For each `BasicCoverageBlock` node with an associated
- // `CoverageSpan`, add a counter. If the `BasicCoverageBlock` branches, add a counter or
+ // coverage span, add a counter. If the `BasicCoverageBlock` branches, add a counter or
// expression to each branch `BasicCoverageBlock` (if the branch BCB has only one incoming
// edge) or edge from the branching BCB to the branch BCB (if the branch BCB has multiple
// incoming edges).
@@ -254,39 +221,36 @@ impl<'a> MakeBcbCounters<'a> {
// the loop. The `traversal` state includes a `context_stack`, providing a way to know if
// the current BCB is in one or more nested loops or not.
let mut traversal = TraverseCoverageGraphWithLoops::new(&self.basic_coverage_blocks);
- while let Some(bcb) = traversal.next(self.basic_coverage_blocks) {
- if bcbs_with_coverage.contains(bcb) {
- debug!("{:?} has at least one `CoverageSpan`. Get or make its counter", bcb);
- let branching_counter_operand = self.get_or_make_counter_operand(bcb)?;
+ while let Some(bcb) = traversal.next() {
+ if bcb_has_coverage_spans(bcb) {
+ debug!("{:?} has at least one coverage span. Get or make its counter", bcb);
+ let branching_counter_operand = self.get_or_make_counter_operand(bcb);
if self.bcb_needs_branch_counters(bcb) {
- self.make_branch_counters(&mut traversal, bcb, branching_counter_operand)?;
+ self.make_branch_counters(&traversal, bcb, branching_counter_operand);
}
} else {
debug!(
- "{:?} does not have any `CoverageSpan`s. A counter will only be added if \
+ "{:?} does not have any coverage spans. A counter will only be added if \
and when a covered BCB has an expression dependency.",
bcb,
);
}
}
- if traversal.is_complete() {
- Ok(())
- } else {
- Error::from_string(format!(
- "`TraverseCoverageGraphWithLoops` missed some `BasicCoverageBlock`s: {:?}",
- traversal.unvisited(),
- ))
- }
+ assert!(
+ traversal.is_complete(),
+ "`TraverseCoverageGraphWithLoops` missed some `BasicCoverageBlock`s: {:?}",
+ traversal.unvisited(),
+ );
}
fn make_branch_counters(
&mut self,
- traversal: &mut TraverseCoverageGraphWithLoops,
+ traversal: &TraverseCoverageGraphWithLoops<'_>,
branching_bcb: BasicCoverageBlock,
- branching_counter_operand: Operand,
- ) -> Result<(), Error> {
+ branching_counter_operand: CovTerm,
+ ) {
let branches = self.bcb_branches(branching_bcb);
debug!(
"{:?} has some branch(es) without counters:\n {}",
@@ -319,10 +283,10 @@ impl<'a> MakeBcbCounters<'a> {
counter",
branch, branching_bcb
);
- self.get_or_make_counter_operand(branch.target_bcb)?
+ self.get_or_make_counter_operand(branch.target_bcb)
} else {
debug!(" {:?} has multiple incoming edges, so adding an edge counter", branch);
- self.get_or_make_edge_counter_operand(branching_bcb, branch.target_bcb)?
+ self.get_or_make_edge_counter_operand(branching_bcb, branch.target_bcb)
};
if let Some(sumup_counter_operand) =
some_sumup_counter_operand.replace(branch_counter_operand)
@@ -333,8 +297,7 @@ impl<'a> MakeBcbCounters<'a> {
sumup_counter_operand,
);
debug!(" [new intermediate expression: {:?}]", intermediate_expression);
- let intermediate_expression_operand = intermediate_expression.as_operand();
- self.coverage_counters.intermediate_expressions.push(intermediate_expression);
+ let intermediate_expression_operand = intermediate_expression.as_term();
some_sumup_counter_operand.replace(intermediate_expression_operand);
}
}
@@ -358,31 +321,18 @@ impl<'a> MakeBcbCounters<'a> {
debug!("{:?} gets an expression: {:?}", expression_branch, expression);
let bcb = expression_branch.target_bcb;
if expression_branch.is_only_path_to_target() {
- self.coverage_counters.set_bcb_counter(bcb, expression)?;
+ self.coverage_counters.set_bcb_counter(bcb, expression);
} else {
- self.coverage_counters.set_bcb_edge_counter(branching_bcb, bcb, expression)?;
+ self.coverage_counters.set_bcb_edge_counter(branching_bcb, bcb, expression);
}
- Ok(())
- }
-
- fn get_or_make_counter_operand(&mut self, bcb: BasicCoverageBlock) -> Result<Operand, Error> {
- self.recursive_get_or_make_counter_operand(bcb, 1)
}
- fn recursive_get_or_make_counter_operand(
- &mut self,
- bcb: BasicCoverageBlock,
- debug_indent_level: usize,
- ) -> Result<Operand, Error> {
+ #[instrument(level = "debug", skip(self))]
+ fn get_or_make_counter_operand(&mut self, bcb: BasicCoverageBlock) -> CovTerm {
// If the BCB already has a counter, return it.
if let Some(counter_kind) = &self.coverage_counters.bcb_counters[bcb] {
- debug!(
- "{}{:?} already has a counter: {:?}",
- NESTED_INDENT.repeat(debug_indent_level),
- bcb,
- counter_kind,
- );
- return Ok(counter_kind.as_operand());
+ debug!("{bcb:?} already has a counter: {counter_kind:?}");
+ return counter_kind.as_term();
}
// A BCB with only one incoming edge gets a simple `Counter` (via `make_counter()`).
@@ -392,20 +342,12 @@ impl<'a> MakeBcbCounters<'a> {
if one_path_to_target || self.bcb_predecessors(bcb).contains(&bcb) {
let counter_kind = self.coverage_counters.make_counter();
if one_path_to_target {
- debug!(
- "{}{:?} gets a new counter: {:?}",
- NESTED_INDENT.repeat(debug_indent_level),
- bcb,
- counter_kind,
- );
+ debug!("{bcb:?} gets a new counter: {counter_kind:?}");
} else {
debug!(
- "{}{:?} has itself as its own predecessor. It can't be part of its own \
- Expression sum, so it will get its own new counter: {:?}. (Note, the compiled \
- code will generate an infinite loop.)",
- NESTED_INDENT.repeat(debug_indent_level),
- bcb,
- counter_kind,
+ "{bcb:?} has itself as its own predecessor. It can't be part of its own \
+ Expression sum, so it will get its own new counter: {counter_kind:?}. \
+ (Note, the compiled code will generate an infinite loop.)",
);
}
return self.coverage_counters.set_bcb_counter(bcb, counter_kind);
@@ -415,24 +357,14 @@ impl<'a> MakeBcbCounters<'a> {
// counters and/or expressions of its incoming edges. This will recursively get or create
// counters for those incoming edges first, then call `make_expression()` to sum them up,
// with additional intermediate expressions as needed.
+ let _sumup_debug_span = debug_span!("(preparing sum-up expression)").entered();
+
let mut predecessors = self.bcb_predecessors(bcb).to_owned().into_iter();
- debug!(
- "{}{:?} has multiple incoming edges and will get an expression that sums them up...",
- NESTED_INDENT.repeat(debug_indent_level),
- bcb,
- );
- let first_edge_counter_operand = self.recursive_get_or_make_edge_counter_operand(
- predecessors.next().unwrap(),
- bcb,
- debug_indent_level + 1,
- )?;
+ let first_edge_counter_operand =
+ self.get_or_make_edge_counter_operand(predecessors.next().unwrap(), bcb);
let mut some_sumup_edge_counter_operand = None;
for predecessor in predecessors {
- let edge_counter_operand = self.recursive_get_or_make_edge_counter_operand(
- predecessor,
- bcb,
- debug_indent_level + 1,
- )?;
+ let edge_counter_operand = self.get_or_make_edge_counter_operand(predecessor, bcb);
if let Some(sumup_edge_counter_operand) =
some_sumup_edge_counter_operand.replace(edge_counter_operand)
{
@@ -441,13 +373,8 @@ impl<'a> MakeBcbCounters<'a> {
Op::Add,
edge_counter_operand,
);
- debug!(
- "{}new intermediate expression: {:?}",
- NESTED_INDENT.repeat(debug_indent_level),
- intermediate_expression
- );
- let intermediate_expression_operand = intermediate_expression.as_operand();
- self.coverage_counters.intermediate_expressions.push(intermediate_expression);
+ debug!("new intermediate expression: {intermediate_expression:?}");
+ let intermediate_expression_operand = intermediate_expression.as_term();
some_sumup_edge_counter_operand.replace(intermediate_expression_operand);
}
}
@@ -456,59 +383,36 @@ impl<'a> MakeBcbCounters<'a> {
Op::Add,
some_sumup_edge_counter_operand.unwrap(),
);
- debug!(
- "{}{:?} gets a new counter (sum of predecessor counters): {:?}",
- NESTED_INDENT.repeat(debug_indent_level),
- bcb,
- counter_kind
- );
+ drop(_sumup_debug_span);
+
+ debug!("{bcb:?} gets a new counter (sum of predecessor counters): {counter_kind:?}");
self.coverage_counters.set_bcb_counter(bcb, counter_kind)
}
+ #[instrument(level = "debug", skip(self))]
fn get_or_make_edge_counter_operand(
&mut self,
from_bcb: BasicCoverageBlock,
to_bcb: BasicCoverageBlock,
- ) -> Result<Operand, Error> {
- self.recursive_get_or_make_edge_counter_operand(from_bcb, to_bcb, 1)
- }
-
- fn recursive_get_or_make_edge_counter_operand(
- &mut self,
- from_bcb: BasicCoverageBlock,
- to_bcb: BasicCoverageBlock,
- debug_indent_level: usize,
- ) -> Result<Operand, Error> {
+ ) -> CovTerm {
// If the source BCB has only one successor (assumed to be the given target), an edge
// counter is unnecessary. Just get or make a counter for the source BCB.
let successors = self.bcb_successors(from_bcb).iter();
if successors.len() == 1 {
- return self.recursive_get_or_make_counter_operand(from_bcb, debug_indent_level + 1);
+ return self.get_or_make_counter_operand(from_bcb);
}
// If the edge already has a counter, return it.
if let Some(counter_kind) =
self.coverage_counters.bcb_edge_counters.get(&(from_bcb, to_bcb))
{
- debug!(
- "{}Edge {:?}->{:?} already has a counter: {:?}",
- NESTED_INDENT.repeat(debug_indent_level),
- from_bcb,
- to_bcb,
- counter_kind
- );
- return Ok(counter_kind.as_operand());
+ debug!("Edge {from_bcb:?}->{to_bcb:?} already has a counter: {counter_kind:?}");
+ return counter_kind.as_term();
}
// Make a new counter to count this edge.
let counter_kind = self.coverage_counters.make_counter();
- debug!(
- "{}Edge {:?}->{:?} gets a new counter: {:?}",
- NESTED_INDENT.repeat(debug_indent_level),
- from_bcb,
- to_bcb,
- counter_kind
- );
+ debug!("Edge {from_bcb:?}->{to_bcb:?} gets a new counter: {counter_kind:?}");
self.coverage_counters.set_bcb_edge_counter(from_bcb, to_bcb, counter_kind)
}
@@ -516,21 +420,14 @@ impl<'a> MakeBcbCounters<'a> {
/// found, select any branch.
fn choose_preferred_expression_branch(
&self,
- traversal: &TraverseCoverageGraphWithLoops,
+ traversal: &TraverseCoverageGraphWithLoops<'_>,
branches: &[BcbBranch],
) -> BcbBranch {
- let branch_needs_a_counter = |branch: &BcbBranch| self.branch_has_no_counter(branch);
-
- let some_reloop_branch = self.find_some_reloop_branch(traversal, &branches);
- if let Some(reloop_branch_without_counter) =
- some_reloop_branch.filter(branch_needs_a_counter)
- {
- debug!(
- "Selecting reloop_branch={:?} that still needs a counter, to get the \
- `Expression`",
- reloop_branch_without_counter
- );
- reloop_branch_without_counter
+ let good_reloop_branch = self.find_good_reloop_branch(traversal, &branches);
+ if let Some(reloop_branch) = good_reloop_branch {
+ assert!(self.branch_has_no_counter(&reloop_branch));
+ debug!("Selecting reloop branch {reloop_branch:?} to get an expression");
+ reloop_branch
} else {
let &branch_without_counter =
branches.iter().find(|&branch| self.branch_has_no_counter(branch)).expect(
@@ -547,75 +444,52 @@ impl<'a> MakeBcbCounters<'a> {
}
}
- /// At most, one of the branches (or its edge, from the branching_bcb, if the branch has
- /// multiple incoming edges) can have a counter computed by expression.
- ///
- /// If at least one of the branches leads outside of a loop (`found_loop_exit` is
- /// true), and at least one other branch does not exit the loop (the first of which
- /// is captured in `some_reloop_branch`), it's likely any reloop branch will be
- /// executed far more often than loop exit branch, making the reloop branch a better
- /// candidate for an expression.
- fn find_some_reloop_branch(
+ /// Tries to find a branch that leads back to the top of a loop, and that
+ /// doesn't already have a counter. Such branches are good candidates to
+ /// be given an expression (instead of a physical counter), because they
+ /// will tend to be executed more times than a loop-exit branch.
+ fn find_good_reloop_branch(
&self,
- traversal: &TraverseCoverageGraphWithLoops,
+ traversal: &TraverseCoverageGraphWithLoops<'_>,
branches: &[BcbBranch],
) -> Option<BcbBranch> {
- let branch_needs_a_counter = |branch: &BcbBranch| self.branch_has_no_counter(branch);
-
- let mut some_reloop_branch: Option<BcbBranch> = None;
- for context in traversal.context_stack.iter().rev() {
- if let Some((backedge_from_bcbs, _)) = &context.loop_backedges {
- let mut found_loop_exit = false;
- for &branch in branches.iter() {
- if backedge_from_bcbs.iter().any(|&backedge_from_bcb| {
- self.bcb_dominates(branch.target_bcb, backedge_from_bcb)
- }) {
- if let Some(reloop_branch) = some_reloop_branch {
- if self.branch_has_no_counter(&reloop_branch) {
- // we already found a candidate reloop_branch that still
- // needs a counter
- continue;
- }
- }
- // The path from branch leads back to the top of the loop. Set this
- // branch as the `reloop_branch`. If this branch already has a
- // counter, and we find another reloop branch that doesn't have a
- // counter yet, that branch will be selected as the `reloop_branch`
- // instead.
- some_reloop_branch = Some(branch);
- } else {
- // The path from branch leads outside this loop
- found_loop_exit = true;
- }
- if found_loop_exit
- && some_reloop_branch.filter(branch_needs_a_counter).is_some()
- {
- // Found both a branch that exits the loop and a branch that returns
- // to the top of the loop (`reloop_branch`), and the `reloop_branch`
- // doesn't already have a counter.
- break;
+ // Consider each loop on the current traversal context stack, top-down.
+ for reloop_bcbs in traversal.reloop_bcbs_per_loop() {
+ let mut all_branches_exit_this_loop = true;
+
+ // Try to find a branch that doesn't exit this loop and doesn't
+ // already have a counter.
+ for &branch in branches {
+ // A branch is a reloop branch if it dominates any BCB that has
+ // an edge back to the loop header. (Other branches are exits.)
+ let is_reloop_branch = reloop_bcbs.iter().any(|&reloop_bcb| {
+ self.basic_coverage_blocks.dominates(branch.target_bcb, reloop_bcb)
+ });
+
+ if is_reloop_branch {
+ all_branches_exit_this_loop = false;
+ if self.branch_has_no_counter(&branch) {
+ // We found a good branch to be given an expression.
+ return Some(branch);
}
+ // Keep looking for another reloop branch without a counter.
+ } else {
+ // This branch exits the loop.
}
- if !found_loop_exit {
- debug!(
- "No branches exit the loop, so any branch without an existing \
- counter can have the `Expression`."
- );
- break;
- }
- if some_reloop_branch.is_some() {
- debug!(
- "Found a branch that exits the loop and a branch the loops back to \
- the top of the loop (`reloop_branch`). The `reloop_branch` will \
- get the `Expression`, as long as it still needs a counter."
- );
- break;
- }
- // else all branches exited this loop context, so run the same checks with
- // the outer loop(s)
}
+
+ if !all_branches_exit_this_loop {
+ // We found one or more reloop branches, but all of them already
+ // have counters. Let the caller choose one of the exit branches.
+ debug!("All reloop branches had counters; skip checking the other loops");
+ return None;
+ }
+
+ // All of the branches exit this loop, so keep looking for a good
+ // reloop branch for one of the outer loops.
}
- some_reloop_branch
+
+ None
}
#[inline]
@@ -661,9 +535,4 @@ impl<'a> MakeBcbCounters<'a> {
fn bcb_has_one_path_to_target(&self, bcb: BasicCoverageBlock) -> bool {
self.bcb_predecessors(bcb).len() <= 1
}
-
- #[inline]
- fn bcb_dominates(&self, dom: BasicCoverageBlock, node: BasicCoverageBlock) -> bool {
- self.basic_coverage_blocks.dominates(dom, node)
- }
}