summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_mir_transform/src/coverage
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_mir_transform/src/coverage')
-rw-r--r--compiler/rustc_mir_transform/src/coverage/counters.rs354
-rw-r--r--compiler/rustc_mir_transform/src/coverage/debug.rs115
-rw-r--r--compiler/rustc_mir_transform/src/coverage/graph.rs115
-rw-r--r--compiler/rustc_mir_transform/src/coverage/mod.rs182
-rw-r--r--compiler/rustc_mir_transform/src/coverage/query.rs57
-rw-r--r--compiler/rustc_mir_transform/src/coverage/spans.rs7
-rw-r--r--compiler/rustc_mir_transform/src/coverage/test_macros/src/lib.rs2
-rw-r--r--compiler/rustc_mir_transform/src/coverage/tests.rs19
8 files changed, 421 insertions, 430 deletions
diff --git a/compiler/rustc_mir_transform/src/coverage/counters.rs b/compiler/rustc_mir_transform/src/coverage/counters.rs
index 658e01d93..3d442e5dc 100644
--- a/compiler/rustc_mir_transform/src/coverage/counters.rs
+++ b/compiler/rustc_mir_transform/src/coverage/counters.rs
@@ -8,55 +8,116 @@ use debug::{DebugCounters, NESTED_INDENT};
use graph::{BasicCoverageBlock, BcbBranch, CoverageGraph, TraverseCoverageGraphWithLoops};
use spans::CoverageSpan;
+use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::graph::WithNumNodes;
use rustc_index::bit_set::BitSet;
+use rustc_index::IndexVec;
use rustc_middle::mir::coverage::*;
-/// Manages the counter and expression indexes/IDs to generate `CoverageKind` components for MIR
-/// `Coverage` statements.
+use std::fmt::{self, Debug};
+
+/// 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 },
+}
+
+impl BcbCounter {
+ fn is_expression(&self) -> bool {
+ matches!(self, Self::Expression { .. })
+ }
+
+ pub(super) fn as_operand(&self) -> Operand {
+ match *self {
+ BcbCounter::Counter { id, .. } => Operand::Counter(id),
+ BcbCounter::Expression { id, .. } => Operand::Expression(id),
+ }
+ }
+}
+
+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,
+ ),
+ }
+ }
+}
+
+/// Generates and stores coverage counter and coverage expression information
+/// associated with nodes/edges in the BCB graph.
pub(super) struct CoverageCounters {
- function_source_hash: u64,
- next_counter_id: u32,
- num_expressions: u32,
+ next_counter_id: CounterId,
+ next_expression_id: ExpressionId,
+
+ /// Coverage counters/expressions that are associated with individual BCBs.
+ bcb_counters: IndexVec<BasicCoverageBlock, Option<BcbCounter>>,
+ /// Coverage counters/expressions that are associated with the control-flow
+ /// 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
+ /// 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>,
+
pub debug_counters: DebugCounters,
}
impl CoverageCounters {
- pub fn new(function_source_hash: u64) -> Self {
+ pub(super) fn new(basic_coverage_blocks: &CoverageGraph) -> Self {
+ let num_bcbs = basic_coverage_blocks.num_nodes();
+
Self {
- function_source_hash,
- next_counter_id: CounterValueReference::START.as_u32(),
- num_expressions: 0,
+ 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(),
+
debug_counters: DebugCounters::new(),
}
}
/// Activate the `DebugCounters` data structures, to provide additional debug formatting
- /// features when formatting `CoverageKind` (counter) values.
+ /// features when formatting [`BcbCounter`] (counter) values.
pub fn enable_debug(&mut self) {
self.debug_counters.enable();
}
- /// Makes `CoverageKind` `Counter`s and `Expressions` for the `BasicCoverageBlock`s directly or
- /// indirectly associated with `CoverageSpans`, and returns additional `Expression`s
+ /// Makes [`BcbCounter`] `Counter`s and `Expressions` for the `BasicCoverageBlock`s directly or
+ /// indirectly associated with `CoverageSpans`, and accumulates additional `Expression`s
/// representing intermediate values.
pub fn make_bcb_counters(
&mut self,
- basic_coverage_blocks: &mut CoverageGraph,
+ basic_coverage_blocks: &CoverageGraph,
coverage_spans: &[CoverageSpan],
- ) -> Result<Vec<CoverageKind>, Error> {
- let mut bcb_counters = BcbCounters::new(self, basic_coverage_blocks);
- bcb_counters.make_bcb_counters(coverage_spans)
+ ) -> Result<(), Error> {
+ MakeBcbCounters::new(self, basic_coverage_blocks).make_bcb_counters(coverage_spans)
}
- fn make_counter<F>(&mut self, debug_block_label_fn: F) -> CoverageKind
+ fn make_counter<F>(&mut self, debug_block_label_fn: F) -> BcbCounter
where
F: Fn() -> Option<String>,
{
- let counter = CoverageKind::Counter {
- function_source_hash: self.function_source_hash,
- id: self.next_counter(),
- };
+ let counter = BcbCounter::Counter { id: self.next_counter() };
if self.debug_counters.is_enabled() {
self.debug_counters.add_counter(&counter, (debug_block_label_fn)());
}
@@ -65,49 +126,120 @@ impl CoverageCounters {
fn make_expression<F>(
&mut self,
- lhs: ExpressionOperandId,
+ lhs: Operand,
op: Op,
- rhs: ExpressionOperandId,
+ rhs: Operand,
debug_block_label_fn: F,
- ) -> CoverageKind
+ ) -> BcbCounter
where
F: Fn() -> Option<String>,
{
let id = self.next_expression();
- let expression = CoverageKind::Expression { id, lhs, op, rhs };
+ let expression = BcbCounter::Expression { id, lhs, op, rhs };
if self.debug_counters.is_enabled() {
self.debug_counters.add_counter(&expression, (debug_block_label_fn)());
}
expression
}
- pub fn make_identity_counter(&mut self, counter_operand: ExpressionOperandId) -> CoverageKind {
+ pub fn make_identity_counter(&mut self, counter_operand: Operand) -> BcbCounter {
let some_debug_block_label = if self.debug_counters.is_enabled() {
self.debug_counters.some_block_label(counter_operand).cloned()
} else {
None
};
- self.make_expression(counter_operand, Op::Add, ExpressionOperandId::ZERO, || {
+ self.make_expression(counter_operand, Op::Add, Operand::Zero, || {
some_debug_block_label.clone()
})
}
/// Counter IDs start from one and go up.
- fn next_counter(&mut self) -> CounterValueReference {
- assert!(self.next_counter_id < u32::MAX - self.num_expressions);
+ fn next_counter(&mut self) -> CounterId {
let next = self.next_counter_id;
- self.next_counter_id += 1;
- CounterValueReference::from(next)
+ self.next_counter_id = next.next_id();
+ 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
+ }
+
+ fn set_bcb_counter(
+ &mut self,
+ bcb: BasicCoverageBlock,
+ counter_kind: BcbCounter,
+ ) -> Result<Operand, Error> {
+ debug_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();
+ if let Some(replaced) = self.bcb_counters[bcb].replace(counter_kind) {
+ Error::from_string(format!(
+ "attempt to set a BasicCoverageBlock coverage counter more than once; \
+ {bcb:?} already had counter {replaced:?}",
+ ))
+ } else {
+ Ok(operand)
+ }
+ }
+
+ fn set_bcb_edge_counter(
+ &mut self,
+ 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`"
+ ));
+ }
+ }
+ self.bcb_has_incoming_edge_counters.insert(to_bcb);
+ let operand = counter_kind.as_operand();
+ if let Some(replaced) = self.bcb_edge_counters.insert((from_bcb, to_bcb), counter_kind) {
+ Error::from_string(format!(
+ "attempt to set an edge counter more than once; from_bcb: \
+ {from_bcb:?} already had counter {replaced:?}",
+ ))
+ } else {
+ Ok(operand)
+ }
}
- /// Expression IDs start from u32::MAX and go down because an Expression can reference
- /// (add or subtract counts) of both Counter regions and Expression regions. The counter
- /// expression operand IDs must be unique across both types.
- fn next_expression(&mut self) -> InjectedExpressionId {
- assert!(self.next_counter_id < u32::MAX - self.num_expressions);
- let next = u32::MAX - self.num_expressions;
- self.num_expressions += 1;
- InjectedExpressionId::from(next)
+ pub(super) fn bcb_counter(&self, bcb: BasicCoverageBlock) -> Option<&BcbCounter> {
+ 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 drain_bcb_counters(
+ &mut self,
+ ) -> impl Iterator<Item = (BasicCoverageBlock, BcbCounter)> + '_ {
+ self.bcb_counters
+ .iter_enumerated_mut()
+ .filter_map(|(bcb, counter)| Some((bcb, counter.take()?)))
+ }
+
+ pub(super) fn drain_bcb_edge_counters(
+ &mut self,
+ ) -> impl Iterator<Item = ((BasicCoverageBlock, BasicCoverageBlock), BcbCounter)> + '_ {
+ self.bcb_edge_counters.drain()
}
}
@@ -115,15 +247,15 @@ impl CoverageCounters {
/// injected with `CoverageSpan`s. `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 BcbCounters<'a> {
+struct MakeBcbCounters<'a> {
coverage_counters: &'a mut CoverageCounters,
- basic_coverage_blocks: &'a mut CoverageGraph,
+ basic_coverage_blocks: &'a CoverageGraph,
}
-impl<'a> BcbCounters<'a> {
+impl<'a> MakeBcbCounters<'a> {
fn new(
coverage_counters: &'a mut CoverageCounters,
- basic_coverage_blocks: &'a mut CoverageGraph,
+ basic_coverage_blocks: &'a CoverageGraph,
) -> Self {
Self { coverage_counters, basic_coverage_blocks }
}
@@ -138,13 +270,9 @@ impl<'a> BcbCounters<'a> {
/// 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<Vec<CoverageKind>, Error> {
+ fn make_bcb_counters(&mut self, coverage_spans: &[CoverageSpan]) -> Result<(), Error> {
debug!("make_bcb_counters(): adding a counter or expression to each BasicCoverageBlock");
let num_bcbs = self.basic_coverage_blocks.num_nodes();
- let mut collect_intermediate_expressions = Vec::with_capacity(num_bcbs);
let mut bcbs_with_coverage = BitSet::new_empty(num_bcbs);
for covspan in coverage_spans {
@@ -165,16 +293,10 @@ impl<'a> BcbCounters<'a> {
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, &mut collect_intermediate_expressions)?;
+ 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,
- &mut collect_intermediate_expressions,
- )?;
+ self.make_branch_counters(&mut traversal, bcb, branching_counter_operand)?;
}
} else {
debug!(
@@ -186,7 +308,7 @@ impl<'a> BcbCounters<'a> {
}
if traversal.is_complete() {
- Ok(collect_intermediate_expressions)
+ Ok(())
} else {
Error::from_string(format!(
"`TraverseCoverageGraphWithLoops` missed some `BasicCoverageBlock`s: {:?}",
@@ -199,8 +321,7 @@ impl<'a> BcbCounters<'a> {
&mut self,
traversal: &mut TraverseCoverageGraphWithLoops,
branching_bcb: BasicCoverageBlock,
- branching_counter_operand: ExpressionOperandId,
- collect_intermediate_expressions: &mut Vec<CoverageKind>,
+ branching_counter_operand: Operand,
) -> Result<(), Error> {
let branches = self.bcb_branches(branching_bcb);
debug!(
@@ -208,9 +329,7 @@ impl<'a> BcbCounters<'a> {
branching_bcb,
branches
.iter()
- .map(|branch| {
- format!("{:?}: {:?}", branch, branch.counter(&self.basic_coverage_blocks))
- })
+ .map(|branch| { format!("{:?}: {:?}", branch, self.branch_counter(branch)) })
.collect::<Vec<_>>()
.join("\n "),
);
@@ -236,17 +355,10 @@ impl<'a> BcbCounters<'a> {
counter",
branch, branching_bcb
);
- self.get_or_make_counter_operand(
- branch.target_bcb,
- collect_intermediate_expressions,
- )?
+ 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,
- collect_intermediate_expressions,
- )?
+ 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)
@@ -261,8 +373,8 @@ impl<'a> BcbCounters<'a> {
" [new intermediate expression: {}]",
self.format_counter(&intermediate_expression)
);
- let intermediate_expression_operand = intermediate_expression.as_operand_id();
- collect_intermediate_expressions.push(intermediate_expression);
+ let intermediate_expression_operand = intermediate_expression.as_operand();
+ self.coverage_counters.intermediate_expressions.push(intermediate_expression);
some_sumup_counter_operand.replace(intermediate_expression_operand);
}
}
@@ -282,41 +394,36 @@ impl<'a> BcbCounters<'a> {
branching_counter_operand,
Op::Subtract,
sumup_counter_operand,
- || Some(format!("{:?}", expression_branch)),
+ || Some(format!("{expression_branch:?}")),
);
debug!("{:?} gets an expression: {}", expression_branch, self.format_counter(&expression));
let bcb = expression_branch.target_bcb;
if expression_branch.is_only_path_to_target() {
- self.basic_coverage_blocks[bcb].set_counter(expression)?;
+ self.coverage_counters.set_bcb_counter(bcb, expression)?;
} else {
- self.basic_coverage_blocks[bcb].set_edge_counter_from(branching_bcb, expression)?;
+ self.coverage_counters.set_bcb_edge_counter(branching_bcb, bcb, expression)?;
}
Ok(())
}
- fn get_or_make_counter_operand(
- &mut self,
- bcb: BasicCoverageBlock,
- collect_intermediate_expressions: &mut Vec<CoverageKind>,
- ) -> Result<ExpressionOperandId, Error> {
- self.recursive_get_or_make_counter_operand(bcb, collect_intermediate_expressions, 1)
+ 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,
- collect_intermediate_expressions: &mut Vec<CoverageKind>,
debug_indent_level: usize,
- ) -> Result<ExpressionOperandId, Error> {
+ ) -> Result<Operand, Error> {
// If the BCB already has a counter, return it.
- if let Some(counter_kind) = self.basic_coverage_blocks[bcb].counter() {
+ if let Some(counter_kind) = &self.coverage_counters.bcb_counters[bcb] {
debug!(
"{}{:?} already has a counter: {}",
NESTED_INDENT.repeat(debug_indent_level),
bcb,
self.format_counter(counter_kind),
);
- return Ok(counter_kind.as_operand_id());
+ return Ok(counter_kind.as_operand());
}
// A BCB with only one incoming edge gets a simple `Counter` (via `make_counter()`).
@@ -324,7 +431,7 @@ impl<'a> BcbCounters<'a> {
// program results in a tight infinite loop, but it should still compile.
let one_path_to_target = self.bcb_has_one_path_to_target(bcb);
if one_path_to_target || self.bcb_predecessors(bcb).contains(&bcb) {
- let counter_kind = self.coverage_counters.make_counter(|| Some(format!("{:?}", bcb)));
+ let counter_kind = self.coverage_counters.make_counter(|| Some(format!("{bcb:?}")));
if one_path_to_target {
debug!(
"{}{:?} gets a new counter: {}",
@@ -342,7 +449,7 @@ impl<'a> BcbCounters<'a> {
self.format_counter(&counter_kind),
);
}
- return self.basic_coverage_blocks[bcb].set_counter(counter_kind);
+ return self.coverage_counters.set_bcb_counter(bcb, counter_kind);
}
// A BCB with multiple incoming edges can compute its count by `Expression`, summing up the
@@ -358,7 +465,6 @@ impl<'a> BcbCounters<'a> {
let first_edge_counter_operand = self.recursive_get_or_make_edge_counter_operand(
predecessors.next().unwrap(),
bcb,
- collect_intermediate_expressions,
debug_indent_level + 1,
)?;
let mut some_sumup_edge_counter_operand = None;
@@ -366,7 +472,6 @@ impl<'a> BcbCounters<'a> {
let edge_counter_operand = self.recursive_get_or_make_edge_counter_operand(
predecessor,
bcb,
- collect_intermediate_expressions,
debug_indent_level + 1,
)?;
if let Some(sumup_edge_counter_operand) =
@@ -383,8 +488,8 @@ impl<'a> BcbCounters<'a> {
NESTED_INDENT.repeat(debug_indent_level),
self.format_counter(&intermediate_expression)
);
- let intermediate_expression_operand = intermediate_expression.as_operand_id();
- collect_intermediate_expressions.push(intermediate_expression);
+ let intermediate_expression_operand = intermediate_expression.as_operand();
+ self.coverage_counters.intermediate_expressions.push(intermediate_expression);
some_sumup_edge_counter_operand.replace(intermediate_expression_operand);
}
}
@@ -392,7 +497,7 @@ impl<'a> BcbCounters<'a> {
first_edge_counter_operand,
Op::Add,
some_sumup_edge_counter_operand.unwrap(),
- || Some(format!("{:?}", bcb)),
+ || Some(format!("{bcb:?}")),
);
debug!(
"{}{:?} gets a new counter (sum of predecessor counters): {}",
@@ -400,43 +505,34 @@ impl<'a> BcbCounters<'a> {
bcb,
self.format_counter(&counter_kind)
);
- self.basic_coverage_blocks[bcb].set_counter(counter_kind)
+ self.coverage_counters.set_bcb_counter(bcb, counter_kind)
}
fn get_or_make_edge_counter_operand(
&mut self,
from_bcb: BasicCoverageBlock,
to_bcb: BasicCoverageBlock,
- collect_intermediate_expressions: &mut Vec<CoverageKind>,
- ) -> Result<ExpressionOperandId, Error> {
- self.recursive_get_or_make_edge_counter_operand(
- from_bcb,
- to_bcb,
- collect_intermediate_expressions,
- 1,
- )
+ ) -> 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,
- collect_intermediate_expressions: &mut Vec<CoverageKind>,
debug_indent_level: usize,
- ) -> Result<ExpressionOperandId, Error> {
+ ) -> Result<Operand, Error> {
// 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,
- collect_intermediate_expressions,
- debug_indent_level + 1,
- );
+ return self.recursive_get_or_make_counter_operand(from_bcb, debug_indent_level + 1);
}
// If the edge already has a counter, return it.
- if let Some(counter_kind) = self.basic_coverage_blocks[to_bcb].edge_counter_from(from_bcb) {
+ 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),
@@ -444,12 +540,12 @@ impl<'a> BcbCounters<'a> {
to_bcb,
self.format_counter(counter_kind)
);
- return Ok(counter_kind.as_operand_id());
+ return Ok(counter_kind.as_operand());
}
// Make a new counter to count this edge.
let counter_kind =
- self.coverage_counters.make_counter(|| Some(format!("{:?}->{:?}", from_bcb, to_bcb)));
+ self.coverage_counters.make_counter(|| Some(format!("{from_bcb:?}->{to_bcb:?}")));
debug!(
"{}Edge {:?}->{:?} gets a new counter: {}",
NESTED_INDENT.repeat(debug_indent_level),
@@ -457,7 +553,7 @@ impl<'a> BcbCounters<'a> {
to_bcb,
self.format_counter(&counter_kind)
);
- self.basic_coverage_blocks[to_bcb].set_edge_counter_from(from_bcb, counter_kind)
+ self.coverage_counters.set_bcb_edge_counter(from_bcb, to_bcb, counter_kind)
}
/// Select a branch for the expression, either the recommended `reloop_branch`, or if none was
@@ -467,8 +563,7 @@ impl<'a> BcbCounters<'a> {
traversal: &TraverseCoverageGraphWithLoops,
branches: &[BcbBranch],
) -> BcbBranch {
- let branch_needs_a_counter =
- |branch: &BcbBranch| branch.counter(&self.basic_coverage_blocks).is_none();
+ 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) =
@@ -481,10 +576,8 @@ impl<'a> BcbCounters<'a> {
);
reloop_branch_without_counter
} else {
- let &branch_without_counter = branches
- .iter()
- .find(|&&branch| branch.counter(&self.basic_coverage_blocks).is_none())
- .expect(
+ let &branch_without_counter =
+ branches.iter().find(|&branch| self.branch_has_no_counter(branch)).expect(
"needs_branch_counters was `true` so there should be at least one \
branch",
);
@@ -511,8 +604,7 @@ impl<'a> BcbCounters<'a> {
traversal: &TraverseCoverageGraphWithLoops,
branches: &[BcbBranch],
) -> Option<BcbBranch> {
- let branch_needs_a_counter =
- |branch: &BcbBranch| branch.counter(&self.basic_coverage_blocks).is_none();
+ 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() {
@@ -523,7 +615,7 @@ impl<'a> BcbCounters<'a> {
self.bcb_dominates(branch.target_bcb, backedge_from_bcb)
}) {
if let Some(reloop_branch) = some_reloop_branch {
- if reloop_branch.counter(&self.basic_coverage_blocks).is_none() {
+ if self.branch_has_no_counter(&reloop_branch) {
// we already found a candidate reloop_branch that still
// needs a counter
continue;
@@ -589,12 +681,24 @@ impl<'a> BcbCounters<'a> {
}
fn bcb_needs_branch_counters(&self, bcb: BasicCoverageBlock) -> bool {
- let branch_needs_a_counter =
- |branch: &BcbBranch| branch.counter(&self.basic_coverage_blocks).is_none();
+ let branch_needs_a_counter = |branch: &BcbBranch| self.branch_has_no_counter(branch);
let branches = self.bcb_branches(bcb);
branches.len() > 1 && branches.iter().any(branch_needs_a_counter)
}
+ fn branch_has_no_counter(&self, branch: &BcbBranch) -> bool {
+ self.branch_counter(branch).is_none()
+ }
+
+ fn branch_counter(&self, branch: &BcbBranch) -> Option<&BcbCounter> {
+ let to_bcb = branch.target_bcb;
+ if let Some(from_bcb) = branch.edge_from_bcb {
+ self.coverage_counters.bcb_edge_counters.get(&(from_bcb, to_bcb))
+ } else {
+ self.coverage_counters.bcb_counters[to_bcb].as_ref()
+ }
+ }
+
/// Returns true if the BasicCoverageBlock has zero or one incoming edge. (If zero, it should be
/// the entry point for the function.)
#[inline]
@@ -608,7 +712,7 @@ impl<'a> BcbCounters<'a> {
}
#[inline]
- fn format_counter(&self, counter_kind: &CoverageKind) -> String {
+ fn format_counter(&self, counter_kind: &BcbCounter) -> String {
self.coverage_counters.debug_counters.format_counter(counter_kind)
}
}
diff --git a/compiler/rustc_mir_transform/src/coverage/debug.rs b/compiler/rustc_mir_transform/src/coverage/debug.rs
index 7ad981441..af616c498 100644
--- a/compiler/rustc_mir_transform/src/coverage/debug.rs
+++ b/compiler/rustc_mir_transform/src/coverage/debug.rs
@@ -108,6 +108,7 @@
//! recursively, generating labels with nested operations, enclosed in parentheses
//! (for example: `bcb2 + (bcb0 - bcb1)`).
+use super::counters::{BcbCounter, CoverageCounters};
use super::graph::{BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph};
use super::spans::CoverageSpan;
@@ -198,9 +199,9 @@ impl DebugOptions {
fn bool_option_val(option: &str, some_strval: Option<&str>) -> bool {
if let Some(val) = some_strval {
- if vec!["yes", "y", "on", "true"].contains(&val) {
+ if ["yes", "y", "on", "true"].contains(&val) {
true
- } else if vec!["no", "n", "off", "false"].contains(&val) {
+ } else if ["no", "n", "off", "false"].contains(&val) {
false
} else {
bug!(
@@ -246,11 +247,11 @@ impl Default for ExpressionFormat {
}
}
-/// If enabled, this struct maintains a map from `CoverageKind` IDs (as `ExpressionOperandId`) to
-/// the `CoverageKind` data and optional label (normally, the counter's associated
+/// If enabled, this struct maintains a map from `BcbCounter` IDs (as `Operand`) to
+/// the `BcbCounter` data and optional label (normally, the counter's associated
/// `BasicCoverageBlock` format string, if any).
///
-/// Use `format_counter` to convert one of these `CoverageKind` counters to a debug output string,
+/// Use `format_counter` to convert one of these `BcbCounter` counters to a debug output string,
/// as directed by the `DebugOptions`. This allows the format of counter labels in logs and dump
/// files (including the `CoverageGraph` graphviz file) to be changed at runtime, via environment
/// variable.
@@ -258,7 +259,7 @@ impl Default for ExpressionFormat {
/// `DebugCounters` supports a recursive rendering of `Expression` counters, so they can be
/// presented as nested expressions such as `(bcb3 - (bcb0 + bcb1))`.
pub(super) struct DebugCounters {
- some_counters: Option<FxHashMap<ExpressionOperandId, DebugCounter>>,
+ some_counters: Option<FxHashMap<Operand, DebugCounter>>,
}
impl DebugCounters {
@@ -275,36 +276,35 @@ impl DebugCounters {
self.some_counters.is_some()
}
- pub fn add_counter(&mut self, counter_kind: &CoverageKind, some_block_label: Option<String>) {
+ pub fn add_counter(&mut self, counter_kind: &BcbCounter, some_block_label: Option<String>) {
if let Some(counters) = &mut self.some_counters {
- let id = counter_kind.as_operand_id();
+ let id = counter_kind.as_operand();
counters
.try_insert(id, DebugCounter::new(counter_kind.clone(), some_block_label))
.expect("attempt to add the same counter_kind to DebugCounters more than once");
}
}
- pub fn some_block_label(&self, operand: ExpressionOperandId) -> Option<&String> {
+ pub fn some_block_label(&self, operand: Operand) -> Option<&String> {
self.some_counters.as_ref().and_then(|counters| {
counters.get(&operand).and_then(|debug_counter| debug_counter.some_block_label.as_ref())
})
}
- pub fn format_counter(&self, counter_kind: &CoverageKind) -> String {
+ pub fn format_counter(&self, counter_kind: &BcbCounter) -> String {
match *counter_kind {
- CoverageKind::Counter { .. } => {
+ BcbCounter::Counter { .. } => {
format!("Counter({})", self.format_counter_kind(counter_kind))
}
- CoverageKind::Expression { .. } => {
+ BcbCounter::Expression { .. } => {
format!("Expression({})", self.format_counter_kind(counter_kind))
}
- CoverageKind::Unreachable { .. } => "Unreachable".to_owned(),
}
}
- fn format_counter_kind(&self, counter_kind: &CoverageKind) -> String {
+ fn format_counter_kind(&self, counter_kind: &BcbCounter) -> String {
let counter_format = &debug_options().counter_format;
- if let CoverageKind::Expression { id, lhs, op, rhs } = *counter_kind {
+ if let BcbCounter::Expression { id, lhs, op, rhs } = *counter_kind {
if counter_format.operation {
return format!(
"{}{} {} {}",
@@ -323,29 +323,29 @@ impl DebugCounters {
}
}
- let id = counter_kind.as_operand_id();
+ let id = counter_kind.as_operand();
if self.some_counters.is_some() && (counter_format.block || !counter_format.id) {
let counters = self.some_counters.as_ref().unwrap();
if let Some(DebugCounter { some_block_label: Some(block_label), .. }) =
counters.get(&id)
{
return if counter_format.id {
- format!("{}#{}", block_label, id.index())
+ format!("{}#{:?}", block_label, id)
} else {
block_label.to_string()
};
}
}
- format!("#{}", id.index())
+ format!("#{:?}", id)
}
- fn format_operand(&self, operand: ExpressionOperandId) -> String {
- if operand.index() == 0 {
+ fn format_operand(&self, operand: Operand) -> String {
+ if matches!(operand, Operand::Zero) {
return String::from("0");
}
if let Some(counters) = &self.some_counters {
if let Some(DebugCounter { counter_kind, some_block_label }) = counters.get(&operand) {
- if let CoverageKind::Expression { .. } = counter_kind {
+ if let BcbCounter::Expression { .. } = counter_kind {
if let Some(label) = some_block_label && debug_options().counter_format.block {
return format!(
"{}:({})",
@@ -358,19 +358,19 @@ impl DebugCounters {
return self.format_counter_kind(counter_kind);
}
}
- format!("#{}", operand.index())
+ format!("#{:?}", operand)
}
}
/// A non-public support class to `DebugCounters`.
#[derive(Debug)]
struct DebugCounter {
- counter_kind: CoverageKind,
+ counter_kind: BcbCounter,
some_block_label: Option<String>,
}
impl DebugCounter {
- fn new(counter_kind: CoverageKind, some_block_label: Option<String>) -> Self {
+ fn new(counter_kind: BcbCounter, some_block_label: Option<String>) -> Self {
Self { counter_kind, some_block_label }
}
}
@@ -379,9 +379,9 @@ impl DebugCounter {
/// a Graphviz (.dot file) representation of the `CoverageGraph`, for debugging purposes.
pub(super) struct GraphvizData {
some_bcb_to_coverage_spans_with_counters:
- Option<FxHashMap<BasicCoverageBlock, Vec<(CoverageSpan, CoverageKind)>>>,
- some_bcb_to_dependency_counters: Option<FxHashMap<BasicCoverageBlock, Vec<CoverageKind>>>,
- some_edge_to_counter: Option<FxHashMap<(BasicCoverageBlock, BasicBlock), CoverageKind>>,
+ Option<FxHashMap<BasicCoverageBlock, Vec<(CoverageSpan, BcbCounter)>>>,
+ some_bcb_to_dependency_counters: Option<FxHashMap<BasicCoverageBlock, Vec<BcbCounter>>>,
+ some_edge_to_counter: Option<FxHashMap<(BasicCoverageBlock, BasicBlock), BcbCounter>>,
}
impl GraphvizData {
@@ -408,7 +408,7 @@ impl GraphvizData {
&mut self,
bcb: BasicCoverageBlock,
coverage_span: &CoverageSpan,
- counter_kind: &CoverageKind,
+ counter_kind: &BcbCounter,
) {
if let Some(bcb_to_coverage_spans_with_counters) =
self.some_bcb_to_coverage_spans_with_counters.as_mut()
@@ -423,7 +423,7 @@ impl GraphvizData {
pub fn get_bcb_coverage_spans_with_counters(
&self,
bcb: BasicCoverageBlock,
- ) -> Option<&[(CoverageSpan, CoverageKind)]> {
+ ) -> Option<&[(CoverageSpan, BcbCounter)]> {
if let Some(bcb_to_coverage_spans_with_counters) =
self.some_bcb_to_coverage_spans_with_counters.as_ref()
{
@@ -436,7 +436,7 @@ impl GraphvizData {
pub fn add_bcb_dependency_counter(
&mut self,
bcb: BasicCoverageBlock,
- counter_kind: &CoverageKind,
+ counter_kind: &BcbCounter,
) {
if let Some(bcb_to_dependency_counters) = self.some_bcb_to_dependency_counters.as_mut() {
bcb_to_dependency_counters
@@ -446,7 +446,7 @@ impl GraphvizData {
}
}
- pub fn get_bcb_dependency_counters(&self, bcb: BasicCoverageBlock) -> Option<&[CoverageKind]> {
+ pub fn get_bcb_dependency_counters(&self, bcb: BasicCoverageBlock) -> Option<&[BcbCounter]> {
if let Some(bcb_to_dependency_counters) = self.some_bcb_to_dependency_counters.as_ref() {
bcb_to_dependency_counters.get(&bcb).map(Deref::deref)
} else {
@@ -458,7 +458,7 @@ impl GraphvizData {
&mut self,
from_bcb: BasicCoverageBlock,
to_bb: BasicBlock,
- counter_kind: &CoverageKind,
+ counter_kind: &BcbCounter,
) {
if let Some(edge_to_counter) = self.some_edge_to_counter.as_mut() {
edge_to_counter
@@ -471,7 +471,7 @@ impl GraphvizData {
&self,
from_bcb: BasicCoverageBlock,
to_bb: BasicBlock,
- ) -> Option<&CoverageKind> {
+ ) -> Option<&BcbCounter> {
if let Some(edge_to_counter) = self.some_edge_to_counter.as_ref() {
edge_to_counter.get(&(from_bcb, to_bb))
} else {
@@ -485,10 +485,9 @@ impl GraphvizData {
/// _not_ used are retained in the `unused_expressions` Vec, to be included in debug output (logs
/// and/or a `CoverageGraph` graphviz output).
pub(super) struct UsedExpressions {
- some_used_expression_operands:
- Option<FxHashMap<ExpressionOperandId, Vec<InjectedExpressionId>>>,
+ some_used_expression_operands: Option<FxHashMap<Operand, Vec<ExpressionId>>>,
some_unused_expressions:
- Option<Vec<(CoverageKind, Option<BasicCoverageBlock>, BasicCoverageBlock)>>,
+ Option<Vec<(BcbCounter, Option<BasicCoverageBlock>, BasicCoverageBlock)>>,
}
impl UsedExpressions {
@@ -506,18 +505,18 @@ impl UsedExpressions {
self.some_used_expression_operands.is_some()
}
- pub fn add_expression_operands(&mut self, expression: &CoverageKind) {
+ pub fn add_expression_operands(&mut self, expression: &BcbCounter) {
if let Some(used_expression_operands) = self.some_used_expression_operands.as_mut() {
- if let CoverageKind::Expression { id, lhs, rhs, .. } = *expression {
+ if let BcbCounter::Expression { id, lhs, rhs, .. } = *expression {
used_expression_operands.entry(lhs).or_insert_with(Vec::new).push(id);
used_expression_operands.entry(rhs).or_insert_with(Vec::new).push(id);
}
}
}
- pub fn expression_is_used(&self, expression: &CoverageKind) -> bool {
+ pub fn expression_is_used(&self, expression: &BcbCounter) -> bool {
if let Some(used_expression_operands) = self.some_used_expression_operands.as_ref() {
- used_expression_operands.contains_key(&expression.as_operand_id())
+ used_expression_operands.contains_key(&expression.as_operand())
} else {
false
}
@@ -525,12 +524,12 @@ impl UsedExpressions {
pub fn add_unused_expression_if_not_found(
&mut self,
- expression: &CoverageKind,
+ expression: &BcbCounter,
edge_from_bcb: Option<BasicCoverageBlock>,
target_bcb: BasicCoverageBlock,
) {
if let Some(used_expression_operands) = self.some_used_expression_operands.as_ref() {
- if !used_expression_operands.contains_key(&expression.as_operand_id()) {
+ if !used_expression_operands.contains_key(&expression.as_operand()) {
self.some_unused_expressions.as_mut().unwrap().push((
expression.clone(),
edge_from_bcb,
@@ -540,11 +539,11 @@ impl UsedExpressions {
}
}
- /// Return the list of unused counters (if any) as a tuple with the counter (`CoverageKind`),
+ /// Return the list of unused counters (if any) as a tuple with the counter (`BcbCounter`),
/// optional `from_bcb` (if it was an edge counter), and `target_bcb`.
pub fn get_unused_expressions(
&self,
- ) -> Vec<(CoverageKind, Option<BasicCoverageBlock>, BasicCoverageBlock)> {
+ ) -> Vec<(BcbCounter, Option<BasicCoverageBlock>, BasicCoverageBlock)> {
if let Some(unused_expressions) = self.some_unused_expressions.as_ref() {
unused_expressions.clone()
} else {
@@ -560,7 +559,7 @@ impl UsedExpressions {
bcb_counters_without_direct_coverage_spans: &[(
Option<BasicCoverageBlock>,
BasicCoverageBlock,
- CoverageKind,
+ BcbCounter,
)],
) {
if self.is_enabled() {
@@ -630,7 +629,7 @@ pub(super) fn dump_coverage_spanview<'tcx>(
.expect("Unexpected error creating MIR spanview HTML file");
let crate_name = tcx.crate_name(def_id.krate);
let item_name = tcx.def_path(def_id).to_filename_friendly_no_crate();
- let title = format!("{}.{} - Coverage Spans", crate_name, item_name);
+ let title = format!("{crate_name}.{item_name} - Coverage Spans");
spanview::write_document(tcx, body_span, span_viewables, &title, &mut file)
.expect("Unexpected IO error dumping coverage spans as HTML");
}
@@ -660,18 +659,21 @@ pub(super) fn dump_coverage_graphviz<'tcx>(
mir_body: &mir::Body<'tcx>,
pass_name: &str,
basic_coverage_blocks: &CoverageGraph,
- debug_counters: &DebugCounters,
+ coverage_counters: &CoverageCounters,
graphviz_data: &GraphvizData,
- intermediate_expressions: &[CoverageKind],
+ intermediate_expressions: &[BcbCounter],
debug_used_expressions: &UsedExpressions,
) {
+ let debug_counters = &coverage_counters.debug_counters;
+
let mir_source = mir_body.source;
let def_id = mir_source.def_id();
let node_content = |bcb| {
bcb_to_string_sections(
tcx,
mir_body,
- debug_counters,
+ coverage_counters,
+ bcb,
&basic_coverage_blocks[bcb],
graphviz_data.get_bcb_coverage_spans_with_counters(bcb),
graphviz_data.get_bcb_dependency_counters(bcb),
@@ -737,12 +739,15 @@ pub(super) fn dump_coverage_graphviz<'tcx>(
fn bcb_to_string_sections<'tcx>(
tcx: TyCtxt<'tcx>,
mir_body: &mir::Body<'tcx>,
- debug_counters: &DebugCounters,
+ coverage_counters: &CoverageCounters,
+ bcb: BasicCoverageBlock,
bcb_data: &BasicCoverageBlockData,
- some_coverage_spans_with_counters: Option<&[(CoverageSpan, CoverageKind)]>,
- some_dependency_counters: Option<&[CoverageKind]>,
- some_intermediate_expressions: Option<&[CoverageKind]>,
+ some_coverage_spans_with_counters: Option<&[(CoverageSpan, BcbCounter)]>,
+ some_dependency_counters: Option<&[BcbCounter]>,
+ some_intermediate_expressions: Option<&[BcbCounter]>,
) -> Vec<String> {
+ let debug_counters = &coverage_counters.debug_counters;
+
let len = bcb_data.basic_blocks.len();
let mut sections = Vec::new();
if let Some(collect_intermediate_expressions) = some_intermediate_expressions {
@@ -778,8 +783,8 @@ fn bcb_to_string_sections<'tcx>(
.join(" \n"),
));
}
- if let Some(counter_kind) = &bcb_data.counter_kind {
- sections.push(format!("{:?}", counter_kind));
+ if let Some(counter_kind) = coverage_counters.bcb_counter(bcb) {
+ sections.push(format!("{counter_kind:?}"));
}
let non_term_blocks = bcb_data.basic_blocks[0..len - 1]
.iter()
diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs
index d2a854b26..59b01ffec 100644
--- a/compiler/rustc_mir_transform/src/coverage/graph.rs
+++ b/compiler/rustc_mir_transform/src/coverage/graph.rs
@@ -1,12 +1,8 @@
-use super::Error;
-
use itertools::Itertools;
-use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::graph::dominators::{self, Dominators};
use rustc_data_structures::graph::{self, GraphSuccessors, WithNumNodes, WithStartNode};
use rustc_index::bit_set::BitSet;
use rustc_index::{IndexSlice, IndexVec};
-use rustc_middle::mir::coverage::*;
use rustc_middle::mir::{self, BasicBlock, BasicBlockData, Terminator, TerminatorKind};
use std::cmp::Ordering;
@@ -15,10 +11,7 @@ use std::ops::{Index, IndexMut};
const ID_SEPARATOR: &str = ",";
/// A coverage-specific simplification of the MIR control flow graph (CFG). The `CoverageGraph`s
-/// nodes are `BasicCoverageBlock`s, which encompass one or more MIR `BasicBlock`s, plus a
-/// `CoverageKind` counter (to be added by `CoverageCounters::make_bcb_counters`), and an optional
-/// set of additional counters--if needed--to count incoming edges, if there are more than one.
-/// (These "edge counters" are eventually converted into new MIR `BasicBlock`s.)
+/// nodes are `BasicCoverageBlock`s, which encompass one or more MIR `BasicBlock`s.
#[derive(Debug)]
pub(super) struct CoverageGraph {
bcbs: IndexVec<BasicCoverageBlock, BasicCoverageBlockData>,
@@ -196,13 +189,6 @@ impl CoverageGraph {
}
#[inline(always)]
- pub fn iter_enumerated_mut(
- &mut self,
- ) -> impl Iterator<Item = (BasicCoverageBlock, &mut BasicCoverageBlockData)> {
- self.bcbs.iter_enumerated_mut()
- }
-
- #[inline(always)]
pub fn bcb_from_bb(&self, bb: BasicBlock) -> Option<BasicCoverageBlock> {
if bb.index() < self.bb_to_bcb.len() { self.bb_to_bcb[bb] } else { None }
}
@@ -320,14 +306,12 @@ rustc_index::newtype_index! {
#[derive(Debug, Clone)]
pub(super) struct BasicCoverageBlockData {
pub basic_blocks: Vec<BasicBlock>,
- pub counter_kind: Option<CoverageKind>,
- edge_from_bcbs: Option<FxHashMap<BasicCoverageBlock, CoverageKind>>,
}
impl BasicCoverageBlockData {
pub fn from(basic_blocks: Vec<BasicBlock>) -> Self {
assert!(basic_blocks.len() > 0);
- Self { basic_blocks, counter_kind: None, edge_from_bcbs: None }
+ Self { basic_blocks }
}
#[inline(always)]
@@ -345,86 +329,6 @@ impl BasicCoverageBlockData {
&mir_body[self.last_bb()].terminator()
}
- pub fn set_counter(
- &mut self,
- counter_kind: CoverageKind,
- ) -> Result<ExpressionOperandId, Error> {
- debug_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`).
- self.edge_from_bcbs.is_none() || counter_kind.is_expression(),
- "attempt to add a `Counter` to a BCB target with existing incoming edge counters"
- );
- let operand = counter_kind.as_operand_id();
- if let Some(replaced) = self.counter_kind.replace(counter_kind) {
- Error::from_string(format!(
- "attempt to set a BasicCoverageBlock coverage counter more than once; \
- {:?} already had counter {:?}",
- self, replaced,
- ))
- } else {
- Ok(operand)
- }
- }
-
- #[inline(always)]
- pub fn counter(&self) -> Option<&CoverageKind> {
- self.counter_kind.as_ref()
- }
-
- #[inline(always)]
- pub fn take_counter(&mut self) -> Option<CoverageKind> {
- self.counter_kind.take()
- }
-
- pub fn set_edge_counter_from(
- &mut self,
- from_bcb: BasicCoverageBlock,
- counter_kind: CoverageKind,
- ) -> Result<ExpressionOperandId, 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.counter_kind.as_ref().is_some_and(|c| !c.is_expression()) {
- return Error::from_string(format!(
- "attempt to add an incoming edge counter from {:?} when the target BCB already \
- has a `Counter`",
- from_bcb
- ));
- }
- }
- let operand = counter_kind.as_operand_id();
- if let Some(replaced) =
- self.edge_from_bcbs.get_or_insert_default().insert(from_bcb, counter_kind)
- {
- Error::from_string(format!(
- "attempt to set an edge counter more than once; from_bcb: \
- {:?} already had counter {:?}",
- from_bcb, replaced,
- ))
- } else {
- Ok(operand)
- }
- }
-
- #[inline]
- pub fn edge_counter_from(&self, from_bcb: BasicCoverageBlock) -> Option<&CoverageKind> {
- if let Some(edge_from_bcbs) = &self.edge_from_bcbs {
- edge_from_bcbs.get(&from_bcb)
- } else {
- None
- }
- }
-
- #[inline]
- pub fn take_edge_counters(
- &mut self,
- ) -> Option<impl Iterator<Item = (BasicCoverageBlock, CoverageKind)>> {
- self.edge_from_bcbs.take().map(|m| m.into_iter())
- }
-
pub fn id(&self) -> String {
format!("@{}", self.basic_blocks.iter().map(|bb| bb.index().to_string()).join(ID_SEPARATOR))
}
@@ -454,17 +358,6 @@ impl BcbBranch {
Self { edge_from_bcb, target_bcb: to_bcb }
}
- pub fn counter<'a>(
- &self,
- basic_coverage_blocks: &'a CoverageGraph,
- ) -> Option<&'a CoverageKind> {
- if let Some(from_bcb) = self.edge_from_bcb {
- basic_coverage_blocks[self.target_bcb].edge_counter_from(from_bcb)
- } else {
- basic_coverage_blocks[self.target_bcb].counter()
- }
- }
-
pub fn is_only_path_to_target(&self) -> bool {
self.edge_from_bcb.is_none()
}
@@ -612,7 +505,7 @@ impl TraverseCoverageGraphWithLoops {
the {}",
successor_to_add,
if let Some(loop_header) = some_loop_header {
- format!("worklist for the loop headed by {:?}", loop_header)
+ format!("worklist for the loop headed by {loop_header:?}")
} else {
String::from("non-loop worklist")
},
@@ -623,7 +516,7 @@ impl TraverseCoverageGraphWithLoops {
"{:?} successor is non-branching. Defer it to the end of the {}",
successor_to_add,
if let Some(loop_header) = some_loop_header {
- format!("worklist for the loop headed by {:?}", loop_header)
+ format!("worklist for the loop headed by {loop_header:?}")
} else {
String::from("non-loop worklist")
},
diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs
index 076e714d7..8c9eae508 100644
--- a/compiler/rustc_mir_transform/src/coverage/mod.rs
+++ b/compiler/rustc_mir_transform/src/coverage/mod.rs
@@ -8,9 +8,9 @@ mod spans;
#[cfg(test)]
mod tests;
-use counters::CoverageCounters;
-use graph::{BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph};
-use spans::{CoverageSpan, CoverageSpans};
+use self::counters::{BcbCounter, CoverageCounters};
+use self::graph::{BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph};
+use self::spans::{CoverageSpan, CoverageSpans};
use crate::MirPass;
@@ -106,6 +106,7 @@ struct Instrumentor<'a, 'tcx> {
source_file: Lrc<SourceFile>,
fn_sig_span: Span,
body_span: Span,
+ function_source_hash: u64,
basic_coverage_blocks: CoverageGraph,
coverage_counters: CoverageCounters,
}
@@ -137,6 +138,8 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
let function_source_hash = hash_mir_source(tcx, hir_body);
let basic_coverage_blocks = CoverageGraph::from_mir(mir_body);
+ let coverage_counters = CoverageCounters::new(&basic_coverage_blocks);
+
Self {
pass_name,
tcx,
@@ -144,8 +147,9 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
source_file,
fn_sig_span,
body_span,
+ function_source_hash,
basic_coverage_blocks,
- coverage_counters: CoverageCounters::new(function_source_hash),
+ coverage_counters,
}
}
@@ -199,52 +203,47 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
// `BasicCoverageBlock`s not already associated with a `CoverageSpan`.
//
// Intermediate expressions (used to compute other `Expression` values), which have no
- // direct associate to any `BasicCoverageBlock`, are returned in the method `Result`.
- let intermediate_expressions_or_error = self
+ // direct association with any `BasicCoverageBlock`, are accumulated inside `coverage_counters`.
+ let result = self
.coverage_counters
.make_bcb_counters(&mut self.basic_coverage_blocks, &coverage_spans);
- let (result, intermediate_expressions) = match intermediate_expressions_or_error {
- Ok(intermediate_expressions) => {
- // If debugging, add any intermediate expressions (which are not associated with any
- // BCB) to the `debug_used_expressions` map.
- if debug_used_expressions.is_enabled() {
- for intermediate_expression in &intermediate_expressions {
- debug_used_expressions.add_expression_operands(intermediate_expression);
- }
+ if let Ok(()) = result {
+ // If debugging, add any intermediate expressions (which are not associated with any
+ // BCB) to the `debug_used_expressions` map.
+ if debug_used_expressions.is_enabled() {
+ for intermediate_expression in &self.coverage_counters.intermediate_expressions {
+ debug_used_expressions.add_expression_operands(intermediate_expression);
}
-
- ////////////////////////////////////////////////////
- // Remove the counter or edge counter from of each `CoverageSpan`s associated
- // `BasicCoverageBlock`, and inject a `Coverage` statement into the MIR.
- //
- // `Coverage` statements injected from `CoverageSpan`s will include the code regions
- // (source code start and end positions) to be counted by the associated counter.
- //
- // These `CoverageSpan`-associated counters are removed from their associated
- // `BasicCoverageBlock`s so that the only remaining counters in the `CoverageGraph`
- // are indirect counters (to be injected next, without associated code regions).
- self.inject_coverage_span_counters(
- coverage_spans,
- &mut graphviz_data,
- &mut debug_used_expressions,
- );
-
- ////////////////////////////////////////////////////
- // For any remaining `BasicCoverageBlock` counters (that were not associated with
- // any `CoverageSpan`), inject `Coverage` statements (_without_ code region `Span`s)
- // to ensure `BasicCoverageBlock` counters that other `Expression`s may depend on
- // are in fact counted, even though they don't directly contribute to counting
- // their own independent code region's coverage.
- self.inject_indirect_counters(&mut graphviz_data, &mut debug_used_expressions);
-
- // Intermediate expressions will be injected as the final step, after generating
- // debug output, if any.
- ////////////////////////////////////////////////////
-
- (Ok(()), intermediate_expressions)
}
- Err(e) => (Err(e), Vec::new()),
+
+ ////////////////////////////////////////////////////
+ // Remove the counter or edge counter from of each `CoverageSpan`s associated
+ // `BasicCoverageBlock`, and inject a `Coverage` statement into the MIR.
+ //
+ // `Coverage` statements injected from `CoverageSpan`s will include the code regions
+ // (source code start and end positions) to be counted by the associated counter.
+ //
+ // These `CoverageSpan`-associated counters are removed from their associated
+ // `BasicCoverageBlock`s so that the only remaining counters in the `CoverageGraph`
+ // are indirect counters (to be injected next, without associated code regions).
+ self.inject_coverage_span_counters(
+ coverage_spans,
+ &mut graphviz_data,
+ &mut debug_used_expressions,
+ );
+
+ ////////////////////////////////////////////////////
+ // For any remaining `BasicCoverageBlock` counters (that were not associated with
+ // any `CoverageSpan`), inject `Coverage` statements (_without_ code region `Span`s)
+ // to ensure `BasicCoverageBlock` counters that other `Expression`s may depend on
+ // are in fact counted, even though they don't directly contribute to counting
+ // their own independent code region's coverage.
+ self.inject_indirect_counters(&mut graphviz_data, &mut debug_used_expressions);
+
+ // Intermediate expressions will be injected as the final step, after generating
+ // debug output, if any.
+ ////////////////////////////////////////////////////
};
if graphviz_data.is_enabled() {
@@ -255,9 +254,9 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
self.mir_body,
self.pass_name,
&self.basic_coverage_blocks,
- &self.coverage_counters.debug_counters,
+ &self.coverage_counters,
&graphviz_data,
- &intermediate_expressions,
+ &self.coverage_counters.intermediate_expressions,
&debug_used_expressions,
);
}
@@ -273,8 +272,11 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
////////////////////////////////////////////////////
// Finally, inject the intermediate expressions collected along the way.
- for intermediate_expression in intermediate_expressions {
- inject_intermediate_expression(self.mir_body, intermediate_expression);
+ for intermediate_expression in &self.coverage_counters.intermediate_expressions {
+ inject_intermediate_expression(
+ self.mir_body,
+ self.make_mir_coverage_kind(intermediate_expression),
+ );
}
}
@@ -303,8 +305,8 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
let span = covspan.span;
let counter_kind = if let Some(&counter_operand) = bcb_counters[bcb].as_ref() {
self.coverage_counters.make_identity_counter(counter_operand)
- } else if let Some(counter_kind) = self.bcb_data_mut(bcb).take_counter() {
- bcb_counters[bcb] = Some(counter_kind.as_operand_id());
+ } else if let Some(counter_kind) = self.coverage_counters.take_bcb_counter(bcb) {
+ bcb_counters[bcb] = Some(counter_kind.as_operand());
debug_used_expressions.add_expression_operands(&counter_kind);
counter_kind
} else {
@@ -312,19 +314,14 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
};
graphviz_data.add_bcb_coverage_span_with_counter(bcb, &covspan, &counter_kind);
- debug!(
- "Calling make_code_region(file_name={}, source_file={:?}, span={}, body_span={})",
- file_name,
- self.source_file,
- source_map.span_to_diagnostic_string(span),
- source_map.span_to_diagnostic_string(body_span)
- );
+ let code_region =
+ make_code_region(source_map, file_name, &self.source_file, span, body_span);
inject_statement(
self.mir_body,
- counter_kind,
+ self.make_mir_coverage_kind(&counter_kind),
self.bcb_leader_bb(bcb),
- Some(make_code_region(source_map, file_name, &self.source_file, span, body_span)),
+ Some(code_region),
);
}
}
@@ -343,19 +340,17 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
debug_used_expressions: &mut debug::UsedExpressions,
) {
let mut bcb_counters_without_direct_coverage_spans = Vec::new();
- for (target_bcb, target_bcb_data) in self.basic_coverage_blocks.iter_enumerated_mut() {
- if let Some(counter_kind) = target_bcb_data.take_counter() {
- bcb_counters_without_direct_coverage_spans.push((None, target_bcb, counter_kind));
- }
- if let Some(edge_counters) = target_bcb_data.take_edge_counters() {
- for (from_bcb, counter_kind) in edge_counters {
- bcb_counters_without_direct_coverage_spans.push((
- Some(from_bcb),
- target_bcb,
- counter_kind,
- ));
- }
- }
+ for (target_bcb, counter_kind) in self.coverage_counters.drain_bcb_counters() {
+ bcb_counters_without_direct_coverage_spans.push((None, target_bcb, counter_kind));
+ }
+ for ((from_bcb, target_bcb), counter_kind) in
+ self.coverage_counters.drain_bcb_edge_counters()
+ {
+ bcb_counters_without_direct_coverage_spans.push((
+ Some(from_bcb),
+ target_bcb,
+ counter_kind,
+ ));
}
// If debug is enabled, validate that every BCB or edge counter not directly associated
@@ -372,7 +367,7 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
);
match counter_kind {
- CoverageKind::Counter { .. } => {
+ BcbCounter::Counter { .. } => {
let inject_to_bb = if let Some(from_bcb) = edge_from_bcb {
// The MIR edge starts `from_bb` (the outgoing / last BasicBlock in
// `from_bcb`) and ends at `to_bb` (the incoming / first BasicBlock in the
@@ -405,12 +400,17 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
target_bb
};
- inject_statement(self.mir_body, counter_kind, inject_to_bb, None);
+ inject_statement(
+ self.mir_body,
+ self.make_mir_coverage_kind(&counter_kind),
+ inject_to_bb,
+ None,
+ );
}
- CoverageKind::Expression { .. } => {
- inject_intermediate_expression(self.mir_body, counter_kind)
- }
- _ => bug!("CoverageKind should be a counter"),
+ BcbCounter::Expression { .. } => inject_intermediate_expression(
+ self.mir_body,
+ self.make_mir_coverage_kind(&counter_kind),
+ ),
}
}
}
@@ -431,13 +431,19 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
}
#[inline]
- fn bcb_data_mut(&mut self, bcb: BasicCoverageBlock) -> &mut BasicCoverageBlockData {
- &mut self.basic_coverage_blocks[bcb]
+ fn format_counter(&self, counter_kind: &BcbCounter) -> String {
+ self.coverage_counters.debug_counters.format_counter(counter_kind)
}
- #[inline]
- fn format_counter(&self, counter_kind: &CoverageKind) -> String {
- self.coverage_counters.debug_counters.format_counter(counter_kind)
+ fn make_mir_coverage_kind(&self, counter_kind: &BcbCounter) -> CoverageKind {
+ match *counter_kind {
+ BcbCounter::Counter { id } => {
+ CoverageKind::Counter { function_source_hash: self.function_source_hash, id }
+ }
+ BcbCounter::Expression { id, lhs, op, rhs } => {
+ CoverageKind::Expression { id, lhs, op, rhs }
+ }
+ }
}
}
@@ -508,6 +514,14 @@ fn make_code_region(
span: Span,
body_span: Span,
) -> CodeRegion {
+ debug!(
+ "Called make_code_region(file_name={}, source_file={:?}, span={}, body_span={})",
+ file_name,
+ source_file,
+ source_map.span_to_diagnostic_string(span),
+ source_map.span_to_diagnostic_string(body_span)
+ );
+
let (start_line, mut start_col) = source_file.lookup_file_pos(span.lo());
let (end_line, end_col) = if span.hi() == span.lo() {
let (end_line, mut end_col) = (start_line, start_col);
diff --git a/compiler/rustc_mir_transform/src/coverage/query.rs b/compiler/rustc_mir_transform/src/coverage/query.rs
index 74b4b4a07..aa205655f 100644
--- a/compiler/rustc_mir_transform/src/coverage/query.rs
+++ b/compiler/rustc_mir_transform/src/coverage/query.rs
@@ -43,43 +43,25 @@ struct CoverageVisitor {
}
impl CoverageVisitor {
- /// Updates `num_counters` to the maximum encountered zero-based counter_id plus 1. Note the
- /// final computed number of counters should be the number of all `CoverageKind::Counter`
- /// statements in the MIR *plus one* for the implicit `ZERO` counter.
+ /// Updates `num_counters` to the maximum encountered counter ID plus 1.
#[inline(always)]
- fn update_num_counters(&mut self, counter_id: u32) {
+ fn update_num_counters(&mut self, counter_id: CounterId) {
+ let counter_id = counter_id.as_u32();
self.info.num_counters = std::cmp::max(self.info.num_counters, counter_id + 1);
}
- /// Computes an expression index for each expression ID, and updates `num_expressions` to the
- /// maximum encountered index plus 1.
+ /// Updates `num_expressions` to the maximum encountered expression ID plus 1.
#[inline(always)]
- fn update_num_expressions(&mut self, expression_id: u32) {
- let expression_index = u32::MAX - expression_id;
- self.info.num_expressions = std::cmp::max(self.info.num_expressions, expression_index + 1);
+ fn update_num_expressions(&mut self, expression_id: ExpressionId) {
+ let expression_id = expression_id.as_u32();
+ self.info.num_expressions = std::cmp::max(self.info.num_expressions, expression_id + 1);
}
- fn update_from_expression_operand(&mut self, operand_id: u32) {
- if operand_id >= self.info.num_counters {
- let operand_as_expression_index = u32::MAX - operand_id;
- if operand_as_expression_index >= self.info.num_expressions {
- // The operand ID is outside the known range of counter IDs and also outside the
- // known range of expression IDs. In either case, the result of a missing operand
- // (if and when used in an expression) will be zero, so from a computation
- // perspective, it doesn't matter whether it is interpreted as a counter or an
- // expression.
- //
- // However, the `num_counters` and `num_expressions` query results are used to
- // allocate arrays when generating the coverage map (during codegen), so choose
- // the type that grows either `num_counters` or `num_expressions` the least.
- if operand_id - self.info.num_counters
- < operand_as_expression_index - self.info.num_expressions
- {
- self.update_num_counters(operand_id)
- } else {
- self.update_num_expressions(operand_id)
- }
- }
+ fn update_from_expression_operand(&mut self, operand: Operand) {
+ match operand {
+ Operand::Counter(id) => self.update_num_counters(id),
+ Operand::Expression(id) => self.update_num_expressions(id),
+ Operand::Zero => {}
}
}
@@ -100,19 +82,15 @@ impl CoverageVisitor {
if self.add_missing_operands {
match coverage.kind {
CoverageKind::Expression { lhs, rhs, .. } => {
- self.update_from_expression_operand(u32::from(lhs));
- self.update_from_expression_operand(u32::from(rhs));
+ self.update_from_expression_operand(lhs);
+ self.update_from_expression_operand(rhs);
}
_ => {}
}
} else {
match coverage.kind {
- CoverageKind::Counter { id, .. } => {
- self.update_num_counters(u32::from(id));
- }
- CoverageKind::Expression { id, .. } => {
- self.update_num_expressions(u32::from(id));
- }
+ CoverageKind::Counter { id, .. } => self.update_num_counters(id),
+ CoverageKind::Expression { id, .. } => self.update_num_expressions(id),
_ => {}
}
}
@@ -123,8 +101,7 @@ fn coverageinfo<'tcx>(tcx: TyCtxt<'tcx>, instance_def: ty::InstanceDef<'tcx>) ->
let mir_body = tcx.instance_mir(instance_def);
let mut coverage_visitor = CoverageVisitor {
- // num_counters always has at least the `ZERO` counter.
- info: CoverageInfo { num_counters: 1, num_expressions: 0 },
+ info: CoverageInfo { num_counters: 0, num_expressions: 0 },
add_missing_operands: false,
};
diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs
index 35cf9ea5f..deebf5345 100644
--- a/compiler/rustc_mir_transform/src/coverage/spans.rs
+++ b/compiler/rustc_mir_transform/src/coverage/spans.rs
@@ -11,7 +11,7 @@ use rustc_middle::ty::TyCtxt;
use rustc_span::source_map::original_sp;
use rustc_span::{BytePos, ExpnKind, MacroKind, Span, Symbol};
-use std::cell::RefCell;
+use std::cell::OnceCell;
use std::cmp::Ordering;
#[derive(Debug, Copy, Clone)]
@@ -67,7 +67,7 @@ impl CoverageStatement {
pub(super) struct CoverageSpan {
pub span: Span,
pub expn_span: Span,
- pub current_macro_or_none: RefCell<Option<Option<Symbol>>>,
+ pub current_macro_or_none: OnceCell<Option<Symbol>>,
pub bcb: BasicCoverageBlock,
pub coverage_statements: Vec<CoverageStatement>,
pub is_closure: bool,
@@ -175,8 +175,7 @@ impl CoverageSpan {
/// If the span is part of a macro, returns the macro name symbol.
pub fn current_macro(&self) -> Option<Symbol> {
self.current_macro_or_none
- .borrow_mut()
- .get_or_insert_with(|| {
+ .get_or_init(|| {
if let ExpnKind::Macro(MacroKind::Bang, current_macro) =
self.expn_span.ctxt().outer_expn_data().kind
{
diff --git a/compiler/rustc_mir_transform/src/coverage/test_macros/src/lib.rs b/compiler/rustc_mir_transform/src/coverage/test_macros/src/lib.rs
index 3d6095d27..f41adf667 100644
--- a/compiler/rustc_mir_transform/src/coverage/test_macros/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/coverage/test_macros/src/lib.rs
@@ -2,5 +2,5 @@ use proc_macro::TokenStream;
#[proc_macro]
pub fn let_bcb(item: TokenStream) -> TokenStream {
- format!("let bcb{} = graph::BasicCoverageBlock::from_usize({});", item, item).parse().unwrap()
+ format!("let bcb{item} = graph::BasicCoverageBlock::from_usize({item});").parse().unwrap()
}
diff --git a/compiler/rustc_mir_transform/src/coverage/tests.rs b/compiler/rustc_mir_transform/src/coverage/tests.rs
index 25891d3ca..4a066ed3a 100644
--- a/compiler/rustc_mir_transform/src/coverage/tests.rs
+++ b/compiler/rustc_mir_transform/src/coverage/tests.rs
@@ -34,7 +34,6 @@ use itertools::Itertools;
use rustc_data_structures::graph::WithNumNodes;
use rustc_data_structures::graph::WithSuccessors;
use rustc_index::{Idx, IndexVec};
-use rustc_middle::mir::coverage::CoverageKind;
use rustc_middle::mir::*;
use rustc_middle::ty;
use rustc_span::{self, BytePos, Pos, Span, DUMMY_SP};
@@ -675,17 +674,17 @@ fn test_make_bcb_counters() {
));
}
}
- let mut coverage_counters = counters::CoverageCounters::new(0);
- let intermediate_expressions = coverage_counters
+ let mut coverage_counters = counters::CoverageCounters::new(&basic_coverage_blocks);
+ coverage_counters
.make_bcb_counters(&mut basic_coverage_blocks, &coverage_spans)
.expect("should be Ok");
- assert_eq!(intermediate_expressions.len(), 0);
+ assert_eq!(coverage_counters.intermediate_expressions.len(), 0);
let_bcb!(1);
assert_eq!(
- 1, // coincidentally, bcb1 has a `Counter` with id = 1
- match basic_coverage_blocks[bcb1].counter().expect("should have a counter") {
- CoverageKind::Counter { id, .. } => id,
+ 0, // bcb1 has a `Counter` with id = 0
+ match coverage_counters.bcb_counter(bcb1).expect("should have a counter") {
+ counters::BcbCounter::Counter { id, .. } => id,
_ => panic!("expected a Counter"),
}
.as_u32()
@@ -693,9 +692,9 @@ fn test_make_bcb_counters() {
let_bcb!(2);
assert_eq!(
- 2, // coincidentally, bcb2 has a `Counter` with id = 2
- match basic_coverage_blocks[bcb2].counter().expect("should have a counter") {
- CoverageKind::Counter { id, .. } => id,
+ 1, // bcb2 has a `Counter` with id = 1
+ match coverage_counters.bcb_counter(bcb2).expect("should have a counter") {
+ counters::BcbCounter::Counter { id, .. } => id,
_ => panic!("expected a Counter"),
}
.as_u32()