Unbox and unwrap the contents of StatementKind::Coverage

The payload of coverage statements was historically a structure with several
fields, so it was boxed to avoid bloating `StatementKind`.

Now that the payload is a single relatively-small enum, we can replace
`Box<Coverage>` with just `CoverageKind`.

This patch also adds a size assertion for `StatementKind`, to avoid
accidentally bloating it in the future.
This commit is contained in:
Zalathar 2024-03-23 19:13:52 +11:00
parent c3b05c6e5b
commit ab92699f4a
15 changed files with 44 additions and 68 deletions

View File

@ -1,11 +1,11 @@
use rustc_codegen_ssa::traits::CoverageInfoBuilderMethods; use rustc_codegen_ssa::traits::CoverageInfoBuilderMethods;
use rustc_middle::mir::Coverage; use rustc_middle::mir::coverage::CoverageKind;
use rustc_middle::ty::Instance; use rustc_middle::ty::Instance;
use crate::builder::Builder; use crate::builder::Builder;
impl<'a, 'gcc, 'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { impl<'a, 'gcc, 'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
fn add_coverage(&mut self, _instance: Instance<'tcx>, _coverage: &Coverage) { fn add_coverage(&mut self, _instance: Instance<'tcx>, _kind: &CoverageKind) {
// TODO(antoyo) // TODO(antoyo)
} }
} }

View File

