Skip to content

Commit 371883a

Browse files
committed
coverage: Split FunctionCoverage into distinct collector/finished phases
This gives us a clearly-defined place to run code after the instance's MIR has been traversed by codegen, but before we emit its `__llvm_covfun` record.
1 parent cc3dce5 commit 371883a

File tree

3 files changed

+40
-24
lines changed

3 files changed

+40
-24
lines changed

compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs

Lines changed: 30 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use rustc_middle::ty::Instance;
1010
/// Holds all of the coverage mapping data associated with a function instance,
1111
/// collected during traversal of `Coverage` statements in the function's MIR.
1212
#[derive(Debug)]
13-
pub struct FunctionCoverage<'tcx> {
13+
pub struct FunctionCoverageCollector<'tcx> {
1414
/// Coverage info that was attached to this function by the instrumentor.
1515
function_coverage_info: &'tcx FunctionCoverageInfo,
1616
is_used: bool,
@@ -26,7 +26,7 @@ pub struct FunctionCoverage<'tcx> {
2626
expressions_seen: BitSet<ExpressionId>,
2727
}
2828

29-
impl<'tcx> FunctionCoverage<'tcx> {
29+
impl<'tcx> FunctionCoverageCollector<'tcx> {
3030
/// Creates a new set of coverage data for a used (called) function.
3131
pub fn new(
3232
instance: Instance<'tcx>,
@@ -76,11 +76,6 @@ impl<'tcx> FunctionCoverage<'tcx> {
7676
}
7777
}
7878

79-
/// Returns true for a used (called) function, and false for an unused function.
80-
pub fn is_used(&self) -> bool {
81-
self.is_used
82-
}
83-
8479
/// Marks a counter ID as having been seen in a counter-increment statement.
8580
#[instrument(level = "debug", skip(self))]
8681
pub(crate) fn mark_counter_id_seen(&mut self, id: CounterId) {
@@ -165,6 +160,28 @@ impl<'tcx> FunctionCoverage<'tcx> {
165160
ZeroExpressions(zero_expressions)
166161
}
167162

163+
pub(crate) fn into_finished(self) -> FunctionCoverage<'tcx> {
164+
let zero_expressions = self.identify_zero_expressions();
165+
let FunctionCoverageCollector { function_coverage_info, is_used, counters_seen, .. } = self;
166+
167+
FunctionCoverage { function_coverage_info, is_used, counters_seen, zero_expressions }
168+
}
169+
}
170+
171+
pub(crate) struct FunctionCoverage<'tcx> {
172+
function_coverage_info: &'tcx FunctionCoverageInfo,
173+
is_used: bool,
174+
175+
counters_seen: BitSet<CounterId>,
176+
zero_expressions: ZeroExpressions,
177+
}
178+
179+
impl<'tcx> FunctionCoverage<'tcx> {
180+
/// Returns true for a used (called) function, and false for an unused function.
181+
pub(crate) fn is_used(&self) -> bool {
182+
self.is_used
183+
}
184+
168185
/// Return the source hash, generated from the HIR node structure, and used to indicate whether
169186
/// or not the source code structure changed between different compilations.
170187
pub fn source_hash(&self) -> u64 {
@@ -177,29 +194,27 @@ impl<'tcx> FunctionCoverage<'tcx> {
177194
pub fn get_expressions_and_counter_regions(
178195
&self,
179196
) -> (Vec<CounterExpression>, impl Iterator<Item = (Counter, &CodeRegion)>) {
180-
let zero_expressions = self.identify_zero_expressions();
181-
182-
let counter_expressions = self.counter_expressions(&zero_expressions);
197+
let counter_expressions = self.counter_expressions();
183198
// Expression IDs are indices into `self.expressions`, and on the LLVM
184199
// side they will be treated as indices into `counter_expressions`, so
185200
// the two vectors should correspond 1:1.
186201
assert_eq!(self.function_coverage_info.expressions.len(), counter_expressions.len());
187202

188-
let counter_regions = self.counter_regions(zero_expressions);
203+
let counter_regions = self.counter_regions();
189204

190205
(counter_expressions, counter_regions)
191206
}
192207

193208
/// Convert this function's coverage expression data into a form that can be
194209
/// passed through FFI to LLVM.
195-
fn counter_expressions(&self, zero_expressions: &ZeroExpressions) -> Vec<CounterExpression> {
210+
fn counter_expressions(&self) -> Vec<CounterExpression> {
196211
// We know that LLVM will optimize out any unused expressions before
197212
// producing the final coverage map, so there's no need to do the same
198213
// thing on the Rust side unless we're confident we can do much better.
199214
// (See `CounterExpressionsMinimizer` in `CoverageMappingWriter.cpp`.)
200215

201216
let counter_from_operand = |operand: CovTerm| match operand {
202-
CovTerm::Expression(id) if zero_expressions.contains(id) => Counter::ZERO,
217+
CovTerm::Expression(id) if self.zero_expressions.contains(id) => Counter::ZERO,
203218
_ => Counter::from_term(operand),
204219
};
205220

@@ -219,18 +234,15 @@ impl<'tcx> FunctionCoverage<'tcx> {
219234

220235
/// Converts this function's coverage mappings into an intermediate form
221236
/// that will be used by `mapgen` when preparing for FFI.
222-
fn counter_regions(
223-
&self,
224-
zero_expressions: ZeroExpressions,
225-
) -> impl Iterator<Item = (Counter, &CodeRegion)> {
237+
fn counter_regions(&self) -> impl Iterator<Item = (Counter, &CodeRegion)> {
226238
// Historically, mappings were stored directly in counter/expression
227239
// statements in MIR, and MIR optimizations would sometimes remove them.
228240
// That's mostly no longer true, so now we detect cases where that would
229241
// have happened, and zero out the corresponding mappings here instead.
230242
let counter_for_term = move |term: CovTerm| {
231243
let force_to_zero = match term {
232244
CovTerm::Counter(id) => !self.counters_seen.contains(id),
233-
CovTerm::Expression(id) => zero_expressions.contains(id),
245+
CovTerm::Expression(id) => self.zero_expressions.contains(id),
234246
CovTerm::Zero => false,
235247
};
236248
if force_to_zero { Counter::ZERO } else { Counter::from_term(term) }

compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::common::CodegenCx;
22
use crate::coverageinfo;
33
use crate::coverageinfo::ffi::CounterMappingRegion;
4-
use crate::coverageinfo::map_data::FunctionCoverage;
4+
use crate::coverageinfo::map_data::{FunctionCoverage, FunctionCoverageCollector};
55
use crate::llvm;
66

77
use rustc_codegen_ssa::traits::{BaseTypeMethods, ConstMethods};
@@ -62,6 +62,7 @@ pub fn finalize(cx: &CodegenCx<'_, '_>) {
6262
// Encode coverage mappings and generate function records
6363
let mut function_data = Vec::new();
6464
for (instance, function_coverage) in function_coverage_map {
65+
let function_coverage = function_coverage.into_finished();
6566
debug!("Generate function coverage for {}, {:?}", cx.codegen_unit.name(), instance);
6667

6768
let mangled_function_name = tcx.symbol_name(instance).name;
@@ -419,7 +420,7 @@ fn add_unused_function_coverage<'tcx>(
419420
) {
420421
// An unused function's mappings will automatically be rewritten to map to
421422
// zero, because none of its counters/expressions are marked as seen.
422-
let function_coverage = FunctionCoverage::unused(instance, function_coverage_info);
423+
let function_coverage = FunctionCoverageCollector::unused(instance, function_coverage_info);
423424

424425
if let Some(coverage_context) = cx.coverage_context() {
425426
coverage_context.function_coverage_map.borrow_mut().insert(instance, function_coverage);

compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use crate::llvm;
33
use crate::builder::Builder;
44
use crate::common::CodegenCx;
55
use crate::coverageinfo::ffi::{CounterExpression, CounterMappingRegion};
6-
use crate::coverageinfo::map_data::FunctionCoverage;
6+
use crate::coverageinfo::map_data::FunctionCoverageCollector;
77

88
use libc::c_uint;
99
use rustc_codegen_ssa::traits::{
@@ -29,7 +29,8 @@ const VAR_ALIGN_BYTES: usize = 8;
2929
/// A context object for maintaining all state needed by the coverageinfo module.
3030
pub struct CrateCoverageContext<'ll, 'tcx> {
3131
/// Coverage data for each instrumented function identified by DefId.
32-
pub(crate) function_coverage_map: RefCell<FxHashMap<Instance<'tcx>, FunctionCoverage<'tcx>>>,
32+
pub(crate) function_coverage_map:
33+
RefCell<FxHashMap<Instance<'tcx>, FunctionCoverageCollector<'tcx>>>,
3334
pub(crate) pgo_func_name_var_map: RefCell<FxHashMap<Instance<'tcx>, &'ll llvm::Value>>,
3435
}
3536

@@ -41,7 +42,9 @@ impl<'ll, 'tcx> CrateCoverageContext<'ll, 'tcx> {
4142
}
4243
}
4344

44-
pub fn take_function_coverage_map(&self) -> FxHashMap<Instance<'tcx>, FunctionCoverage<'tcx>> {
45+
pub fn take_function_coverage_map(
46+
&self,
47+
) -> FxHashMap<Instance<'tcx>, FunctionCoverageCollector<'tcx>> {
4548
self.function_coverage_map.replace(FxHashMap::default())
4649
}
4750
}
@@ -93,7 +96,7 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
9396
let mut coverage_map = coverage_context.function_coverage_map.borrow_mut();
9497
let func_coverage = coverage_map
9598
.entry(instance)
96-
.or_insert_with(|| FunctionCoverage::new(instance, function_coverage_info));
99+
.or_insert_with(|| FunctionCoverageCollector::new(instance, function_coverage_info));
97100

98101
let Coverage { kind } = coverage;
99102
match *kind {

0 commit comments

Comments
 (0)