From a7bc1a2edf6066c16b01f40a2a0120c9d6ff4a49 Mon Sep 17 00:00:00 2001 From: Rich Kadel Date: Fri, 23 Oct 2020 11:41:56 -0700 Subject: [PATCH 1/2] 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. --- compiler/rustc_codegen_llvm/src/context.rs | 4 +- .../src/coverageinfo/mapgen.rs | 5 +- .../src/coverageinfo/mod.rs | 79 +++++++++++-------- .../rustc_codegen_ssa/src/mir/coverageinfo.rs | 24 +++--- .../src/traits/coverageinfo.rs | 12 ++- 5 files changed, 74 insertions(+), 50 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 150cedde7e833..56ff580b43b59 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -324,8 +324,8 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { } #[inline] - pub fn coverage_context(&'a self) -> &'a coverageinfo::CrateCoverageContext<'tcx> { - self.coverage_cx.as_ref().unwrap() + pub fn coverage_context(&'a self) -> Option<&'a coverageinfo::CrateCoverageContext<'tcx>> { + self.coverage_cx.as_ref() } } diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs index 0098555a3736b..94ef33ac5b467 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs @@ -26,7 +26,10 @@ use tracing::debug; /// undocumented details in Clang's implementation (that may or may not be important) were also /// replicated for Rust's Coverage Map. 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() { // This module has no functions with coverage instrumentation return; diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs index 2bd37bf9c4f9c..7fdbe1a55128a 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs @@ -64,17 +64,22 @@ impl CoverageInfoBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> { function_source_hash: u64, id: CounterValueReference, region: CodeRegion, - ) { - debug!( - "adding counter to coverage_regions: instance={:?}, function_source_hash={}, id={:?}, \ - at {:?}", - instance, function_source_hash, id, region, - ); - let mut coverage_regions = self.coverage_context().function_coverage_map.borrow_mut(); - coverage_regions - .entry(instance) - .or_insert_with(|| FunctionCoverage::new(self.tcx, instance)) - .add_counter(function_source_hash, id, region); + ) -> bool { + if let Some(coverage_context) = self.coverage_context() { + debug!( + "adding counter to coverage_regions: instance={:?}, function_source_hash={}, id={:?}, \ + at {:?}", + instance, function_source_hash, id, region, + ); + let mut coverage_regions = coverage_context.function_coverage_map.borrow_mut(); + coverage_regions + .entry(instance) + .or_insert_with(|| FunctionCoverage::new(self.tcx, instance)) + .add_counter(function_source_hash, id, region); + true + } else { + false + } } fn add_counter_expression_region( @@ -85,29 +90,39 @@ impl CoverageInfoBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> { op: Op, rhs: ExpressionOperandId, region: CodeRegion, - ) { - debug!( - "adding counter expression to coverage_regions: instance={:?}, id={:?}, {:?} {:?} {:?}, \ - at {:?}", - instance, id, lhs, op, rhs, region, - ); - let mut coverage_regions = self.coverage_context().function_coverage_map.borrow_mut(); - coverage_regions - .entry(instance) - .or_insert_with(|| FunctionCoverage::new(self.tcx, instance)) - .add_counter_expression(id, lhs, op, rhs, region); + ) -> bool { + if let Some(coverage_context) = self.coverage_context() { + debug!( + "adding counter expression to coverage_regions: instance={:?}, id={:?}, {:?} {:?} {:?}, \ + at {:?}", + instance, id, lhs, op, rhs, region, + ); + let mut coverage_regions = coverage_context.function_coverage_map.borrow_mut(); + coverage_regions + .entry(instance) + .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) { - debug!( - "adding unreachable code to coverage_regions: instance={:?}, at {:?}", - instance, region, - ); - let mut coverage_regions = self.coverage_context().function_coverage_map.borrow_mut(); - coverage_regions - .entry(instance) - .or_insert_with(|| FunctionCoverage::new(self.tcx, instance)) - .add_unreachable_region(region); + fn add_unreachable_region(&mut self, instance: Instance<'tcx>, region: CodeRegion) -> bool { + if let Some(coverage_context) = self.coverage_context() { + debug!( + "adding unreachable code to coverage_regions: instance={:?}, at {:?}", + instance, region, + ); + let mut coverage_regions = coverage_context.function_coverage_map.borrow_mut(); + coverage_regions + .entry(instance) + .or_insert_with(|| FunctionCoverage::new(self.tcx, instance)) + .add_unreachable_region(region); + true + } else { + false + } } } diff --git a/compiler/rustc_codegen_ssa/src/mir/coverageinfo.rs b/compiler/rustc_codegen_ssa/src/mir/coverageinfo.rs index a2ad27b925c34..4811adea9ec06 100644 --- a/compiler/rustc_codegen_ssa/src/mir/coverageinfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/coverageinfo.rs @@ -10,19 +10,19 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let Coverage { kind, code_region } = coverage; match kind { 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 num_counters = bx.const_u32(coverageinfo.num_counters); - let id = bx.const_u32(u32::from(id)); - debug!( - "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); + let fn_name = bx.create_pgo_func_name_var(self.instance); + let hash = bx.const_u64(function_source_hash); + let num_counters = bx.const_u32(coverageinfo.num_counters); + let id = bx.const_u32(u32::from(id)); + debug!( + "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); + } } CoverageKind::Expression { id, lhs, op, rhs } => { bx.add_counter_expression_region(self.instance, id, lhs, op, rhs, code_region); diff --git a/compiler/rustc_codegen_ssa/src/traits/coverageinfo.rs b/compiler/rustc_codegen_ssa/src/traits/coverageinfo.rs index b74e4e459016f..3b1654f3ad4fc 100644 --- a/compiler/rustc_codegen_ssa/src/traits/coverageinfo.rs +++ b/compiler/rustc_codegen_ssa/src/traits/coverageinfo.rs @@ -9,14 +9,18 @@ pub trait CoverageInfoMethods: BackendTypes { pub trait CoverageInfoBuilderMethods<'tcx>: BackendTypes { 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( &mut self, instance: Instance<'tcx>, function_source_hash: u64, id: CounterValueReference, 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( &mut self, instance: Instance<'tcx>, @@ -25,7 +29,9 @@ pub trait CoverageInfoBuilderMethods<'tcx>: BackendTypes { op: Op, rhs: ExpressionOperandId, 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; } From f75a236fe0751a0d9bfb740c32eec14da787f112 Mon Sep 17 00:00:00 2001 From: Rich Kadel Date: Fri, 23 Oct 2020 14:58:08 -0700 Subject: [PATCH 2/2] Update compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs Co-authored-by: Wesley Wiser --- compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs index 94ef33ac5b467..c1163a871cf1f 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs @@ -26,10 +26,10 @@ use tracing::debug; /// undocumented details in Clang's implementation (that may or may not be important) were also /// replicated for Rust's Coverage Map. pub fn finalize<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) { - if cx.coverage_context().is_none() { - return; - } - let function_coverage_map = cx.coverage_context().unwrap().take_function_coverage_map(); + let function_coverage_map = match cx.coverage_context() { + Some(ctx) => ctx.take_function_coverage_map(), + None => return, + }; if function_coverage_map.is_empty() { // This module has no functions with coverage instrumentation return;