1
Fork 0

Auto merge of #114791 - Zalathar:bcb-counter, r=cjgillot

coverage: Give the instrumentor its own counter type, separate from MIR

Within the MIR representation of coverage data, `CoverageKind` is an important part of `StatementKind::Coverage`, but the `InstrumentCoverage` pass also uses it heavily as an internal data structure. This means that any change to `CoverageKind` also needs to update all of the internal parts of `InstrumentCoverage` that manipulate it directly, making the MIR representation difficult to modify.

---

This change fixes that by giving the instrumentor its own `BcbCounter` type for internal use, which is then converted to a `CoverageKind` when injecting coverage information into MIR.

The main change is mostly mechanical, because the initial `BcbCounter` is drop-in compatible with `CoverageKind`, minus the unnecessary `CoverageKind::Unreachable` variant.

I've then removed the `function_source_hash` field from `BcbCounter::Counter`, as a small example of how the two types can now usefully differ from each other. Every counter in a MIR-level function should have the same source hash, so we can supply the hash during the conversion to `CoverageKind::Counter` instead.

---

*Background:* BCB stands for “basic coverage block”, which is a node in the simplified control-flow graph used by coverage instrumentation. The instrumentor pass uses the function's actual MIR control-flow graph to build a simplified BCB graph, then assigns coverage counters and counter expressions to various nodes/edges in that simplified graph, and then finally injects corresponding coverage information into the underlying MIR.
This commit is contained in:
bors 2023-08-20 13:37:47 +00:00
commit 0510a1526d
5 changed files with 146 additions and 102 deletions

View file

