Make codegen coverage_context optional, and check

Addresses Issue #78286

Libraries compiled with coverage and linked with out enabling coverage
would fail when attempting to add the library's coverage statements to
the codegen coverage context (None).

Now, if coverage statements are encountered while compiling / linking
with `-Z instrument-coverage` disabled, codegen will *not* attempt to
add code regions to a coverage map, and it will not inject the LLVM
instrprof_increment intrinsic calls.
This commit is contained in:
Rich Kadel 2020-10-23 11:41:56 -07:00
parent 07a63e6d1f
commit a7bc1a2edf
5 changed files with 74 additions and 50 deletions

View File

@ -324,8 +324,8 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
} }
#[inline] #[inline]
pub fn coverage_context(&'a self) -> &'a coverageinfo::CrateCoverageContext<'tcx> { pub fn coverage_context(&'a self) -> Option<&'a coverageinfo::CrateCoverageContext<'tcx>> {
self.coverage_cx.as_ref().unwrap() self.coverage_cx.as_ref()
} }
} }

View File

@ -26,7 +26,10 @@ use tracing::debug;
/// undocumented details in Clang's implementation (that may or may not be important) were also /// undocumented details in Clang's implementation (that may or may not be important) were also
/// replicated for Rust's Coverage Map. /// replicated for Rust's Coverage Map.
pub fn finalize<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) { pub fn finalize<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) {
let function_coverage_map = cx.coverage_context().take_function_coverage_map(); if cx.coverage_context().is_none() {
return;
}
let function_coverage_map = cx.coverage_context().unwrap().take_function_coverage_map();
if function_coverage_map.is_empty() { if function_coverage_map.is_empty() {
// This module has no functions with coverage instrumentation // This module has no functions with coverage instrumentation
return; return;

View File

@ -64,17 +64,22 @@ impl CoverageInfoBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
function_source_hash: u64, function_source_hash: u64,
id: CounterValueReference, id: CounterValueReference,
region: CodeRegion, region: CodeRegion,
) { ) -> bool {
debug!( if let Some(coverage_context) = self.coverage_context() {
"adding counter to coverage_regions: instance={:?}, function_source_hash={}, id={:?}, \ debug!(
at {:?}", "adding counter to coverage_regions: instance={:?}, function_source_hash={}, id={:?}, \
instance, function_source_hash, id, region, at {:?}",
); instance, function_source_hash, id, region,
let mut coverage_regions = self.coverage_context().function_coverage_map.borrow_mut(); );
coverage_regions let mut coverage_regions = coverage_context.function_coverage_map.borrow_mut();
.entry(instance) coverage_regions
.or_insert_with(|| FunctionCoverage::new(self.tcx, instance)) .entry(instance)
.add_counter(function_source_hash, id, region); .or_insert_with(|| FunctionCoverage::new(self.tcx, instance))
.add_counter(function_source_hash, id, region);
true
} else {
false
}
} }
fn add_counter_expression_region( fn add_counter_expression_region(
@ -85,29 +90,39 @@ impl CoverageInfoBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
op: Op, op: Op,
rhs: ExpressionOperandId, rhs: ExpressionOperandId,
region: CodeRegion, region: CodeRegion,
) { ) -> bool {
debug!( if let Some(coverage_context) = self.coverage_context() {
"adding counter expression to coverage_regions: instance={:?}, id={:?}, {:?} {:?} {:?}, \ debug!(
at {:?}", "adding counter expression to coverage_regions: instance={:?}, id={:?}, {:?} {:?} {:?}, \
instance, id, lhs, op, rhs, region, at {:?}",
); instance, id, lhs, op, rhs, region,
let mut coverage_regions = self.coverage_context().function_coverage_map.borrow_mut(); );
coverage_regions let mut coverage_regions = coverage_context.function_coverage_map.borrow_mut();
.entry(instance) coverage_regions
.or_insert_with(|| FunctionCoverage::new(self.tcx, instance)) .entry(instance)
.add_counter_expression(id, lhs, op, rhs, region); .or_insert_with(|| FunctionCoverage::new(self.tcx, instance))
.add_counter_expression(id, lhs, op, rhs, region);
true
} else {
false
}
} }
fn add_unreachable_region(&mut self, instance: Instance<'tcx>, region: CodeRegion) { fn add_unreachable_region(&mut self, instance: Instance<'tcx>, region: CodeRegion) -> bool {
debug!( if let Some(coverage_context) = self.coverage_context() {
"adding unreachable code to coverage_regions: instance={:?}, at {:?}", debug!(
instance, region, "adding unreachable code to coverage_regions: instance={:?}, at {:?}",
); instance, region,
let mut coverage_regions = self.coverage_context().function_coverage_map.borrow_mut(); );
coverage_regions let mut coverage_regions = coverage_context.function_coverage_map.borrow_mut();
.entry(instance) coverage_regions
.or_insert_with(|| FunctionCoverage::new(self.tcx, instance)) .entry(instance)
.add_unreachable_region(region); .or_insert_with(|| FunctionCoverage::new(self.tcx, instance))
.add_unreachable_region(region);
true
} else {
false
}
} }
} }

