Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move most coverage code out of rustc_codegen_ssa #113355

Merged
merged 3 commits into from
Jul 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 3 additions & 61 deletions compiler/rustc_codegen_gcc/src/coverageinfo.rs
Original file line number Diff line number Diff line change
@@ -1,69 +1,11 @@
use gccjit::RValue;
use rustc_codegen_ssa::traits::{CoverageInfoBuilderMethods, CoverageInfoMethods};
use rustc_hir::def_id::DefId;
use rustc_middle::mir::coverage::{
CodeRegion,
CounterValueReference,
ExpressionOperandId,
InjectedExpressionId,
Op,
};
use rustc_codegen_ssa::traits::CoverageInfoBuilderMethods;
use rustc_middle::mir::Coverage;
use rustc_middle::ty::Instance;

use crate::builder::Builder;
use crate::context::CodegenCx;

impl<'a, 'gcc, 'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
fn set_function_source_hash(
&mut self,
_instance: Instance<'tcx>,
_function_source_hash: u64,
) -> bool {
unimplemented!();
}

fn add_coverage_counter(&mut self, _instance: Instance<'tcx>, _id: CounterValueReference, _region: CodeRegion) -> bool {
// TODO(antoyo)
false
}

fn add_coverage_counter_expression(&mut self, _instance: Instance<'tcx>, _id: InjectedExpressionId, _lhs: ExpressionOperandId, _op: Op, _rhs: ExpressionOperandId, _region: Option<CodeRegion>) -> bool {
// TODO(antoyo)
false
}

fn add_coverage_unreachable(&mut self, _instance: Instance<'tcx>, _region: CodeRegion) -> bool {
fn add_coverage(&mut self, _instance: Instance<'tcx>, _coverage: &Coverage) {
// TODO(antoyo)
false
}
}

impl<'gcc, 'tcx> CoverageInfoMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
fn coverageinfo_finalize(&self) {
// TODO(antoyo)
}