@ -96,21 +96,6 @@ pub enum CoverageKind {
Unreachable, Unreachable,
} }
impl CoverageKind {
pub fn as_operand(&self) -> Operand {
use CoverageKind::*;
match *self {
Counter { id, .. } => Operand::Counter(id),
Expression { id, .. } => Operand::Expression(id),
Unreachable => bug!("Unreachable coverage cannot be part of an expression"),
}
}
pub fn is_expression(&self) -> bool {
matches!(self, Self::Expression { .. })
}
}
impl Debug for CoverageKind { impl Debug for CoverageKind {
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
use CoverageKind::*; use CoverageKind::*;

View file

@ -14,36 +14,76 @@ use rustc_index::bit_set::BitSet;
use rustc_index::IndexVec; use rustc_index::IndexVec;
use rustc_middle::mir::coverage::*; use rustc_middle::mir::coverage::*;
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 /// Generates and stores coverage counter and coverage expression information
/// associated with nodes/edges in the BCB graph. /// associated with nodes/edges in the BCB graph.
pub(super) struct CoverageCounters { pub(super) struct CoverageCounters {
function_source_hash: u64,
next_counter_id: CounterId, next_counter_id: CounterId,
next_expression_id: ExpressionId, next_expression_id: ExpressionId,
/// Coverage counters/expressions that are associated with individual BCBs. /// Coverage counters/expressions that are associated with individual BCBs.
bcb_counters: IndexVec<BasicCoverageBlock, Option<CoverageKind>>, bcb_counters: IndexVec<BasicCoverageBlock, Option<BcbCounter>>,
/// Coverage counters/expressions that are associated with the control-flow /// Coverage counters/expressions that are associated with the control-flow
/// edge between two BCBs. /// edge between two BCBs.
bcb_edge_counters: FxHashMap<(BasicCoverageBlock, BasicCoverageBlock), CoverageKind>, bcb_edge_counters: FxHashMap<(BasicCoverageBlock, BasicCoverageBlock), BcbCounter>,
/// Tracks which BCBs have a counter associated with some incoming edge. /// Tracks which BCBs have a counter associated with some incoming edge.
/// Only used by debug assertions, to verify that BCBs with incoming edge /// Only used by debug assertions, to verify that BCBs with incoming edge
/// counters do not have their own physical counters (expressions are allowed). /// counters do not have their own physical counters (expressions are allowed).
bcb_has_incoming_edge_counters: BitSet<BasicCoverageBlock>, bcb_has_incoming_edge_counters: BitSet<BasicCoverageBlock>,
/// Expression nodes that are not directly associated with any particular /// Expression nodes that are not directly associated with any particular
/// BCB/edge, but are needed as operands to more complex expressions. /// BCB/edge, but are needed as operands to more complex expressions.
/// These are always `CoverageKind::Expression`. /// These are always [`BcbCounter::Expression`].
pub(super) intermediate_expressions: Vec<CoverageKind>, pub(super) intermediate_expressions: Vec<BcbCounter>,
pub debug_counters: DebugCounters, pub debug_counters: DebugCounters,
} }
impl CoverageCounters { impl CoverageCounters {
pub(super) fn new(function_source_hash: u64, basic_coverage_blocks: &CoverageGraph) -> Self { pub(super) fn new(basic_coverage_blocks: &CoverageGraph) -> Self {
let num_bcbs = basic_coverage_blocks.num_nodes(); let num_bcbs = basic_coverage_blocks.num_nodes();
Self { Self {
function_source_hash,
next_counter_id: CounterId::START, next_counter_id: CounterId::START,
next_expression_id: ExpressionId::START, next_expression_id: ExpressionId::START,
@ -57,12 +97,12 @@ impl CoverageCounters {
} }
/// Activate the `DebugCounters` data structures, to provide additional debug formatting /// 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) { pub fn enable_debug(&mut self) {
self.debug_counters.enable(); self.debug_counters.enable();
} }
/// Makes `CoverageKind` `Counter`s and `Expressions` for the `BasicCoverageBlock`s directly or /// Makes [`BcbCounter`] `Counter`s and `Expressions` for the `BasicCoverageBlock`s directly or
/// indirectly associated with `CoverageSpans`, and accumulates additional `Expression`s /// indirectly associated with `CoverageSpans`, and accumulates additional `Expression`s
/// representing intermediate values. /// representing intermediate values.
pub fn make_bcb_counters( pub fn make_bcb_counters(
@ -73,14 +113,11 @@ impl CoverageCounters {
MakeBcbCounters::new(self, basic_coverage_blocks).make_bcb_counters(coverage_spans) 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 where
F: Fn() -> Option<String>, F: Fn() -> Option<String>,
{ {
let counter = CoverageKind::Counter { let counter = BcbCounter::Counter { id: self.next_counter() };
function_source_hash: self.function_source_hash,
id: self.next_counter(),
};
if self.debug_counters.is_enabled() { if self.debug_counters.is_enabled() {
self.debug_counters.add_counter(&counter, (debug_block_label_fn)()); self.debug_counters.add_counter(&counter, (debug_block_label_fn)());
} }
@ -93,19 +130,19 @@ impl CoverageCounters {
op: Op, op: Op,
rhs: Operand, rhs: Operand,
debug_block_label_fn: F, debug_block_label_fn: F,
) -> CoverageKind ) -> BcbCounter
where where
F: Fn() -> Option<String>, F: Fn() -> Option<String>,
{ {
let id = self.next_expression(); 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() { if self.debug_counters.is_enabled() {
self.debug_counters.add_counter(&expression, (debug_block_label_fn)()); self.debug_counters.add_counter(&expression, (debug_block_label_fn)());
} }
expression expression
} }
pub fn make_identity_counter(&mut self, counter_operand: Operand) -> CoverageKind { pub fn make_identity_counter(&mut self, counter_operand: Operand) -> BcbCounter {
let some_debug_block_label = if self.debug_counters.is_enabled() { let some_debug_block_label = if self.debug_counters.is_enabled() {
self.debug_counters.some_block_label(counter_operand).cloned() self.debug_counters.some_block_label(counter_operand).cloned()
} else { } else {
@ -134,7 +171,7 @@ impl CoverageCounters {
fn set_bcb_counter( fn set_bcb_counter(
&mut self, &mut self,
bcb: BasicCoverageBlock, bcb: BasicCoverageBlock,
counter_kind: CoverageKind, counter_kind: BcbCounter,
) -> Result<Operand, Error> { ) -> Result<Operand, Error> {
debug_assert!( debug_assert!(
// If the BCB has an edge counter (to be injected into a new `BasicBlock`), it can also // If the BCB has an edge counter (to be injected into a new `BasicBlock`), it can also
@ -158,7 +195,7 @@ impl CoverageCounters {
&mut self, &mut self,
from_bcb: BasicCoverageBlock, from_bcb: BasicCoverageBlock,
to_bcb: BasicCoverageBlock, to_bcb: BasicCoverageBlock,
counter_kind: CoverageKind, counter_kind: BcbCounter,
) -> Result<Operand, Error> { ) -> Result<Operand, Error> {
if level_enabled!(tracing::Level::DEBUG) { if level_enabled!(tracing::Level::DEBUG) {
// If the BCB has an edge counter (to be injected into a new `BasicBlock`), it can also // If the BCB has an edge counter (to be injected into a new `BasicBlock`), it can also
@ -183,17 +220,17 @@ impl CoverageCounters {
} }
} }
pub(super) fn bcb_counter(&self, bcb: BasicCoverageBlock) -> Option<&CoverageKind> { pub(super) fn bcb_counter(&self, bcb: BasicCoverageBlock) -> Option<&BcbCounter> {
self.bcb_counters[bcb].as_ref() self.bcb_counters[bcb].as_ref()
} }
pub(super) fn take_bcb_counter(&mut self, bcb: BasicCoverageBlock) -> Option<CoverageKind> { pub(super) fn take_bcb_counter(&mut self, bcb: BasicCoverageBlock) -> Option<BcbCounter> {
self.bcb_counters[bcb].take() self.bcb_counters[bcb].take()
} }
pub(super) fn drain_bcb_counters( pub(super) fn drain_bcb_counters(
&mut self, &mut self,
) -> impl Iterator<Item = (BasicCoverageBlock, CoverageKind)> + '_ { ) -> impl Iterator<Item = (BasicCoverageBlock, BcbCounter)> + '_ {
self.bcb_counters self.bcb_counters
.iter_enumerated_mut() .iter_enumerated_mut()
.filter_map(|(bcb, counter)| Some((bcb, counter.take()?))) .filter_map(|(bcb, counter)| Some((bcb, counter.take()?)))
@ -201,7 +238,7 @@ impl CoverageCounters {
pub(super) fn drain_bcb_edge_counters( pub(super) fn drain_bcb_edge_counters(
&mut self, &mut self,
) -> impl Iterator<Item = ((BasicCoverageBlock, BasicCoverageBlock), CoverageKind)> + '_ { ) -> impl Iterator<Item = ((BasicCoverageBlock, BasicCoverageBlock), BcbCounter)> + '_ {
self.bcb_edge_counters.drain() self.bcb_edge_counters.drain()
} }
} }
@ -653,7 +690,7 @@ impl<'a> MakeBcbCounters<'a> {
self.branch_counter(branch).is_none() self.branch_counter(branch).is_none()
} }
fn branch_counter(&self, branch: &BcbBranch) -> Option<&CoverageKind> { fn branch_counter(&self, branch: &BcbBranch) -> Option<&BcbCounter> {
let to_bcb = branch.target_bcb; let to_bcb = branch.target_bcb;
if let Some(from_bcb) = branch.edge_from_bcb { if let Some(from_bcb) = branch.edge_from_bcb {
self.coverage_counters.bcb_edge_counters.get(&(from_bcb, to_bcb)) self.coverage_counters.bcb_edge_counters.get(&(from_bcb, to_bcb))
@ -675,7 +712,7 @@ impl<'a> MakeBcbCounters<'a> {
} }
#[inline] #[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) self.coverage_counters.debug_counters.format_counter(counter_kind)
} }
} }

View file

@ -108,7 +108,7 @@
//! recursively, generating labels with nested operations, enclosed in parentheses //! recursively, generating labels with nested operations, enclosed in parentheses
//! (for example: `bcb2 + (bcb0 - bcb1)`). //! (for example: `bcb2 + (bcb0 - bcb1)`).
use super::counters::CoverageCounters; use super::counters::{BcbCounter, CoverageCounters};
use super::graph::{BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph}; use super::graph::{BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph};
use super::spans::CoverageSpan; use super::spans::CoverageSpan;
@ -247,11 +247,11 @@ impl Default for ExpressionFormat {
} }
} }
/// If enabled, this struct maintains a map from `CoverageKind` IDs (as `Operand`) to /// If enabled, this struct maintains a map from `BcbCounter` IDs (as `Operand`) to
/// the `CoverageKind` data and optional label (normally, the counter's associated /// the `BcbCounter` data and optional label (normally, the counter's associated
/// `BasicCoverageBlock` format string, if any). /// `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 /// 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 /// files (including the `CoverageGraph` graphviz file) to be changed at runtime, via environment
/// variable. /// variable.
@ -276,7 +276,7 @@ impl DebugCounters {
self.some_counters.is_some() 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 { if let Some(counters) = &mut self.some_counters {
let id = counter_kind.as_operand(); let id = counter_kind.as_operand();
counters counters
@ -291,21 +291,20 @@ impl DebugCounters {
}) })
} }
pub fn format_counter(&self, counter_kind: &CoverageKind) -> String { pub fn format_counter(&self, counter_kind: &BcbCounter) -> String {
match *counter_kind { match *counter_kind {
CoverageKind::Counter { .. } => { BcbCounter::Counter { .. } => {
format!("Counter({})", self.format_counter_kind(counter_kind)) format!("Counter({})", self.format_counter_kind(counter_kind))
} }
CoverageKind::Expression { .. } => { BcbCounter::Expression { .. } => {
format!("Expression({})", self.format_counter_kind(counter_kind)) 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; 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 { if counter_format.operation {
return format!( return format!(
"{}{} {} {}", "{}{} {} {}",
@ -346,7 +345,7 @@ impl DebugCounters {
} }
if let Some(counters) = &self.some_counters { if let Some(counters) = &self.some_counters {
if let Some(DebugCounter { counter_kind, some_block_label }) = counters.get(&operand) { 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 { if let Some(label) = some_block_label && debug_options().counter_format.block {
return format!( return format!(
"{}:({})", "{}:({})",
@ -366,12 +365,12 @@ impl DebugCounters {
/// A non-public support class to `DebugCounters`. /// A non-public support class to `DebugCounters`.
#[derive(Debug)] #[derive(Debug)]
struct DebugCounter { struct DebugCounter {
counter_kind: CoverageKind, counter_kind: BcbCounter,
some_block_label: Option<String>, some_block_label: Option<String>,
} }
impl DebugCounter { 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 } Self { counter_kind, some_block_label }
} }
} }
@ -380,9 +379,9 @@ impl DebugCounter {
/// a Graphviz (.dot file) representation of the `CoverageGraph`, for debugging purposes. /// a Graphviz (.dot file) representation of the `CoverageGraph`, for debugging purposes.
pub(super) struct GraphvizData { pub(super) struct GraphvizData {
some_bcb_to_coverage_spans_with_counters: some_bcb_to_coverage_spans_with_counters:
Option<FxHashMap<BasicCoverageBlock, Vec<(CoverageSpan, CoverageKind)>>>, Option<FxHashMap<BasicCoverageBlock, Vec<(CoverageSpan, BcbCounter)>>>,
some_bcb_to_dependency_counters: Option<FxHashMap<BasicCoverageBlock, Vec<CoverageKind>>>, some_bcb_to_dependency_counters: Option<FxHashMap<BasicCoverageBlock, Vec<BcbCounter>>>,
some_edge_to_counter: Option<FxHashMap<(BasicCoverageBlock, BasicBlock), CoverageKind>>, some_edge_to_counter: Option<FxHashMap<(BasicCoverageBlock, BasicBlock), BcbCounter>>,
} }
impl GraphvizData { impl GraphvizData {
@ -409,7 +408,7 @@ impl GraphvizData {
&mut self, &mut self,
bcb: BasicCoverageBlock, bcb: BasicCoverageBlock,
coverage_span: &CoverageSpan, coverage_span: &CoverageSpan,
counter_kind: &CoverageKind, counter_kind: &BcbCounter,
) { ) {
if let Some(bcb_to_coverage_spans_with_counters) = if let Some(bcb_to_coverage_spans_with_counters) =
self.some_bcb_to_coverage_spans_with_counters.as_mut() self.some_bcb_to_coverage_spans_with_counters.as_mut()
@ -424,7 +423,7 @@ impl GraphvizData {
pub fn get_bcb_coverage_spans_with_counters( pub fn get_bcb_coverage_spans_with_counters(
&self, &self,
bcb: BasicCoverageBlock, bcb: BasicCoverageBlock,
) -> Option<&[(CoverageSpan, CoverageKind)]> { ) -> Option<&[(CoverageSpan, BcbCounter)]> {
if let Some(bcb_to_coverage_spans_with_counters) = if let Some(bcb_to_coverage_spans_with_counters) =
self.some_bcb_to_coverage_spans_with_counters.as_ref() self.some_bcb_to_coverage_spans_with_counters.as_ref()
{ {
@ -437,7 +436,7 @@ impl GraphvizData {
pub fn add_bcb_dependency_counter( pub fn add_bcb_dependency_counter(
&mut self, &mut self,
bcb: BasicCoverageBlock, bcb: BasicCoverageBlock,
counter_kind: &CoverageKind, counter_kind: &BcbCounter,
) { ) {
if let Some(bcb_to_dependency_counters) = self.some_bcb_to_dependency_counters.as_mut() { if let Some(bcb_to_dependency_counters) = self.some_bcb_to_dependency_counters.as_mut() {
bcb_to_dependency_counters bcb_to_dependency_counters
@ -447,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() { if let Some(bcb_to_dependency_counters) = self.some_bcb_to_dependency_counters.as_ref() {
bcb_to_dependency_counters.get(&bcb).map(Deref::deref) bcb_to_dependency_counters.get(&bcb).map(Deref::deref)
} else { } else {
@ -459,7 +458,7 @@ impl GraphvizData {
&mut self, &mut self,
from_bcb: BasicCoverageBlock, from_bcb: BasicCoverageBlock,
to_bb: BasicBlock, to_bb: BasicBlock,
counter_kind: &CoverageKind, counter_kind: &BcbCounter,
) { ) {
if let Some(edge_to_counter) = self.some_edge_to_counter.as_mut() { if let Some(edge_to_counter) = self.some_edge_to_counter.as_mut() {
edge_to_counter edge_to_counter
@ -472,7 +471,7 @@ impl GraphvizData {
&self, &self,
from_bcb: BasicCoverageBlock, from_bcb: BasicCoverageBlock,
to_bb: BasicBlock, to_bb: BasicBlock,
) -> Option<&CoverageKind> { ) -> Option<&BcbCounter> {
if let Some(edge_to_counter) = self.some_edge_to_counter.as_ref() { if let Some(edge_to_counter) = self.some_edge_to_counter.as_ref() {
edge_to_counter.get(&(from_bcb, to_bb)) edge_to_counter.get(&(from_bcb, to_bb))
} else { } else {
@ -488,7 +487,7 @@ impl GraphvizData {
pub(super) struct UsedExpressions { pub(super) struct UsedExpressions {
some_used_expression_operands: Option<FxHashMap<Operand, Vec<ExpressionId>>>, some_used_expression_operands: Option<FxHashMap<Operand, Vec<ExpressionId>>>,
some_unused_expressions: some_unused_expressions:
Option<Vec<(CoverageKind, Option<BasicCoverageBlock>, BasicCoverageBlock)>>, Option<Vec<(BcbCounter, Option<BasicCoverageBlock>, BasicCoverageBlock)>>,
} }
impl UsedExpressions { impl UsedExpressions {
@ -506,16 +505,16 @@ impl UsedExpressions {
self.some_used_expression_operands.is_some() 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 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(lhs).or_insert_with(Vec::new).push(id);
used_expression_operands.entry(rhs).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() { if let Some(used_expression_operands) = self.some_used_expression_operands.as_ref() {
used_expression_operands.contains_key(&expression.as_operand()) used_expression_operands.contains_key(&expression.as_operand())
} else { } else {
@ -525,7 +524,7 @@ impl UsedExpressions {
pub fn add_unused_expression_if_not_found( pub fn add_unused_expression_if_not_found(
&mut self, &mut self,
expression: &CoverageKind, expression: &BcbCounter,
edge_from_bcb: Option<BasicCoverageBlock>, edge_from_bcb: Option<BasicCoverageBlock>,
target_bcb: BasicCoverageBlock, target_bcb: BasicCoverageBlock,
) { ) {
@ -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`. /// optional `from_bcb` (if it was an edge counter), and `target_bcb`.
pub fn get_unused_expressions( pub fn get_unused_expressions(
&self, &self,
) -> Vec<(CoverageKind, Option<BasicCoverageBlock>, BasicCoverageBlock)> { ) -> Vec<(BcbCounter, Option<BasicCoverageBlock>, BasicCoverageBlock)> {
if let Some(unused_expressions) = self.some_unused_expressions.as_ref() { if let Some(unused_expressions) = self.some_unused_expressions.as_ref() {
unused_expressions.clone() unused_expressions.clone()
} else { } else {
@ -560,7 +559,7 @@ impl UsedExpressions {
bcb_counters_without_direct_coverage_spans: &[( bcb_counters_without_direct_coverage_spans: &[(
Option<BasicCoverageBlock>, Option<BasicCoverageBlock>,
BasicCoverageBlock, BasicCoverageBlock,
CoverageKind, BcbCounter,
)], )],
) { ) {
if self.is_enabled() { if self.is_enabled() {
@ -662,7 +661,7 @@ pub(super) fn dump_coverage_graphviz<'tcx>(
basic_coverage_blocks: &CoverageGraph, basic_coverage_blocks: &CoverageGraph,
coverage_counters: &CoverageCounters, coverage_counters: &CoverageCounters,
graphviz_data: &GraphvizData, graphviz_data: &GraphvizData,
intermediate_expressions: &[CoverageKind], intermediate_expressions: &[BcbCounter],
debug_used_expressions: &UsedExpressions, debug_used_expressions: &UsedExpressions,
) { ) {
let debug_counters = &coverage_counters.debug_counters; let debug_counters = &coverage_counters.debug_counters;
@ -743,9 +742,9 @@ fn bcb_to_string_sections<'tcx>(
coverage_counters: &CoverageCounters, coverage_counters: &CoverageCounters,
bcb: BasicCoverageBlock, bcb: BasicCoverageBlock,
bcb_data: &BasicCoverageBlockData, bcb_data: &BasicCoverageBlockData,
some_coverage_spans_with_counters: Option<&[(CoverageSpan, CoverageKind)]>, some_coverage_spans_with_counters: Option<&[(CoverageSpan, BcbCounter)]>,
some_dependency_counters: Option<&[CoverageKind]>, some_dependency_counters: Option<&[BcbCounter]>,
some_intermediate_expressions: Option<&[CoverageKind]>, some_intermediate_expressions: Option<&[BcbCounter]>,
) -> Vec<String> { ) -> Vec<String> {
let debug_counters = &coverage_counters.debug_counters; let debug_counters = &coverage_counters.debug_counters;

View file

@ -8,9 +8,9 @@ mod spans;
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;
use counters::CoverageCounters; use self::counters::{BcbCounter, CoverageCounters};
use graph::{BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph}; use self::graph::{BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph};
use spans::{CoverageSpan, CoverageSpans}; use self::spans::{CoverageSpan, CoverageSpans};
use crate::MirPass; use crate::MirPass;
@ -106,6 +106,7 @@ struct Instrumentor<'a, 'tcx> {
source_file: Lrc<SourceFile>, source_file: Lrc<SourceFile>,
fn_sig_span: Span, fn_sig_span: Span,
body_span: Span, body_span: Span,
function_source_hash: u64,
basic_coverage_blocks: CoverageGraph, basic_coverage_blocks: CoverageGraph,
coverage_counters: CoverageCounters, coverage_counters: CoverageCounters,
} }
@ -137,7 +138,7 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
let function_source_hash = hash_mir_source(tcx, hir_body); let function_source_hash = hash_mir_source(tcx, hir_body);
let basic_coverage_blocks = CoverageGraph::from_mir(mir_body); let basic_coverage_blocks = CoverageGraph::from_mir(mir_body);
let coverage_counters = CoverageCounters::new(function_source_hash, &basic_coverage_blocks); let coverage_counters = CoverageCounters::new(&basic_coverage_blocks);
Self { Self {
pass_name, pass_name,
@ -146,6 +147,7 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
source_file, source_file,
fn_sig_span, fn_sig_span,
body_span, body_span,
function_source_hash,
basic_coverage_blocks, basic_coverage_blocks,
coverage_counters, coverage_counters,
} }
@ -270,8 +272,11 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
//////////////////////////////////////////////////// ////////////////////////////////////////////////////
// Finally, inject the intermediate expressions collected along the way. // Finally, inject the intermediate expressions collected along the way.
for intermediate_expression in self.coverage_counters.intermediate_expressions.drain(..) { for intermediate_expression in &self.coverage_counters.intermediate_expressions {
inject_intermediate_expression(self.mir_body, intermediate_expression); inject_intermediate_expression(
self.mir_body,
self.make_mir_coverage_kind(intermediate_expression),
);
} }
} }
@ -309,19 +314,14 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
}; };
graphviz_data.add_bcb_coverage_span_with_counter(bcb, &covspan, &counter_kind); graphviz_data.add_bcb_coverage_span_with_counter(bcb, &covspan, &counter_kind);
debug!( let code_region =
"Calling make_code_region(file_name={}, source_file={:?}, span={}, body_span={})", make_code_region(source_map, file_name, &self.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)
);
inject_statement( inject_statement(
self.mir_body, self.mir_body,
counter_kind, self.make_mir_coverage_kind(&counter_kind),
self.bcb_leader_bb(bcb), self.bcb_leader_bb(bcb),
Some(make_code_region(source_map, file_name, &self.source_file, span, body_span)), Some(code_region),
); );
} }
} }
@ -367,7 +367,7 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
); );
match counter_kind { match counter_kind {
CoverageKind::Counter { .. } => { BcbCounter::Counter { .. } => {
let inject_to_bb = if let Some(from_bcb) = edge_from_bcb { let inject_to_bb = if let Some(from_bcb) = edge_from_bcb {
// The MIR edge starts `from_bb` (the outgoing / last BasicBlock in // The MIR edge starts `from_bb` (the outgoing / last BasicBlock in
// `from_bcb`) and ends at `to_bb` (the incoming / first BasicBlock in the // `from_bcb`) and ends at `to_bb` (the incoming / first BasicBlock in the
@ -400,12 +400,17 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
target_bb 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 { .. } => { BcbCounter::Expression { .. } => inject_intermediate_expression(
inject_intermediate_expression(self.mir_body, counter_kind) self.mir_body,
} self.make_mir_coverage_kind(&counter_kind),
_ => bug!("CoverageKind should be a counter"), ),
} }
} }
} }
@ -426,9 +431,20 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
} }
#[inline] #[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) 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 }
}
}
}
} }
fn inject_edge_counter_basic_block( fn inject_edge_counter_basic_block(
@ -498,6 +514,14 @@ fn make_code_region(
span: Span, span: Span,
body_span: Span, body_span: Span,
) -> CodeRegion { ) -> 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 (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, end_col) = if span.hi() == span.lo() {
let (end_line, mut end_col) = (start_line, start_col); let (end_line, mut end_col) = (start_line, start_col);

View file

@ -34,7 +34,6 @@ use itertools::Itertools;
use rustc_data_structures::graph::WithNumNodes; use rustc_data_structures::graph::WithNumNodes;
use rustc_data_structures::graph::WithSuccessors; use rustc_data_structures::graph::WithSuccessors;
use rustc_index::{Idx, IndexVec}; use rustc_index::{Idx, IndexVec};
use rustc_middle::mir::coverage::CoverageKind;
use rustc_middle::mir::*; use rustc_middle::mir::*;
use rustc_middle::ty; use rustc_middle::ty;
use rustc_span::{self, BytePos, Pos, Span, DUMMY_SP}; use rustc_span::{self, BytePos, Pos, Span, DUMMY_SP};
@ -675,8 +674,8 @@ fn test_make_bcb_counters() {
)); ));
} }
} }
let mut coverage_counters = counters::CoverageCounters::new(0, &basic_coverage_blocks); let mut coverage_counters = counters::CoverageCounters::new(&basic_coverage_blocks);
let () = coverage_counters coverage_counters
.make_bcb_counters(&mut basic_coverage_blocks, &coverage_spans) .make_bcb_counters(&mut basic_coverage_blocks, &coverage_spans)
.expect("should be Ok"); .expect("should be Ok");
assert_eq!(coverage_counters.intermediate_expressions.len(), 0); assert_eq!(coverage_counters.intermediate_expressions.len(), 0);
@ -685,7 +684,7 @@ fn test_make_bcb_counters() {
assert_eq!( assert_eq!(
0, // bcb1 has a `Counter` with id = 0 0, // bcb1 has a `Counter` with id = 0
match coverage_counters.bcb_counter(bcb1).expect("should have a counter") { match coverage_counters.bcb_counter(bcb1).expect("should have a counter") {
CoverageKind::Counter { id, .. } => id, counters::BcbCounter::Counter { id, .. } => id,
_ => panic!("expected a Counter"), _ => panic!("expected a Counter"),
} }
.as_u32() .as_u32()
@ -695,7 +694,7 @@ fn test_make_bcb_counters() {
assert_eq!( assert_eq!(
1, // bcb2 has a `Counter` with id = 1 1, // bcb2 has a `Counter` with id = 1
match coverage_counters.bcb_counter(bcb2).expect("should have a counter") { match coverage_counters.bcb_counter(bcb2).expect("should have a counter") {
CoverageKind::Counter { id, .. } => id, counters::BcbCounter::Counter { id, .. } => id,
_ => panic!("expected a Counter"), _ => panic!("expected a Counter"),
} }
.as_u32() .as_u32()