diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-30 03:59:35 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-30 03:59:35 +0000 |
commit | d1b2d29528b7794b41e66fc2136e395a02f8529b (patch) | |
tree | a4a17504b260206dec3cf55b2dca82929a348ac2 /compiler/rustc_mir_transform/src/coverage | |
parent | Releasing progress-linux version 1.72.1+dfsg1-1~progress7.99u1. (diff) | |
download | rustc-d1b2d29528b7794b41e66fc2136e395a02f8529b.tar.xz rustc-d1b2d29528b7794b41e66fc2136e395a02f8529b.zip |
Merging upstream version 1.73.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_mir_transform/src/coverage')
-rw-r--r-- | compiler/rustc_mir_transform/src/coverage/counters.rs | 354 | ||||
-rw-r--r-- | compiler/rustc_mir_transform/src/coverage/debug.rs | 115 | ||||
-rw-r--r-- | compiler/rustc_mir_transform/src/coverage/graph.rs | 115 | ||||
-rw-r--r-- | compiler/rustc_mir_transform/src/coverage/mod.rs | 182 | ||||
-rw-r--r-- | compiler/rustc_mir_transform/src/coverage/query.rs | 57 | ||||
-rw-r--r-- | compiler/rustc_mir_transform/src/coverage/spans.rs | 7 | ||||
-rw-r--r-- | compiler/rustc_mir_transform/src/coverage/test_macros/src/lib.rs | 2 | ||||
-rw-r--r-- | compiler/rustc_mir_transform/src/coverage/tests.rs | 19 |
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() |