-
Notifications
You must be signed in to change notification settings - Fork 12.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Rollup merge of #113355 - Zalathar:ssa, r=oli-obk
Move most coverage code out of `rustc_codegen_ssa` *This is one step in my larger coverage refactoring ambitions described at <https://github.com/rust-lang/compiler-team/issues/645>.* The backend implementation of coverage instrumentation was originally split between SSA and LLVM, perhaps in the hopes that it could be used by other backends. In practice, this split mostly just makes the coverage implementation harder to navigate and harder to modify. It seems unlikely that any backend will actually implement coverage instrumentation in the foreseeable future, especially since many parts of the existing implementation (outside the LLVM backend) are heavily tied to the specific details of LLVM's coverage instrumentation features. The current shared implementation of `codegen_coverage` is heavily tied to the details of `StatementKind::Coverage`, which makes those details difficult to change. I have reason to want to change those details as part of future fixes/improvements, so this will reduce the amount of interface churn caused by those later changes. --- This is intended to be a pure refactoring change, with no changes to actual behaviour. All of the “added” code has really just been moved from other files.
- Loading branch information
Showing
12 changed files
with
88 additions
and
168 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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!(); | ||
} | ||
} |
File renamed without changes.
1 change: 1 addition & 0 deletions
1
...rustc_codegen_ssa/src/coverageinfo/map.rs → ...codegen_llvm/src/coverageinfo/map_data.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} |
Oops, something went wrong.