@ -14,7 +14,6 @@ use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
use rustc_llvm::RustString; use rustc_llvm::RustString;
use rustc_middle::bug; use rustc_middle::bug;
use rustc_middle::mir::coverage::CoverageKind; use rustc_middle::mir::coverage::CoverageKind;
use rustc_middle::mir::Coverage;
use rustc_middle::ty::layout::HasTyCtxt; use rustc_middle::ty::layout::HasTyCtxt;
use rustc_middle::ty::Instance; use rustc_middle::ty::Instance;
@ -75,7 +74,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> { impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
#[instrument(level = "debug", skip(self))] #[instrument(level = "debug", skip(self))]
fn add_coverage(&mut self, instance: Instance<'tcx>, coverage: &Coverage) { fn add_coverage(&mut self, instance: Instance<'tcx>, kind: &CoverageKind) {
// Our caller should have already taken care of inlining subtleties, // Our caller should have already taken care of inlining subtleties,
// so we can assume that counter/expression IDs in this coverage // so we can assume that counter/expression IDs in this coverage
// statement are meaningful for the given instance. // statement are meaningful for the given instance.
@ -98,7 +97,6 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
.entry(instance) .entry(instance)
.or_insert_with(|| FunctionCoverageCollector::new(instance, function_coverage_info)); .or_insert_with(|| FunctionCoverageCollector::new(instance, function_coverage_info));
let Coverage { kind } = coverage;
match *kind { match *kind {
CoverageKind::SpanMarker | CoverageKind::BlockMarker { .. } => unreachable!( CoverageKind::SpanMarker | CoverageKind::BlockMarker { .. } => unreachable!(
"marker statement {kind:?} should have been removed by CleanupPostBorrowck" "marker statement {kind:?} should have been removed by CleanupPostBorrowck"

View File

@ -1,12 +1,12 @@
use crate::traits::*; use crate::traits::*;
use rustc_middle::mir::Coverage; use rustc_middle::mir::coverage::CoverageKind;
use rustc_middle::mir::SourceScope; use rustc_middle::mir::SourceScope;
use super::FunctionCx; use super::FunctionCx;
impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
pub fn codegen_coverage(&self, bx: &mut Bx, coverage: &Coverage, scope: SourceScope) { pub fn codegen_coverage(&self, bx: &mut Bx, kind: &CoverageKind, scope: SourceScope) {
// Determine the instance that coverage data was originally generated for. // Determine the instance that coverage data was originally generated for.
let instance = if let Some(inlined) = scope.inlined_instance(&self.mir.source_scopes) { let instance = if let Some(inlined) = scope.inlined_instance(&self.mir.source_scopes) {
self.monomorphize(inlined) self.monomorphize(inlined)
@ -15,6 +15,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
}; };
// Handle the coverage info in a backend-specific way. // Handle the coverage info in a backend-specific way.
bx.add_coverage(instance, coverage); bx.add_coverage(instance, kind);
} }
} }

View File

@ -64,8 +64,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
cg_indirect_place.storage_dead(bx); cg_indirect_place.storage_dead(bx);
} }
} }
mir::StatementKind::Coverage(box ref coverage) => { mir::StatementKind::Coverage(ref kind) => {
self.codegen_coverage(bx, coverage, statement.source_info.scope); self.codegen_coverage(bx, kind, statement.source_info.scope);
} }
mir::StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(ref op)) => { mir::StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(ref op)) => {
if !matches!(bx.tcx().sess.opts.optimize, OptLevel::No | OptLevel::Less) { if !matches!(bx.tcx().sess.opts.optimize, OptLevel::No | OptLevel::Less) {

View File

@ -1,5 +1,5 @@
use super::BackendTypes; use super::BackendTypes;
use rustc_middle::mir::Coverage; use rustc_middle::mir::coverage::CoverageKind;
use rustc_middle::ty::Instance; use rustc_middle::ty::Instance;
pub trait CoverageInfoBuilderMethods<'tcx>: BackendTypes { pub trait CoverageInfoBuilderMethods<'tcx>: BackendTypes {
@ -7,5 +7,5 @@ pub trait CoverageInfoBuilderMethods<'tcx>: BackendTypes {
/// ///
/// This can potentially be a no-op in backends that don't support /// This can potentially be a no-op in backends that don't support
/// coverage instrumentation. /// coverage instrumentation.
fn add_coverage(&mut self, instance: Instance<'tcx>, coverage: &Coverage); fn add_coverage(&mut self, instance: Instance<'tcx>, kind: &CoverageKind);
} }

View File

@ -346,8 +346,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> {
self.fail(location, format!("explicit `{kind:?}` is forbidden")); self.fail(location, format!("explicit `{kind:?}` is forbidden"));
} }
} }
StatementKind::Coverage(coverage) => { StatementKind::Coverage(kind) => {
let kind = &coverage.kind;
if self.mir_phase >= MirPhase::Analysis(AnalysisPhase::PostCleanup) if self.mir_phase >= MirPhase::Analysis(AnalysisPhase::PostCleanup)
&& let CoverageKind::BlockMarker { .. } | CoverageKind::SpanMarker { .. } = kind && let CoverageKind::BlockMarker { .. } | CoverageKind::SpanMarker { .. } = kind
{ {

View File

@ -13,7 +13,7 @@ use rustc_middle::mir::interpret::{
Provenance, Provenance,
}; };
use rustc_middle::mir::visit::Visitor; use rustc_middle::mir::visit::Visitor;
use rustc_middle::mir::{self, *}; use rustc_middle::mir::*;
use rustc_target::abi::Size; use rustc_target::abi::Size;
const INDENT: &str = " "; const INDENT: &str = " ";
@ -711,7 +711,7 @@ impl Debug for Statement<'_> {
AscribeUserType(box (ref place, ref c_ty), ref variance) => { AscribeUserType(box (ref place, ref c_ty), ref variance) => {
write!(fmt, "AscribeUserType({place:?}, {variance:?}, {c_ty:?})") write!(fmt, "AscribeUserType({place:?}, {variance:?}, {c_ty:?})")
} }
Coverage(box mir::Coverage { ref kind }) => write!(fmt, "Coverage::{kind:?}"), Coverage(ref kind) => write!(fmt, "Coverage::{kind:?}"),
Intrinsic(box ref intrinsic) => write!(fmt, "{intrinsic}"), Intrinsic(box ref intrinsic) => write!(fmt, "{intrinsic}"),
ConstEvalCounter => write!(fmt, "ConstEvalCounter"), ConstEvalCounter => write!(fmt, "ConstEvalCounter"),
Nop => write!(fmt, "nop"), Nop => write!(fmt, "nop"),

View File

@ -373,7 +373,7 @@ pub enum StatementKind<'tcx> {
/// ///
/// Interpreters and codegen backends that don't support coverage instrumentation /// Interpreters and codegen backends that don't support coverage instrumentation
/// can usually treat this as a no-op. /// can usually treat this as a no-op.
Coverage(Box<Coverage>), Coverage(CoverageKind),
/// Denotes a call to an intrinsic that does not require an unwind path and always returns. /// Denotes a call to an intrinsic that does not require an unwind path and always returns.
/// This avoids adding a new block and a terminator for simple intrinsics. /// This avoids adding a new block and a terminator for simple intrinsics.
@ -517,12 +517,6 @@ pub enum FakeReadCause {
ForIndex, ForIndex,
} }
#[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)]
#[derive(TypeFoldable, TypeVisitable)]
pub struct Coverage {
pub kind: CoverageKind,
}
#[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)] #[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)]
#[derive(TypeFoldable, TypeVisitable)] #[derive(TypeFoldable, TypeVisitable)]
pub struct CopyNonOverlapping<'tcx> { pub struct CopyNonOverlapping<'tcx> {
@ -1465,5 +1459,6 @@ mod size_asserts {
static_assert_size!(Place<'_>, 16); static_assert_size!(Place<'_>, 16);
static_assert_size!(PlaceElem<'_>, 24); static_assert_size!(PlaceElem<'_>, 24);
static_assert_size!(Rvalue<'_>, 40); static_assert_size!(Rvalue<'_>, 40);
static_assert_size!(StatementKind<'_>, 16);
// tidy-alphabetical-end // tidy-alphabetical-end
} }

View File

@ -156,10 +156,10 @@ macro_rules! make_mir_visitor {
fn visit_coverage( fn visit_coverage(
&mut self, &mut self,
coverage: & $($mutability)? Coverage, kind: & $($mutability)? coverage::CoverageKind,
location: Location, location: Location,
) { ) {
self.super_coverage(coverage, location); self.super_coverage(kind, location);
} }
fn visit_retag( fn visit_retag(
@ -803,7 +803,7 @@ macro_rules! make_mir_visitor {
} }
fn super_coverage(&mut self, fn super_coverage(&mut self,
_coverage: & $($mutability)? Coverage, _kind: & $($mutability)? coverage::CoverageKind,
_location: Location) { _location: Location) {
} }

View File

@ -107,9 +107,7 @@ impl<'tcx> CFG<'tcx> {
/// This results in more accurate coverage reports for certain kinds of /// This results in more accurate coverage reports for certain kinds of
/// syntax (e.g. `continue` or `if !`) that would otherwise not appear in MIR. /// syntax (e.g. `continue` or `if !`) that would otherwise not appear in MIR.
pub(crate) fn push_coverage_span_marker(&mut self, block: BasicBlock, source_info: SourceInfo) { pub(crate) fn push_coverage_span_marker(&mut self, block: BasicBlock, source_info: SourceInfo) {
let kind = StatementKind::Coverage(Box::new(Coverage { let kind = StatementKind::Coverage(coverage::CoverageKind::SpanMarker);
kind: coverage::CoverageKind::SpanMarker,
}));
let stmt = Statement { source_info, kind }; let stmt = Statement { source_info, kind };
self.push(block, stmt); self.push(block, stmt);
} }

View File

@ -127,9 +127,7 @@ impl Builder<'_, '_> {
let marker_statement = mir::Statement { let marker_statement = mir::Statement {
source_info, source_info,
kind: mir::StatementKind::Coverage(Box::new(mir::Coverage { kind: mir::StatementKind::Coverage(CoverageKind::BlockMarker { id }),
kind: CoverageKind::BlockMarker { id },
})),
}; };
self.cfg.push(block, marker_statement); self.cfg.push(block, marker_statement);

View File

@ -18,7 +18,7 @@
use crate::MirPass; use crate::MirPass;
use rustc_middle::mir::coverage::CoverageKind; use rustc_middle::mir::coverage::CoverageKind;
use rustc_middle::mir::{Body, BorrowKind, Coverage, Rvalue, StatementKind, TerminatorKind}; use rustc_middle::mir::{Body, BorrowKind, Rvalue, StatementKind, TerminatorKind};
use rustc_middle::ty::TyCtxt; use rustc_middle::ty::TyCtxt;
pub struct CleanupPostBorrowck; pub struct CleanupPostBorrowck;
@ -30,12 +30,11 @@ impl<'tcx> MirPass<'tcx> for CleanupPostBorrowck {
match statement.kind { match statement.kind {
StatementKind::AscribeUserType(..) StatementKind::AscribeUserType(..)
| StatementKind::Assign(box (_, Rvalue::Ref(_, BorrowKind::Fake, _))) | StatementKind::Assign(box (_, Rvalue::Ref(_, BorrowKind::Fake, _)))
| StatementKind::Coverage(box Coverage { | StatementKind::Coverage(
// These kinds of coverage statements are markers inserted during // These kinds of coverage statements are markers inserted during
// MIR building, and are not needed after InstrumentCoverage. // MIR building, and are not needed after InstrumentCoverage.
kind: CoverageKind::BlockMarker { .. } | CoverageKind::SpanMarker { .. }, CoverageKind::BlockMarker { .. } | CoverageKind::SpanMarker { .. },
.. )
})
| StatementKind::FakeRead(..) => statement.make_nop(), | StatementKind::FakeRead(..) => statement.make_nop(),
_ => (), _ => (),
} }

View File

@ -15,7 +15,7 @@ use crate::MirPass;
use rustc_middle::mir::coverage::*; use rustc_middle::mir::coverage::*;
use rustc_middle::mir::{ use rustc_middle::mir::{
self, BasicBlock, BasicBlockData, Coverage, SourceInfo, Statement, StatementKind, Terminator, self, BasicBlock, BasicBlockData, SourceInfo, Statement, StatementKind, Terminator,
TerminatorKind, TerminatorKind,
}; };
use rustc_middle::ty::TyCtxt; use rustc_middle::ty::TyCtxt;
@ -230,10 +230,7 @@ fn inject_statement(mir_body: &mut mir::Body<'_>, counter_kind: CoverageKind, bb
debug!(" injecting statement {counter_kind:?} for {bb:?}"); debug!(" injecting statement {counter_kind:?} for {bb:?}");
let data = &mut mir_body[bb]; let data = &mut mir_body[bb];
let source_info = data.terminator().source_info; let source_info = data.terminator().source_info;
let statement = Statement { let statement = Statement { source_info, kind: StatementKind::Coverage(counter_kind) };
source_info,
kind: StatementKind::Coverage(Box::new(Coverage { kind: counter_kind })),
};
data.statements.insert(0, statement); data.statements.insert(0, statement);
} }

View File

@ -1,7 +1,7 @@
use rustc_data_structures::captures::Captures; use rustc_data_structures::captures::Captures;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc_middle::mir::coverage::{CounterId, CoverageKind}; use rustc_middle::mir::coverage::{CounterId, CoverageKind};
use rustc_middle::mir::{Body, Coverage, CoverageIdsInfo, Statement, StatementKind}; use rustc_middle::mir::{Body, CoverageIdsInfo, Statement, StatementKind};
use rustc_middle::query::TyCtxtAt; use rustc_middle::query::TyCtxtAt;
use rustc_middle::ty::{self, TyCtxt}; use rustc_middle::ty::{self, TyCtxt};
use rustc_middle::util::Providers; use rustc_middle::util::Providers;
@ -54,7 +54,7 @@ fn coverage_ids_info<'tcx>(
let mir_body = tcx.instance_mir(instance_def); let mir_body = tcx.instance_mir(instance_def);
let max_counter_id = all_coverage_in_mir_body(mir_body) let max_counter_id = all_coverage_in_mir_body(mir_body)
.filter_map(|coverage| match coverage.kind { .filter_map(|kind| match *kind {
CoverageKind::CounterIncrement { id } => Some(id), CoverageKind::CounterIncrement { id } => Some(id),
_ => None, _ => None,
}) })
@ -66,12 +66,10 @@ fn coverage_ids_info<'tcx>(
fn all_coverage_in_mir_body<'a, 'tcx>( fn all_coverage_in_mir_body<'a, 'tcx>(
body: &'a Body<'tcx>, body: &'a Body<'tcx>,
) -> impl Iterator<Item = &'a Coverage> + Captures<'tcx> { ) -> impl Iterator<Item = &'a CoverageKind> + Captures<'tcx> {
body.basic_blocks.iter().flat_map(|bb_data| &bb_data.statements).filter_map(|statement| { body.basic_blocks.iter().flat_map(|bb_data| &bb_data.statements).filter_map(|statement| {
match statement.kind { match statement.kind {
StatementKind::Coverage(box ref coverage) if !is_inlined(body, statement) => { StatementKind::Coverage(ref kind) if !is_inlined(body, statement) => Some(kind),
Some(coverage)
}
_ => None, _ => None,
} }
}) })

View File

@ -187,9 +187,7 @@ fn filtered_statement_span(statement: &Statement<'_>) -> Option<Span> {
// for their parent `BasicBlock`. // for their parent `BasicBlock`.
StatementKind::StorageLive(_) StatementKind::StorageLive(_)
| StatementKind::StorageDead(_) | StatementKind::StorageDead(_)
// Ignore `ConstEvalCounter`s
| StatementKind::ConstEvalCounter | StatementKind::ConstEvalCounter
// Ignore `Nop`s
| StatementKind::Nop => None, | StatementKind::Nop => None,
// FIXME(#78546): MIR InstrumentCoverage - Can the source_info.span for `FakeRead` // FIXME(#78546): MIR InstrumentCoverage - Can the source_info.span for `FakeRead`
@ -211,30 +209,28 @@ fn filtered_statement_span(statement: &Statement<'_>) -> Option<Span> {
StatementKind::FakeRead(box (FakeReadCause::ForGuardBinding, _)) => None, StatementKind::FakeRead(box (FakeReadCause::ForGuardBinding, _)) => None,
// Retain spans from most other statements. // Retain spans from most other statements.
StatementKind::FakeRead(box (_, _)) // Not including `ForGuardBinding` StatementKind::FakeRead(_)
| StatementKind::Intrinsic(..) | StatementKind::Intrinsic(..)
| StatementKind::Coverage(box mir::Coverage { | StatementKind::Coverage(
// The purpose of `SpanMarker` is to be matched and accepted here. // The purpose of `SpanMarker` is to be matched and accepted here.
kind: CoverageKind::SpanMarker CoverageKind::SpanMarker,
}) )
| StatementKind::Assign(_) | StatementKind::Assign(_)
| StatementKind::SetDiscriminant { .. } | StatementKind::SetDiscriminant { .. }
| StatementKind::Deinit(..) | StatementKind::Deinit(..)
| StatementKind::Retag(_, _) | StatementKind::Retag(_, _)
| StatementKind::PlaceMention(..) | StatementKind::PlaceMention(..)
| StatementKind::AscribeUserType(_, _) => { | StatementKind::AscribeUserType(_, _) => Some(statement.source_info.span),
Some(statement.source_info.span)
}
StatementKind::Coverage(box mir::Coverage { // Block markers are used for branch coverage, so ignore them here.
// Block markers are used for branch coverage, so ignore them here. StatementKind::Coverage(CoverageKind::BlockMarker { .. }) => None,
kind: CoverageKind::BlockMarker {..}
}) => None,
StatementKind::Coverage(box mir::Coverage { // These coverage statements should not exist prior to coverage instrumentation.
// These coverage statements should not exist prior to coverage instrumentation. StatementKind::Coverage(
kind: CoverageKind::CounterIncrement { .. } | CoverageKind::ExpressionUsed { .. } CoverageKind::CounterIncrement { .. } | CoverageKind::ExpressionUsed { .. },
}) => bug!("Unexpected coverage statement found during coverage instrumentation: {statement:?}"), ) => bug!(
"Unexpected coverage statement found during coverage instrumentation: {statement:?}"
),
} }
} }
@ -382,9 +378,7 @@ pub(super) fn extract_branch_mappings(
// Fill out the mapping from block marker IDs to their enclosing blocks. // Fill out the mapping from block marker IDs to their enclosing blocks.
for (bb, data) in mir_body.basic_blocks.iter_enumerated() { for (bb, data) in mir_body.basic_blocks.iter_enumerated() {
for statement in &data.statements { for statement in &data.statements {
if let StatementKind::Coverage(coverage) = &statement.kind if let StatementKind::Coverage(CoverageKind::BlockMarker { id }) = statement.kind {
&& let CoverageKind::BlockMarker { id } = coverage.kind
{
block_markers[id] = Some(bb); block_markers[id] = Some(bb);
} }
} }