View File

@ -10,19 +10,19 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
let Coverage { kind, code_region } = coverage; let Coverage { kind, code_region } = coverage;
match kind { match kind {
CoverageKind::Counter { function_source_hash, id } => { CoverageKind::Counter { function_source_hash, id } => {
bx.add_counter_region(self.instance, function_source_hash, id, code_region); if bx.add_counter_region(self.instance, function_source_hash, id, code_region) {
let coverageinfo = bx.tcx().coverageinfo(self.instance.def_id());
let coverageinfo = bx.tcx().coverageinfo(self.instance.def_id()); let fn_name = bx.create_pgo_func_name_var(self.instance);
let hash = bx.const_u64(function_source_hash);
let fn_name = bx.create_pgo_func_name_var(self.instance); let num_counters = bx.const_u32(coverageinfo.num_counters);
let hash = bx.const_u64(function_source_hash); let id = bx.const_u32(u32::from(id));
let num_counters = bx.const_u32(coverageinfo.num_counters); debug!(
let id = bx.const_u32(u32::from(id)); "codegen intrinsic instrprof.increment(fn_name={:?}, hash={:?}, num_counters={:?}, index={:?})",
debug!( fn_name, hash, num_counters, id,
"codegen intrinsic instrprof.increment(fn_name={:?}, hash={:?}, num_counters={:?}, index={:?})", );
fn_name, hash, num_counters, id, bx.instrprof_increment(fn_name, hash, num_counters, id);
); }
bx.instrprof_increment(fn_name, hash, num_counters, id);
} }
CoverageKind::Expression { id, lhs, op, rhs } => { CoverageKind::Expression { id, lhs, op, rhs } => {
bx.add_counter_expression_region(self.instance, id, lhs, op, rhs, code_region); bx.add_counter_expression_region(self.instance, id, lhs, op, rhs, code_region);

View File

@ -9,14 +9,18 @@ pub trait CoverageInfoMethods: BackendTypes {
pub trait CoverageInfoBuilderMethods<'tcx>: BackendTypes { pub trait CoverageInfoBuilderMethods<'tcx>: BackendTypes {
fn create_pgo_func_name_var(&self, instance: Instance<'tcx>) -> Self::Value; fn create_pgo_func_name_var(&self, instance: Instance<'tcx>) -> Self::Value;
/// Returns true if the counter was added to the coverage map; false if `-Z instrument-coverage`
/// is not enabled (a coverage map is not being generated).
fn add_counter_region( fn add_counter_region(
&mut self, &mut self,
instance: Instance<'tcx>, instance: Instance<'tcx>,
function_source_hash: u64, function_source_hash: u64,
id: CounterValueReference, id: CounterValueReference,
region: CodeRegion, region: CodeRegion,
); ) -> bool;
/// Returns true if the expression was added to the coverage map; false if
/// `-Z instrument-coverage` is not enabled (a coverage map is not being generated).
fn add_counter_expression_region( fn add_counter_expression_region(
&mut self, &mut self,
instance: Instance<'tcx>, instance: Instance<'tcx>,
@ -25,7 +29,9 @@ pub trait CoverageInfoBuilderMethods<'tcx>: BackendTypes {
op: Op, op: Op,
rhs: ExpressionOperandId, rhs: ExpressionOperandId,
region: CodeRegion, region: CodeRegion,
); ) -> bool;
fn add_unreachable_region(&mut self, instance: Instance<'tcx>, region: CodeRegion); /// Returns true if the region was added to the coverage map; false if `-Z instrument-coverage`
/// is not enabled (a coverage map is not being generated).
fn add_unreachable_region(&mut self, instance: Instance<'tcx>, region: CodeRegion) -> bool;
} }