Replace ExpressionOperandId with enum Operand

Because the three kinds of operand are now distinguished explicitly, we no
longer need fiddly code to disambiguate counter IDs and expression IDs based on
the total number of counters/expressions in a function.

This does increase the size of operands from 4 bytes to 8 bytes, but that
shouldn't be a big deal since they are mostly stored inside boxed structures,
and the current coverage code is not particularly size-optimized anyway.
This commit is contained in:
Zalathar 2023-06-26 22:28:48 +10:00
parent 5a808d40f4
commit 1a014d42f4
11 changed files with 96 additions and 147 deletions

View file

@ -3,17 +3,17 @@ pub use super::ffi::*;
use rustc_index::{IndexSlice, IndexVec}; use rustc_index::{IndexSlice, IndexVec};
use rustc_middle::bug; use rustc_middle::bug;
use rustc_middle::mir::coverage::{ use rustc_middle::mir::coverage::{
CodeRegion, CounterValueReference, ExpressionOperandId, InjectedExpressionId, CodeRegion, CounterValueReference, InjectedExpressionId, InjectedExpressionIndex,
InjectedExpressionIndex, MappedExpressionIndex, Op, MappedExpressionIndex, Op, Operand,
}; };
use rustc_middle::ty::Instance; use rustc_middle::ty::Instance;
use rustc_middle::ty::TyCtxt; use rustc_middle::ty::TyCtxt;
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct Expression { pub struct Expression {
lhs: ExpressionOperandId, lhs: Operand,
op: Op, op: Op,
rhs: ExpressionOperandId, rhs: Operand,
region: Option<CodeRegion>, region: Option<CodeRegion>,
} }
@ -105,16 +105,16 @@ impl<'tcx> FunctionCoverage<'tcx> {
pub fn add_counter_expression( pub fn add_counter_expression(
&mut self, &mut self,
expression_id: InjectedExpressionId, expression_id: InjectedExpressionId,
lhs: ExpressionOperandId, lhs: Operand,
op: Op, op: Op,
rhs: ExpressionOperandId, rhs: Operand,
region: Option<CodeRegion>, region: Option<CodeRegion>,
) { ) {
debug!( debug!(
"add_counter_expression({:?}, lhs={:?}, op={:?}, rhs={:?} at {:?}", "add_counter_expression({:?}, lhs={:?}, op={:?}, rhs={:?} at {:?}",
expression_id, lhs, op, rhs, region expression_id, lhs, op, rhs, region
); );
let expression_index = self.expression_index(u32::from(expression_id)); let expression_index = self.expression_index(expression_id);
debug_assert!( debug_assert!(
expression_index.as_usize() < self.expressions.len(), expression_index.as_usize() < self.expressions.len(),
"expression_index {} is out of range for expressions.len() = {} "expression_index {} is out of range for expressions.len() = {}
@ -186,10 +186,7 @@ impl<'tcx> FunctionCoverage<'tcx> {
// This closure converts any `Expression` operand (`lhs` or `rhs` of the `Op::Add` or // This closure converts any `Expression` operand (`lhs` or `rhs` of the `Op::Add` or
// `Op::Subtract` operation) into its native `llvm::coverage::Counter::CounterKind` type // `Op::Subtract` operation) into its native `llvm::coverage::Counter::CounterKind` type
// and value. Operand ID value `0` maps to `CounterKind::Zero`; values in the known range // and value.
// of injected LLVM counters map to `CounterKind::CounterValueReference` (and the value
// matches the injected counter index); and any other value is converted into a
// `CounterKind::Expression` with the expression's `new_index`.
// //
// Expressions will be returned from this function in a sequential vector (array) of // Expressions will be returned from this function in a sequential vector (array) of
// `CounterExpression`, so the expression IDs must be mapped from their original, // `CounterExpression`, so the expression IDs must be mapped from their original,
@ -206,17 +203,13 @@ impl<'tcx> FunctionCoverage<'tcx> {
// `expression_index`s lower than the referencing `Expression`. Therefore, it is // `expression_index`s lower than the referencing `Expression`. Therefore, it is
// reasonable to look up the new index of an expression operand while the `new_indexes` // reasonable to look up the new index of an expression operand while the `new_indexes`
// vector is only complete up to the current `ExpressionIndex`. // vector is only complete up to the current `ExpressionIndex`.
let id_to_counter = |new_indexes: &IndexSlice< type NewIndexes = IndexSlice<InjectedExpressionIndex, Option<MappedExpressionIndex>>;
InjectedExpressionIndex, let id_to_counter = |new_indexes: &NewIndexes, operand: Operand| match operand {
Option<MappedExpressionIndex>, Operand::Zero => Some(Counter::zero()),
>, Operand::Counter(id) => {
id: ExpressionOperandId| {
if id == ExpressionOperandId::ZERO {
Some(Counter::zero())
} else if id.index() < self.counters.len() {
debug_assert!( debug_assert!(
id.index() > 0, id.index() > 0,
"ExpressionOperandId indexes for counters are 1-based, but this id={}", "Operand::Counter indexes for counters are 1-based, but this id={}",
id.index() id.index()
); );
// Note: Some codegen-injected Counters may be only referenced by `Expression`s, // Note: Some codegen-injected Counters may be only referenced by `Expression`s,
@ -224,8 +217,9 @@ impl<'tcx> FunctionCoverage<'tcx> {
let index = CounterValueReference::from(id.index()); let index = CounterValueReference::from(id.index());
// Note, the conversion to LLVM `Counter` adjusts the index to be zero-based. // Note, the conversion to LLVM `Counter` adjusts the index to be zero-based.
Some(Counter::counter_value_reference(index)) Some(Counter::counter_value_reference(index))
} else { }
let index = self.expression_index(u32::from(id)); Operand::Expression(id) => {
let index = self.expression_index(id);
self.expressions self.expressions
.get(index) .get(index)
.expect("expression id is out of range") .expect("expression id is out of range")
@ -341,8 +335,9 @@ impl<'tcx> FunctionCoverage<'tcx> {
self.unreachable_regions.iter().map(|region| (Counter::zero(), region)) self.unreachable_regions.iter().map(|region| (Counter::zero(), region))
} }
fn expression_index(&self, id_descending_from_max: u32) -> InjectedExpressionIndex { fn expression_index(&self, id: InjectedExpressionId) -> InjectedExpressionIndex {
debug_assert!(id_descending_from_max >= self.counters.len() as u32); debug_assert!(id.as_usize() >= self.counters.len());
let id_descending_from_max = id.as_u32();
InjectedExpressionIndex::from(u32::MAX - id_descending_from_max) InjectedExpressionIndex::from(u32::MAX - id_descending_from_max)
} }
} }

View file

@ -17,7 +17,7 @@ use rustc_hir::def_id::DefId;
use rustc_llvm::RustString; use rustc_llvm::RustString;
use rustc_middle::bug; use rustc_middle::bug;
use rustc_middle::mir::coverage::{ use rustc_middle::mir::coverage::{
CodeRegion, CounterValueReference, CoverageKind, ExpressionOperandId, InjectedExpressionId, Op, CodeRegion, CounterValueReference, CoverageKind, InjectedExpressionId, Op, Operand,
}; };
use rustc_middle::mir::Coverage; use rustc_middle::mir::Coverage;
use rustc_middle::ty; use rustc_middle::ty;
@ -203,9 +203,9 @@ impl<'tcx> Builder<'_, '_, 'tcx> {
&mut self, &mut self,
instance: Instance<'tcx>, instance: Instance<'tcx>,
id: InjectedExpressionId, id: InjectedExpressionId,
lhs: ExpressionOperandId, lhs: Operand,
op: Op, op: Op,
rhs: ExpressionOperandId, rhs: Operand,
region: Option<CodeRegion>, region: Option<CodeRegion>,
) -> bool { ) -> bool {
if let Some(coverage_context) = self.coverage_context() { if let Some(coverage_context) = self.coverage_context() {

View file

@ -5,32 +5,6 @@ use rustc_span::Symbol;
use std::fmt::{self, Debug, Formatter}; use std::fmt::{self, Debug, Formatter};
rustc_index::newtype_index! {
/// An ExpressionOperandId value is assigned directly from either a
/// CounterValueReference.as_u32() (which ascend from 1) or an ExpressionOperandId.as_u32()
/// (which _*descend*_ from u32::MAX). Id value `0` (zero) represents a virtual counter with a
/// constant value of `0`.
#[derive(HashStable)]
#[max = 0xFFFF_FFFF]
#[debug_format = "ExpressionOperandId({})"]
pub struct ExpressionOperandId {
}
}
impl ExpressionOperandId {
/// An expression operand for a "zero counter", as described in the following references:
///
/// * <https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/docs/CoverageMappingFormat.rst#counter>
/// * <https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/docs/CoverageMappingFormat.rst#tag>
/// * <https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/docs/CoverageMappingFormat.rst#counter-expressions>
///
/// This operand can be used to count two or more separate code regions with a single counter,
/// if they run sequentially with no branches, by injecting the `Counter` in a `BasicBlock` for
/// one of the code regions, and inserting `CounterExpression`s ("add ZERO to the counter") in
/// the coverage map for the other code regions.
pub const ZERO: Self = Self::from_u32(0);
}
rustc_index::newtype_index! { rustc_index::newtype_index! {
#[derive(HashStable)] #[derive(HashStable)]
#[max = 0xFFFF_FFFF] #[max = 0xFFFF_FFFF]
@ -39,7 +13,7 @@ rustc_index::newtype_index! {
} }
impl CounterValueReference { impl CounterValueReference {
/// Counters start at 1 to reserve 0 for ExpressionOperandId::ZERO. /// Counters start at 1 for historical reasons.
pub const START: Self = Self::from_u32(1); pub const START: Self = Self::from_u32(1);
/// Returns explicitly-requested zero-based version of the counter id, used /// Returns explicitly-requested zero-based version of the counter id, used
@ -52,8 +26,6 @@ impl CounterValueReference {
} }
rustc_index::newtype_index! { rustc_index::newtype_index! {
/// InjectedExpressionId.as_u32() converts to ExpressionOperandId.as_u32()
///
/// Values descend from u32::MAX. /// Values descend from u32::MAX.
#[derive(HashStable)] #[derive(HashStable)]
#[max = 0xFFFF_FFFF] #[max = 0xFFFF_FFFF]
@ -62,8 +34,6 @@ rustc_index::newtype_index! {
} }
rustc_index::newtype_index! { rustc_index::newtype_index! {
/// InjectedExpressionIndex.as_u32() translates to u32::MAX - ExpressionOperandId.as_u32()
///
/// Values ascend from 0. /// Values ascend from 0.
#[derive(HashStable)] #[derive(HashStable)]
#[max = 0xFFFF_FFFF] #[max = 0xFFFF_FFFF]
@ -81,17 +51,25 @@ rustc_index::newtype_index! {
pub struct MappedExpressionIndex {} pub struct MappedExpressionIndex {}
} }
impl From<CounterValueReference> for ExpressionOperandId { /// Operand of a coverage-counter expression.
#[inline] ///
fn from(v: CounterValueReference) -> ExpressionOperandId { /// Operands can be a constant zero value, an actual coverage counter, or another
ExpressionOperandId::from(v.as_u32()) /// expression. Counter/expression operands are referred to by ID.
} #[derive(Copy, Clone, PartialEq, Eq)]
#[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)]
pub enum Operand {
Zero,
Counter(CounterValueReference),
Expression(InjectedExpressionId),
} }
impl From<InjectedExpressionId> for ExpressionOperandId { impl Debug for Operand {
#[inline] fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
fn from(v: InjectedExpressionId) -> ExpressionOperandId { match self {
ExpressionOperandId::from(v.as_u32()) Self::Zero => write!(f, "Zero"),
Self::Counter(id) => f.debug_tuple("Counter").field(&id.as_u32()).finish(),
Self::Expression(id) => f.debug_tuple("Expression").field(&id.as_u32()).finish(),
}
} }
} }
@ -107,19 +85,19 @@ pub enum CoverageKind {
/// ID of this coverage-counter expression within its enclosing function. /// ID of this coverage-counter expression within its enclosing function.
/// Other expressions in the same function can refer to it as an operand. /// Other expressions in the same function can refer to it as an operand.
id: InjectedExpressionId, id: InjectedExpressionId,
lhs: ExpressionOperandId, lhs: Operand,
op: Op, op: Op,
rhs: ExpressionOperandId, rhs: Operand,
}, },
Unreachable, Unreachable,
} }
impl CoverageKind { impl CoverageKind {
pub fn as_operand_id(&self) -> ExpressionOperandId { pub fn as_operand(&self) -> Operand {
use CoverageKind::*; use CoverageKind::*;
match *self { match *self {
Counter { id, .. } => ExpressionOperandId::from(id), Counter { id, .. } => Operand::Counter(id),
Expression { id, .. } => ExpressionOperandId::from(id), Expression { id, .. } => Operand::Expression(id),
Unreachable => bug!("Unreachable coverage cannot be part of an expression"), Unreachable => bug!("Unreachable coverage cannot be part of an expression"),
} }
} }
@ -136,14 +114,14 @@ impl Debug for CoverageKind {
Counter { id, .. } => write!(fmt, "Counter({:?})", id.index()), Counter { id, .. } => write!(fmt, "Counter({:?})", id.index()),
Expression { id, lhs, op, rhs } => write!( Expression { id, lhs, op, rhs } => write!(
fmt, fmt,
"Expression({:?}) = {} {} {}", "Expression({:?}) = {:?} {} {:?}",
id.index(), id.index(),
lhs.index(), lhs,
match op { match op {
Op::Add => "+", Op::Add => "+",
Op::Subtract => "-", Op::Subtract => "-",
}, },
rhs.index(), rhs,
), ),
Unreachable => write!(fmt, "Unreachable"), Unreachable => write!(fmt, "Unreachable"),
} }

View file

@ -470,7 +470,6 @@ TrivialTypeTraversalAndLiftImpls! {
::rustc_hir::Unsafety, ::rustc_hir::Unsafety,
::rustc_target::asm::InlineAsmRegOrRegClass, ::rustc_target::asm::InlineAsmRegOrRegClass,
::rustc_target::spec::abi::Abi, ::rustc_target::spec::abi::Abi,
crate::mir::coverage::ExpressionOperandId,
crate::mir::coverage::CounterValueReference, crate::mir::coverage::CounterValueReference,
crate::mir::coverage::InjectedExpressionId, crate::mir::coverage::InjectedExpressionId,
crate::mir::coverage::InjectedExpressionIndex, crate::mir::coverage::InjectedExpressionIndex,

View file

@ -65,9 +65,9 @@ impl CoverageCounters {
fn make_expression<F>( fn make_expression<F>(
&mut self, &mut self,
lhs: ExpressionOperandId, lhs: Operand,
op: Op, op: Op,
rhs: ExpressionOperandId, rhs: Operand,
debug_block_label_fn: F, debug_block_label_fn: F,
) -> CoverageKind ) -> CoverageKind
where where
@ -81,13 +81,13 @@ impl CoverageCounters {
expression expression
} }
pub fn make_identity_counter(&mut self, counter_operand: ExpressionOperandId) -> CoverageKind { pub fn make_identity_counter(&mut self, counter_operand: Operand) -> CoverageKind {
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 {
None None
}; };
self.make_expression(counter_operand, Op::Add, ExpressionOperandId::ZERO, || { self.make_expression(counter_operand, Op::Add, Operand::Zero, || {
some_debug_block_label.clone() some_debug_block_label.clone()
}) })
} }
@ -199,7 +199,7 @@ impl<'a> BcbCounters<'a> {
&mut self, &mut self,
traversal: &mut TraverseCoverageGraphWithLoops, traversal: &mut TraverseCoverageGraphWithLoops,
branching_bcb: BasicCoverageBlock, branching_bcb: BasicCoverageBlock,
branching_counter_operand: ExpressionOperandId, branching_counter_operand: Operand,
collect_intermediate_expressions: &mut Vec<CoverageKind>, collect_intermediate_expressions: &mut Vec<CoverageKind>,
) -> Result<(), Error> { ) -> Result<(), Error> {
let branches = self.bcb_branches(branching_bcb); let branches = self.bcb_branches(branching_bcb);
@ -261,7 +261,7 @@ impl<'a> BcbCounters<'a> {
" [new intermediate expression: {}]", " [new intermediate expression: {}]",
self.format_counter(&intermediate_expression) self.format_counter(&intermediate_expression)
); );
let intermediate_expression_operand = intermediate_expression.as_operand_id(); let intermediate_expression_operand = intermediate_expression.as_operand();
collect_intermediate_expressions.push(intermediate_expression); collect_intermediate_expressions.push(intermediate_expression);
some_sumup_counter_operand.replace(intermediate_expression_operand); some_sumup_counter_operand.replace(intermediate_expression_operand);
} }
@ -298,7 +298,7 @@ impl<'a> BcbCounters<'a> {
&mut self, &mut self,
bcb: BasicCoverageBlock, bcb: BasicCoverageBlock,
collect_intermediate_expressions: &mut Vec<CoverageKind>, collect_intermediate_expressions: &mut Vec<CoverageKind>,
) -> Result<ExpressionOperandId, Error> { ) -> Result<Operand, Error> {
self.recursive_get_or_make_counter_operand(bcb, collect_intermediate_expressions, 1) self.recursive_get_or_make_counter_operand(bcb, collect_intermediate_expressions, 1)
} }
@ -307,7 +307,7 @@ impl<'a> BcbCounters<'a> {
bcb: BasicCoverageBlock, bcb: BasicCoverageBlock,
collect_intermediate_expressions: &mut Vec<CoverageKind>, collect_intermediate_expressions: &mut Vec<CoverageKind>,
debug_indent_level: usize, debug_indent_level: usize,
) -> Result<ExpressionOperandId, Error> { ) -> Result<Operand, Error> {
// If the BCB already has a counter, return it. // 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.basic_coverage_blocks[bcb].counter() {
debug!( debug!(
@ -316,7 +316,7 @@ impl<'a> BcbCounters<'a> {
bcb, bcb,
self.format_counter(counter_kind), 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()`). // A BCB with only one incoming edge gets a simple `Counter` (via `make_counter()`).
@ -383,7 +383,7 @@ impl<'a> BcbCounters<'a> {
NESTED_INDENT.repeat(debug_indent_level), NESTED_INDENT.repeat(debug_indent_level),
self.format_counter(&intermediate_expression) self.format_counter(&intermediate_expression)
); );
let intermediate_expression_operand = intermediate_expression.as_operand_id(); let intermediate_expression_operand = intermediate_expression.as_operand();
collect_intermediate_expressions.push(intermediate_expression); collect_intermediate_expressions.push(intermediate_expression);
some_sumup_edge_counter_operand.replace(intermediate_expression_operand); some_sumup_edge_counter_operand.replace(intermediate_expression_operand);
} }
@ -408,7 +408,7 @@ impl<'a> BcbCounters<'a> {
from_bcb: BasicCoverageBlock, from_bcb: BasicCoverageBlock,
to_bcb: BasicCoverageBlock, to_bcb: BasicCoverageBlock,
collect_intermediate_expressions: &mut Vec<CoverageKind>, collect_intermediate_expressions: &mut Vec<CoverageKind>,
) -> Result<ExpressionOperandId, Error> { ) -> Result<Operand, Error> {
self.recursive_get_or_make_edge_counter_operand( self.recursive_get_or_make_edge_counter_operand(
from_bcb, from_bcb,
to_bcb, to_bcb,
@ -423,7 +423,7 @@ impl<'a> BcbCounters<'a> {
to_bcb: BasicCoverageBlock, to_bcb: BasicCoverageBlock,
collect_intermediate_expressions: &mut Vec<CoverageKind>, collect_intermediate_expressions: &mut Vec<CoverageKind>,
debug_indent_level: usize, 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 // 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. // counter is unnecessary. Just get or make a counter for the source BCB.
let successors = self.bcb_successors(from_bcb).iter(); let successors = self.bcb_successors(from_bcb).iter();
@ -444,7 +444,7 @@ impl<'a> BcbCounters<'a> {
to_bcb, to_bcb,
self.format_counter(counter_kind) 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. // Make a new counter to count this edge.

View file

@ -246,7 +246,7 @@ impl Default for ExpressionFormat {
} }
} }
/// If enabled, this struct maintains a map from `CoverageKind` IDs (as `ExpressionOperandId`) to /// If enabled, this struct maintains a map from `CoverageKind` IDs (as `Operand`) to
/// the `CoverageKind` data and optional label (normally, the counter's associated /// the `CoverageKind` data and optional label (normally, the counter's associated
/// `BasicCoverageBlock` format string, if any). /// `BasicCoverageBlock` format string, if any).
/// ///
@ -258,7 +258,7 @@ impl Default for ExpressionFormat {
/// `DebugCounters` supports a recursive rendering of `Expression` counters, so they can be /// `DebugCounters` supports a recursive rendering of `Expression` counters, so they can be
/// presented as nested expressions such as `(bcb3 - (bcb0 + bcb1))`. /// presented as nested expressions such as `(bcb3 - (bcb0 + bcb1))`.
pub(super) struct DebugCounters { pub(super) struct DebugCounters {
some_counters: Option<FxHashMap<ExpressionOperandId, DebugCounter>>, some_counters: Option<FxHashMap<Operand, DebugCounter>>,
} }
impl DebugCounters { impl DebugCounters {
@ -277,14 +277,14 @@ impl DebugCounters {
pub fn add_counter(&mut self, counter_kind: &CoverageKind, some_block_label: Option<String>) { pub fn add_counter(&mut self, counter_kind: &CoverageKind, 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_id(); let id = counter_kind.as_operand();
counters counters
.try_insert(id, DebugCounter::new(counter_kind.clone(), some_block_label)) .try_insert(id, DebugCounter::new(counter_kind.clone(), some_block_label))
.expect("attempt to add the same counter_kind to DebugCounters more than once"); .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| { self.some_counters.as_ref().and_then(|counters| {
counters.get(&operand).and_then(|debug_counter| debug_counter.some_block_label.as_ref()) counters.get(&operand).and_then(|debug_counter| debug_counter.some_block_label.as_ref())
}) })
@ -323,24 +323,24 @@ 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) { if self.some_counters.is_some() && (counter_format.block || !counter_format.id) {
let counters = self.some_counters.as_ref().unwrap(); let counters = self.some_counters.as_ref().unwrap();
if let Some(DebugCounter { some_block_label: Some(block_label), .. }) = if let Some(DebugCounter { some_block_label: Some(block_label), .. }) =
counters.get(&id) counters.get(&id)
{ {
return if counter_format.id { return if counter_format.id {
format!("{}#{}", block_label, id.index()) format!("{}#{:?}", block_label, id)
} else { } else {
block_label.to_string() block_label.to_string()
}; };
} }
} }
format!("#{}", id.index()) format!("#{:?}", id)
} }
fn format_operand(&self, operand: ExpressionOperandId) -> String { fn format_operand(&self, operand: Operand) -> String {
if operand.index() == 0 { if matches!(operand, Operand::Zero) {
return String::from("0"); return String::from("0");
} }
if let Some(counters) = &self.some_counters { if let Some(counters) = &self.some_counters {
@ -358,7 +358,7 @@ impl DebugCounters {
return self.format_counter_kind(counter_kind); return self.format_counter_kind(counter_kind);
} }
} }
format!("#{}", operand.index()) format!("#{:?}", operand)
} }
} }
@ -485,8 +485,7 @@ impl GraphvizData {
/// _not_ used are retained in the `unused_expressions` Vec, to be included in debug output (logs /// _not_ used are retained in the `unused_expressions` Vec, to be included in debug output (logs
/// and/or a `CoverageGraph` graphviz output). /// and/or a `CoverageGraph` graphviz output).
pub(super) struct UsedExpressions { pub(super) struct UsedExpressions {
some_used_expression_operands: some_used_expression_operands: Option<FxHashMap<Operand, Vec<InjectedExpressionId>>>,
Option<FxHashMap<ExpressionOperandId, Vec<InjectedExpressionId>>>,
some_unused_expressions: some_unused_expressions:
Option<Vec<(CoverageKind, Option<BasicCoverageBlock>, BasicCoverageBlock)>>, Option<Vec<(CoverageKind, Option<BasicCoverageBlock>, BasicCoverageBlock)>>,
} }
@ -517,7 +516,7 @@ impl UsedExpressions {
pub fn expression_is_used(&self, expression: &CoverageKind) -> bool { pub fn expression_is_used(&self, expression: &CoverageKind) -> 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_id()) used_expression_operands.contains_key(&expression.as_operand())
} else { } else {
false false
} }
@ -530,7 +529,7 @@ impl UsedExpressions {
target_bcb: BasicCoverageBlock, target_bcb: BasicCoverageBlock,
) { ) {
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() {
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(( self.some_unused_expressions.as_mut().unwrap().push((
expression.clone(), expression.clone(),
edge_from_bcb, edge_from_bcb,

View file

@ -345,10 +345,7 @@ impl BasicCoverageBlockData {
&mir_body[self.last_bb()].terminator() &mir_body[self.last_bb()].terminator()
} }
pub fn set_counter( pub fn set_counter(&mut self, counter_kind: CoverageKind) -> Result<Operand, Error> {
&mut self,
counter_kind: CoverageKind,
) -> Result<ExpressionOperandId, 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
// have an expression (to be injected into an existing `BasicBlock` represented by this // have an expression (to be injected into an existing `BasicBlock` represented by this
@ -356,7 +353,7 @@ impl BasicCoverageBlockData {
self.edge_from_bcbs.is_none() || counter_kind.is_expression(), self.edge_from_bcbs.is_none() || counter_kind.is_expression(),
"attempt to add a `Counter` to a BCB target with existing incoming edge counters" "attempt to add a `Counter` to a BCB target with existing incoming edge counters"
); );
let operand = counter_kind.as_operand_id(); let operand = counter_kind.as_operand();
if let Some(replaced) = self.counter_kind.replace(counter_kind) { if let Some(replaced) = self.counter_kind.replace(counter_kind) {
Error::from_string(format!( Error::from_string(format!(
"attempt to set a BasicCoverageBlock coverage counter more than once; \ "attempt to set a BasicCoverageBlock coverage counter more than once; \
@ -381,7 +378,7 @@ impl BasicCoverageBlockData {
&mut self, &mut self,
from_bcb: BasicCoverageBlock, from_bcb: BasicCoverageBlock,
counter_kind: CoverageKind, counter_kind: CoverageKind,
) -> Result<ExpressionOperandId, 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
// have an expression (to be injected into an existing `BasicBlock` represented by this // have an expression (to be injected into an existing `BasicBlock` represented by this
@ -393,7 +390,7 @@ impl BasicCoverageBlockData {
)); ));
} }
} }
let operand = counter_kind.as_operand_id(); let operand = counter_kind.as_operand();
if let Some(replaced) = if let Some(replaced) =
self.edge_from_bcbs.get_or_insert_default().insert(from_bcb, counter_kind) self.edge_from_bcbs.get_or_insert_default().insert(from_bcb, counter_kind)
{ {

View file

@ -304,7 +304,7 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
let counter_kind = if let Some(&counter_operand) = bcb_counters[bcb].as_ref() { let counter_kind = if let Some(&counter_operand) = bcb_counters[bcb].as_ref() {
self.coverage_counters.make_identity_counter(counter_operand) self.coverage_counters.make_identity_counter(counter_operand)
} else if let Some(counter_kind) = self.bcb_data_mut(bcb).take_counter() { } else if let Some(counter_kind) = self.bcb_data_mut(bcb).take_counter() {
bcb_counters[bcb] = Some(counter_kind.as_operand_id()); bcb_counters[bcb] = Some(counter_kind.as_operand());
debug_used_expressions.add_expression_operands(&counter_kind); debug_used_expressions.add_expression_operands(&counter_kind);
counter_kind counter_kind
} else { } else {

View file

@ -47,39 +47,24 @@ impl CoverageVisitor {
/// final computed number of counters should be the number of all `CoverageKind::Counter` /// final computed number of counters should be the number of all `CoverageKind::Counter`
/// statements in the MIR *plus one* for the implicit `ZERO` counter. /// statements in the MIR *plus one* for the implicit `ZERO` counter.
#[inline(always)] #[inline(always)]
fn update_num_counters(&mut self, counter_id: u32) { fn update_num_counters(&mut self, counter_id: CounterValueReference) {
let counter_id = counter_id.as_u32();
self.info.num_counters = std::cmp::max(self.info.num_counters, counter_id + 1); 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 /// Computes an expression index for each expression ID, and updates `num_expressions` to the
/// maximum encountered index plus 1. /// maximum encountered index plus 1.
#[inline(always)] #[inline(always)]
fn update_num_expressions(&mut self, expression_id: u32) { fn update_num_expressions(&mut self, expression_id: InjectedExpressionId) {
let expression_index = u32::MAX - expression_id; let expression_index = u32::MAX - expression_id.as_u32();
self.info.num_expressions = std::cmp::max(self.info.num_expressions, expression_index + 1); self.info.num_expressions = std::cmp::max(self.info.num_expressions, expression_index + 1);
} }
fn update_from_expression_operand(&mut self, operand_id: u32) { fn update_from_expression_operand(&mut self, operand: Operand) {
if operand_id >= self.info.num_counters { match operand {
let operand_as_expression_index = u32::MAX - operand_id; Operand::Counter(id) => self.update_num_counters(id),
if operand_as_expression_index >= self.info.num_expressions { Operand::Expression(id) => self.update_num_expressions(id),
// The operand ID is outside the known range of counter IDs and also outside the Operand::Zero => {}
// 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)
}
}
} }
} }
@ -100,19 +85,15 @@ impl CoverageVisitor {
if self.add_missing_operands { if self.add_missing_operands {
match coverage.kind { match coverage.kind {
CoverageKind::Expression { lhs, rhs, .. } => { CoverageKind::Expression { lhs, rhs, .. } => {
self.update_from_expression_operand(u32::from(lhs)); self.update_from_expression_operand(lhs);
self.update_from_expression_operand(u32::from(rhs)); self.update_from_expression_operand(rhs);
} }
_ => {} _ => {}
} }
} else { } else {
match coverage.kind { match coverage.kind {
CoverageKind::Counter { id, .. } => { CoverageKind::Counter { id, .. } => self.update_num_counters(id),
self.update_num_counters(u32::from(id)); CoverageKind::Expression { id, .. } => self.update_num_expressions(id),
}
CoverageKind::Expression { id, .. } => {
self.update_num_expressions(u32::from(id));
}
_ => {} _ => {}
} }
} }

View file

@ -3,7 +3,7 @@ digraph Cov_0_3 {
node [fontname="Courier, monospace"]; node [fontname="Courier, monospace"];
edge [fontname="Courier, monospace"]; edge [fontname="Courier, monospace"];
bcb3__Cov_0_3 [shape="none", label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="gray" align="center" colspan="1">bcb3</td></tr><tr><td align="left" balign="left">Counter(bcb3) at 13:10-13:10<br align="left"/> 13:10-13:10: @5[0]: Coverage::Counter(2) for $DIR/coverage_graphviz.rs:13:10 - 13:11</td></tr><tr><td align="left" balign="left">bb5: Goto</td></tr></table>>]; bcb3__Cov_0_3 [shape="none", label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="gray" align="center" colspan="1">bcb3</td></tr><tr><td align="left" balign="left">Counter(bcb3) at 13:10-13:10<br align="left"/> 13:10-13:10: @5[0]: Coverage::Counter(2) for $DIR/coverage_graphviz.rs:13:10 - 13:11</td></tr><tr><td align="left" balign="left">bb5: Goto</td></tr></table>>];
bcb2__Cov_0_3 [shape="none", label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="gray" align="center" colspan="1">bcb2</td></tr><tr><td align="left" balign="left">Expression(bcb1:(bcb0 + bcb3) - bcb3) at 12:13-12:18<br align="left"/> 12:13-12:18: @4[0]: Coverage::Expression(4294967293) = 4294967294 + 0 for $DIR/coverage_graphviz.rs:15:1 - 15:2<br align="left"/>Expression(bcb2:(bcb1:(bcb0 + bcb3) - bcb3) + 0) at 15:2-15:2<br align="left"/> 15:2-15:2: @4.Return: return</td></tr><tr><td align="left" balign="left">bb4: Return</td></tr></table>>]; bcb2__Cov_0_3 [shape="none", label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="gray" align="center" colspan="1">bcb2</td></tr><tr><td align="left" balign="left">Expression(bcb1:(bcb0 + bcb3) - bcb3) at 12:13-12:18<br align="left"/> 12:13-12:18: @4[0]: Coverage::Expression(4294967293) = Expression(4294967294) + Zero for $DIR/coverage_graphviz.rs:15:1 - 15:2<br align="left"/>Expression(bcb2:(bcb1:(bcb0 + bcb3) - bcb3) + 0) at 15:2-15:2<br align="left"/> 15:2-15:2: @4.Return: return</td></tr><tr><td align="left" balign="left">bb4: Return</td></tr></table>>];
bcb1__Cov_0_3 [shape="none", label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="gray" align="center" colspan="1">bcb1</td></tr><tr><td align="left" balign="left">Expression(bcb0 + bcb3) at 10:5-11:17<br align="left"/> 11:12-11:17: @2.Call: _2 = bar() -&gt; [return: bb3, unwind: bb6]</td></tr><tr><td align="left" balign="left">bb1: FalseUnwind<br align="left"/>bb2: Call</td></tr><tr><td align="left" balign="left">bb3: SwitchInt</td></tr></table>>]; bcb1__Cov_0_3 [shape="none", label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="gray" align="center" colspan="1">bcb1</td></tr><tr><td align="left" balign="left">Expression(bcb0 + bcb3) at 10:5-11:17<br align="left"/> 11:12-11:17: @2.Call: _2 = bar() -&gt; [return: bb3, unwind: bb6]</td></tr><tr><td align="left" balign="left">bb1: FalseUnwind<br align="left"/>bb2: Call</td></tr><tr><td align="left" balign="left">bb3: SwitchInt</td></tr></table>>];
bcb0__Cov_0_3 [shape="none", label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="gray" align="center" colspan="1">bcb0</td></tr><tr><td align="left" balign="left"></td></tr><tr><td align="left" balign="left">Counter(bcb0) at 9:1-9:11<br align="left"/> </td></tr><tr><td align="left" balign="left">bb0: Goto</td></tr></table>>]; bcb0__Cov_0_3 [shape="none", label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="gray" align="center" colspan="1">bcb0</td></tr><tr><td align="left" balign="left"></td></tr><tr><td align="left" balign="left">Counter(bcb0) at 9:1-9:11<br align="left"/> </td></tr><tr><td align="left" balign="left">bb0: Goto</td></tr></table>>];
bcb3__Cov_0_3 -> bcb1__Cov_0_3 [label=<>]; bcb3__Cov_0_3 -> bcb1__Cov_0_3 [label=<>];

View file

@ -13,7 +13,7 @@
} }
bb1: { bb1: {
+ Coverage::Expression(4294967295) = 1 + 2 for /the/src/instrument_coverage.rs:12:5 - 13:17; + Coverage::Expression(4294967295) = Counter(1) + Counter(2) for /the/src/instrument_coverage.rs:12:5 - 13:17;
falseUnwind -> [real: bb2, unwind: bb6]; falseUnwind -> [real: bb2, unwind: bb6];
} }
@ -27,8 +27,8 @@
} }
bb4: { bb4: {
+ Coverage::Expression(4294967293) = 4294967294 + 0 for /the/src/instrument_coverage.rs:17:1 - 17:2; + Coverage::Expression(4294967293) = Expression(4294967294) + Zero for /the/src/instrument_coverage.rs:17:1 - 17:2;
+ Coverage::Expression(4294967294) = 4294967295 - 2 for /the/src/instrument_coverage.rs:14:13 - 14:18; + Coverage::Expression(4294967294) = Expression(4294967295) - Counter(2) for /the/src/instrument_coverage.rs:14:13 - 14:18;
_0 = const (); _0 = const ();
StorageDead(_2); StorageDead(_2);
return; return;