Make source-based code coverage compatible with MIR inlining

When codegenning code coverage use the instance that coverage data was
originally generated for, to ensure basic level of compatibility with
MIR inlining.
This commit is contained in:
Tomasz Miąsko 2021-03-13 00:00:00 +00:00
parent 107896c32d
commit 1796cc0e6c
7 changed files with 68 additions and 51 deletions

View file

@ -8,7 +8,7 @@ use rustc_middle::mir::coverage::{
use rustc_middle::ty::Instance;
use rustc_middle::ty::TyCtxt;
#[derive(Clone, Debug)]
#[derive(Clone, Debug, PartialEq)]
pub struct Expression {
lhs: ExpressionOperandId,
op: Op,
@ -64,7 +64,9 @@ impl<'tcx> FunctionCoverage<'tcx> {
/// Adds a code region to be counted by an injected counter intrinsic.
pub fn add_counter(&mut self, id: CounterValueReference, region: CodeRegion) {
self.counters[id].replace(region).expect_none("add_counter called with duplicate `id`");
if let Some(previous_region) = self.counters[id].replace(region.clone()) {
assert_eq!(previous_region, region, "add_counter: code region for id changed");
}
}
/// Both counters and "counter expressions" (or simply, "expressions") can be operands in other
@ -94,9 +96,18 @@ impl<'tcx> FunctionCoverage<'tcx> {
expression_id, lhs, op, rhs, region
);
let expression_index = self.expression_index(u32::from(expression_id));
self.expressions[expression_index]
.replace(Expression { lhs, op, rhs, region })
.expect_none("add_counter_expression called with duplicate `id_descending_from_max`");
if let Some(previous_expression) = self.expressions[expression_index].replace(Expression {
lhs,
op,
rhs,
region: region.clone(),
}) {
assert_eq!(
previous_expression,
Expression { lhs, op, rhs, region },
"add_counter_expression: expression for id changed"
);
}
}
/// Add a region that will be marked as "unreachable", with a constant "zero counter".

View file

@ -2,27 +2,38 @@ 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) {
pub fn codegen_coverage(&self, bx: &mut Bx, coverage: Coverage, scope: SourceScope) {
// Determine the instance that coverage data was originally generated for.
let scope_data = &self.mir.source_scopes[scope];
let instance = if let Some((inlined_instance, _)) = scope_data.inlined {
self.monomorphize(inlined_instance)
} else if let Some(inlined_scope) = scope_data.inlined_parent_scope {
self.monomorphize(self.mir.source_scopes[inlined_scope].inlined.unwrap().0)
} else {
self.instance
};
let Coverage { kind, code_region } = coverage;
match kind {
CoverageKind::Counter { function_source_hash, id } => {
if bx.set_function_source_hash(self.instance, function_source_hash) {
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(self.instance, id, code_region);
bx.add_coverage_counter(instance, id, code_region);
}
let coverageinfo = bx.tcx().coverageinfo(self.instance.def_id());
let coverageinfo = bx.tcx().coverageinfo(instance.def_id());
let fn_name = bx.create_pgo_func_name_var(self.instance);
let fn_name = bx.create_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(u32::from(id));
@ -34,11 +45,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
}
}
CoverageKind::Expression { id, lhs, op, rhs } => {
bx.add_coverage_counter_expression(self.instance, id, lhs, op, rhs, code_region);
bx.add_coverage_counter_expression(instance, id, lhs, op, rhs, code_region);
}
CoverageKind::Unreachable => {
bx.add_coverage_unreachable(
self.instance,
instance,
code_region.expect("unreachable regions always have code regions"),
);
}

View file

@ -112,7 +112,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
bx
}
mir::StatementKind::Coverage(box ref coverage) => {
self.codegen_coverage(&mut bx, coverage.clone());
self.codegen_coverage(&mut bx, coverage.clone(), statement.source_info.scope);
bx
}
mir::StatementKind::CopyNonOverlapping(box mir::CopyNonOverlapping {