fn get_pgo_func_name_var(&self, _instance: Instance<'tcx>) -> RValue<'gcc> {
unimplemented!();
}

/// Functions with MIR-based coverage are normally codegenned _only_ if
/// called. LLVM coverage tools typically expect every function to be
/// defined (even if unused), with at least one call to LLVM intrinsic
/// `instrprof.increment`.
///
/// Codegen a small function that will never be called, with one counter
/// that will never be incremented.
///
/// For used/called functions, the coverageinfo was already added to the
/// `function_coverage_map` (keyed by function `Instance`) during codegen.
/// But in this case, since the unused function was _not_ previously
/// codegenned, collect the coverage `CodeRegion`s from the MIR and add
/// them. The first `CodeRegion` is used to add a single counter, with the
/// same counter ID used in the injected `instrprof.increment` intrinsic
/// call. Since the function is never called, all other `CodeRegion`s can be
/// added as `unreachable_region`s.
fn define_unused_fn(&self, _def_id: DefId) {
unimplemented!();
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
pub use super::ffi::*;

use rustc_index::{IndexSlice, IndexVec};
use rustc_middle::bug;
use rustc_middle::mir::coverage::{
CodeRegion, CounterValueReference, ExpressionOperandId, InjectedExpressionId,
InjectedExpressionIndex, MappedExpressionIndex, Op,
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use crate::common::CodegenCx;
use crate::coverageinfo;
use crate::coverageinfo::map_data::{Counter, CounterExpression};
use crate::llvm;

use llvm::coverageinfo::CounterMappingRegion;
use rustc_codegen_ssa::coverageinfo::map::{Counter, CounterExpression};
use rustc_codegen_ssa::traits::{ConstMethods, CoverageInfoMethods};
use rustc_codegen_ssa::traits::ConstMethods;
use rustc_data_structures::fx::FxIndexSet;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::DefId;
Expand Down
77 changes: 70 additions & 7 deletions compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,33 @@ use crate::llvm;
use crate::abi::Abi;
use crate::builder::Builder;
use crate::common::CodegenCx;
use crate::coverageinfo::map_data::{CounterExpression, FunctionCoverage};

use libc::c_uint;
use llvm::coverageinfo::CounterMappingRegion;
use rustc_codegen_ssa::coverageinfo::map::{CounterExpression, FunctionCoverage};
use rustc_codegen_ssa::traits::{
BaseTypeMethods, BuilderMethods, ConstMethods, CoverageInfoBuilderMethods, CoverageInfoMethods,
MiscMethods, StaticMethods,
BaseTypeMethods, BuilderMethods, ConstMethods, CoverageInfoBuilderMethods, MiscMethods,
StaticMethods,
};
use rustc_data_structures::fx::FxHashMap;
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_llvm::RustString;
use rustc_middle::bug;
use rustc_middle::mir::coverage::{
CodeRegion, CounterValueReference, ExpressionOperandId, InjectedExpressionId, Op,
CodeRegion, CounterValueReference, CoverageKind, ExpressionOperandId, InjectedExpressionId, Op,
};
use rustc_middle::mir::Coverage;
use rustc_middle::ty;
use rustc_middle::ty::layout::FnAbiOf;
use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt};
use rustc_middle::ty::subst::InternalSubsts;
use rustc_middle::ty::Instance;

use std::cell::RefCell;
use std::ffi::CString;

mod ffi;
pub(crate) mod map_data;
pub mod mapgen;

const UNUSED_FUNCTION_COUNTER_ID: CounterValueReference = CounterValueReference::START;
Expand All @@ -53,11 +56,17 @@ impl<'ll, 'tcx> CrateCoverageContext<'ll, 'tcx> {
}
}

impl<'ll, 'tcx> CoverageInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
fn coverageinfo_finalize(&self) {
// These methods used to be part of trait `CoverageInfoMethods`, which no longer
// exists after most coverage code was moved out of SSA.
impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
pub(crate) fn coverageinfo_finalize(&self) {
mapgen::finalize(self)
}

/// For LLVM codegen, returns a function-specific `Value` for a global
/// string, to hold the function name passed to LLVM intrinsic
/// `instrprof.increment()`. The `Value` is only created once per instance.
/// Multiple invocations with the same instance return the same `Value`.
fn get_pgo_func_name_var(&self, instance: Instance<'tcx>) -> &'ll llvm::Value {
if let Some(coverage_context) = self.coverage_context() {
debug!("getting pgo_func_name_var for instance={:?}", instance);
Expand Down Expand Up @@ -94,6 +103,54 @@ impl<'ll, 'tcx> CoverageInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
}

impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
fn add_coverage(&mut self, instance: Instance<'tcx>, coverage: &Coverage) {
let bx = self;

let Coverage { kind, code_region } = coverage.clone();
match kind {
CoverageKind::Counter { function_source_hash, id } => {
if bx.set_function_source_hash(instance, function_source_hash) {
// If `set_function_source_hash()` returned true, the coverage map is enabled,
// so continue adding the counter.
if let Some(code_region) = code_region {
// Note: Some counters do not have code regions, but may still be referenced
// from expressions. In that case, don't add the counter to the coverage map,
// but do inject the counter intrinsic.
bx.add_coverage_counter(instance, id, code_region);
}

let coverageinfo = bx.tcx().coverageinfo(instance.def);

let fn_name = bx.get_pgo_func_name_var(instance);
let hash = bx.const_u64(function_source_hash);
let num_counters = bx.const_u32(coverageinfo.num_counters);
let index = bx.const_u32(id.zero_based_index());
debug!(
"codegen intrinsic instrprof.increment(fn_name={:?}, hash={:?}, num_counters={:?}, index={:?})",
fn_name, hash, num_counters, index,
);
bx.instrprof_increment(fn_name, hash, num_counters, index);
}
}
CoverageKind::Expression { id, lhs, op, rhs } => {
bx.add_coverage_counter_expression(instance, id, lhs, op, rhs, code_region);
}
CoverageKind::Unreachable => {
bx.add_coverage_unreachable(
instance,
code_region.expect("unreachable regions always have code regions"),
);
}
}
}
}

// These methods used to be part of trait `CoverageInfoBuilderMethods`, but
// after moving most coverage code out of SSA they are now just ordinary methods.
impl<'tcx> Builder<'_, '_, 'tcx> {
/// Returns true if the function source hash was added to the coverage map (even if it had
/// already been added, for this instance). Returns false *only* if `-C instrument-coverage` is
/// not enabled (a coverage map is not being generated).
fn set_function_source_hash(
&mut self,
instance: Instance<'tcx>,
Expand All @@ -115,6 +172,8 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
}
}

/// Returns true if the counter was added to the coverage map; false if `-C instrument-coverage`
/// is not enabled (a coverage map is not being generated).
fn add_coverage_counter(
&mut self,
instance: Instance<'tcx>,
Expand All @@ -137,6 +196,8 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
}
}

/// Returns true if the expression was added to the coverage map; false if
/// `-C instrument-coverage` is not enabled (a coverage map is not being generated).
fn add_coverage_counter_expression(
&mut self,
instance: Instance<'tcx>,
Expand All @@ -163,6 +224,8 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
}
}

/// Returns true if the region was added to the coverage map; false if `-C instrument-coverage`
/// is not enabled (a coverage map is not being generated).
fn add_coverage_unreachable(&mut self, instance: Instance<'tcx>, region: CodeRegion) -> bool {
if let Some(coverage_context) = self.coverage_context() {
debug!(
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_llvm/src/llvm/ffi.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#![allow(non_camel_case_types)]
#![allow(non_upper_case_globals)]

use rustc_codegen_ssa::coverageinfo::map as coverage_map;
use crate::coverageinfo::map_data as coverage_map;

use super::debuginfo::{
DIArray, DIBasicType, DIBuilder, DICompositeType, DIDerivedType, DIDescriptor, DIEnumerator,
Expand Down
2 changes: 0 additions & 2 deletions compiler/rustc_codegen_ssa/src/coverageinfo/mod.rs

This file was deleted.

1 change: 0 additions & 1 deletion compiler/rustc_codegen_ssa/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ pub mod back;
pub mod base;
pub mod codegen_attrs;
pub mod common;
pub mod coverageinfo;
pub mod debuginfo;
pub mod errors;
pub mod glue;
Expand Down
41 changes: 3 additions & 38 deletions compiler/rustc_codegen_ssa/src/mir/coverageinfo.rs
Original file line number Diff line number Diff line change
@@ -1,55 +1,20 @@
use crate::traits::*;

use rustc_middle::mir::coverage::*;
use rustc_middle::mir::Coverage;
use rustc_middle::mir::SourceScope;

use super::FunctionCx;

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, coverage: &Coverage, scope: SourceScope) {
// Determine the instance that coverage data was originally generated for.
let instance = if let Some(inlined) = scope.inlined_instance(&self.mir.source_scopes) {
self.monomorphize(inlined)
} else {
self.instance
};

let Coverage { kind, code_region } = coverage;
match kind {
CoverageKind::Counter { function_source_hash, id } => {
if bx.set_function_source_hash(instance, function_source_hash) {
// If `set_function_source_hash()` returned true, the coverage map is enabled,
// so continue adding the counter.
if let Some(code_region) = code_region {
// Note: Some counters do not have code regions, but may still be referenced
// from expressions. In that case, don't add the counter to the coverage map,
// but do inject the counter intrinsic.
bx.add_coverage_counter(instance, id, code_region);
}

let coverageinfo = bx.tcx().coverageinfo(instance.def);

let fn_name = bx.get_pgo_func_name_var(instance);
let hash = bx.const_u64(function_source_hash);
let num_counters = bx.const_u32(coverageinfo.num_counters);
let index = bx.const_u32(id.zero_based_index());
debug!(
"codegen intrinsic instrprof.increment(fn_name={:?}, hash={:?}, num_counters={:?}, index={:?})",
fn_name, hash, num_counters, index,
);
bx.instrprof_increment(fn_name, hash, num_counters, index);
}
}
CoverageKind::Expression { id, lhs, op, rhs } => {
bx.add_coverage_counter_expression(instance, id, lhs, op, rhs, code_region);
}
CoverageKind::Unreachable => {
bx.add_coverage_unreachable(
instance,
code_region.expect("unreachable regions always have code regions"),
);
}
}
// Handle the coverage info in a backend-specific way.
bx.add_coverage(instance, coverage);
}
}
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_ssa/src/mir/statement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
}
}
mir::StatementKind::Coverage(box ref coverage) => {
self.codegen_coverage(bx, coverage.clone(), statement.source_info.scope);
self.codegen_coverage(bx, coverage, statement.source_info.scope);
}
mir::StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(ref op)) => {
let op_val = self.codegen_operand(bx, op);
Expand Down
58 changes: 6 additions & 52 deletions compiler/rustc_codegen_ssa/src/traits/coverageinfo.rs
Original file line number Diff line number Diff line change
@@ -1,57 +1,11 @@
use super::BackendTypes;
use rustc_hir::def_id::DefId;
use rustc_middle::mir::coverage::*;
use rustc_middle::mir::Coverage;
use rustc_middle::ty::Instance;

pub trait CoverageInfoMethods<'tcx>: BackendTypes {
fn coverageinfo_finalize(&self);

/// Codegen a small function that will never be called, with one counter
/// that will never be incremented, that gives LLVM coverage tools a
/// function definition it needs in order to resolve coverage map references
/// to unused functions. This is necessary so unused functions will appear
/// as uncovered (coverage execution count `0`) in LLVM coverage reports.
fn define_unused_fn(&self, def_id: DefId);

/// For LLVM codegen, returns a function-specific `Value` for a global
/// string, to hold the function name passed to LLVM intrinsic
/// `instrprof.increment()`. The `Value` is only created once per instance.
/// Multiple invocations with the same instance return the same `Value`.
fn get_pgo_func_name_var(&self, instance: Instance<'tcx>) -> Self::Value;
}

pub trait CoverageInfoBuilderMethods<'tcx>: BackendTypes {
/// Returns true if the function source hash was added to the coverage map (even if it had
/// already been added, for this instance). Returns false *only* if `-C instrument-coverage` is
/// not enabled (a coverage map is not being generated).
fn set_function_source_hash(
&mut self,
instance: Instance<'tcx>,
function_source_hash: u64,
) -> bool;

/// Returns true if the counter was added to the coverage map; false if `-C instrument-coverage`
/// is not enabled (a coverage map is not being generated).
fn add_coverage_counter(
&mut self,
instance: Instance<'tcx>,
index: CounterValueReference,
region: CodeRegion,
) -> bool;

/// Returns true if the expression was added to the coverage map; false if
/// `-C instrument-coverage` is not enabled (a coverage map is not being generated).
fn add_coverage_counter_expression(
&mut self,
instance: Instance<'tcx>,
id: InjectedExpressionId,
lhs: ExpressionOperandId,
op: Op,
rhs: ExpressionOperandId,
region: Option<CodeRegion>,
) -> bool;

/// Returns true if the region was added to the coverage map; false if `-C instrument-coverage`
/// is not enabled (a coverage map is not being generated).
fn add_coverage_unreachable(&mut self, instance: Instance<'tcx>, region: CodeRegion) -> bool;
/// Handle the MIR coverage info in a backend-specific way.
///
/// This can potentially be a no-op in backends that don't support
/// coverage instrumentation.
fn add_coverage(&mut self, instance: Instance<'tcx>, coverage: &Coverage);
}
Loading