Skip to content

Commit 7ad4349

Browse files
committed
coverage: Store all of a function's mappings in FunctionCoverageInfo
1 parent 34b9792 commit 7ad4349

File tree

14 files changed

+56
-225
lines changed

14 files changed

+56
-225
lines changed

compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs

Lines changed: 18 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,13 @@ pub struct FunctionCoverage<'tcx> {
2323
function_coverage_info: &'tcx FunctionCoverageInfo,
2424
is_used: bool,
2525

26-
/// Tracks which counters have been seen, to avoid duplicate mappings
27-
/// that might be introduced by MIR inlining.
26+
/// Tracks which counters have been seen, so that we can identify mappings
27+
/// to counters that were optimized out, and set them to zero.
2828
counters_seen: BitSet<CounterId>,
2929
expressions: IndexVec<ExpressionId, Option<Expression>>,
3030
/// Tracks which expressions are known to always have a value of zero.
3131
/// Only updated during the finalize step.
3232
zero_expressions: FxIndexSet<ExpressionId>,
33-
mappings: Vec<Mapping>,
3433
}
3534

3635
impl<'tcx> FunctionCoverage<'tcx> {
@@ -67,7 +66,6 @@ impl<'tcx> FunctionCoverage<'tcx> {
6766
counters_seen: BitSet::new_empty(num_counters),
6867
expressions: IndexVec::from_elem_n(None, num_expressions),
6968
zero_expressions: FxIndexSet::default(),
70-
mappings: Vec::new(),
7169
}
7270
}
7371

@@ -76,28 +74,20 @@ impl<'tcx> FunctionCoverage<'tcx> {
7674
self.is_used
7775
}
7876

79-
/// Adds code regions to be counted by an injected counter intrinsic.
77+
/// Marks a counter ID as having been seen in a counter-increment statement.
8078
#[instrument(level = "debug", skip(self))]
81-
pub(crate) fn add_counter(&mut self, id: CounterId, code_regions: &[CodeRegion]) {
82-
if self.counters_seen.insert(id) {
83-
self.add_mappings(CovTerm::Counter(id), code_regions);
84-
}
79+
pub(crate) fn add_counter(&mut self, id: CounterId) {
80+
self.counters_seen.insert(id);
8581
}
8682

87-
/// Adds information about a coverage expression, along with zero or more
88-
/// code regions mapped to that expression.
89-
///
90-
/// Both counters and "counter expressions" (or simply, "expressions") can be operands in other
91-
/// expressions. These are tracked as separate variants of `CovTerm`, so there is no ambiguity
92-
/// between operands that are counter IDs and operands that are expression IDs.
83+
/// Adds information about a coverage expression.
9384
#[instrument(level = "debug", skip(self))]
9485
pub(crate) fn add_counter_expression(
9586
&mut self,
9687
expression_id: ExpressionId,
9788
lhs: CovTerm,
9889
op: Op,
9990
rhs: CovTerm,
100-
code_regions: &[CodeRegion],
10191
) {
10292
debug_assert!(
10393
expression_id.as_usize() < self.expressions.len(),
@@ -111,10 +101,7 @@ impl<'tcx> FunctionCoverage<'tcx> {
111101
let expression = Expression { lhs, op, rhs };
112102
let slot = &mut self.expressions[expression_id];
113103
match slot {
114-
None => {
115-
*slot = Some(expression);
116-
self.add_mappings(CovTerm::Expression(expression_id), code_regions);
117-
}
104+
None => *slot = Some(expression),
118105
// If this expression ID slot has already been filled, it should
119106
// contain identical information.
120107
Some(ref previous_expression) => assert_eq!(
@@ -124,25 +111,8 @@ impl<'tcx> FunctionCoverage<'tcx> {
124111
}
125112
}
126113

127-
/// Adds regions that will be marked as "unreachable", with a constant "zero counter".
128-
#[instrument(level = "debug", skip(self))]
129-
pub(crate) fn add_unreachable_regions(&mut self, code_regions: &[CodeRegion]) {
130-
assert!(!code_regions.is_empty(), "unreachable regions always have code regions");
131-
self.add_mappings(CovTerm::Zero, code_regions);
132-
}
133-
134-
#[instrument(level = "debug", skip(self))]
135-
fn add_mappings(&mut self, term: CovTerm, code_regions: &[CodeRegion]) {
136-
self.mappings
137-
.extend(code_regions.iter().cloned().map(|code_region| Mapping { term, code_region }));
138-
}
139-
140114
pub(crate) fn finalize(&mut self) {
141115
self.update_zero_expressions();
142-
143-
// Sort all of the collected mappings into a predictable order.
144-
// (Mappings have a total order, so an unstable sort should be fine.)
145-
self.mappings.sort_unstable();
146116
}
147117

148118
/// Identify expressions that will always have a value of zero, and note
@@ -249,8 +219,17 @@ impl<'tcx> FunctionCoverage<'tcx> {
249219
/// Converts this function's coverage mappings into an intermediate form
250220
/// that will be used by `mapgen` when preparing for FFI.
251221
pub(crate) fn mappings_for_ffi(&self) -> impl Iterator<Item = (Counter, &CodeRegion)> {
252-
self.mappings.iter().map(|&Mapping { term, ref code_region }| {
253-
let counter = Counter::from_term(term);
222+
self.function_coverage_info.mappings.iter().map(|&Mapping { term, ref code_region }| {
223+
// Historically, mappings were stored directly in counter/expression
224+
// statements in MIR, and MIR optimizations would sometimes remove them.
225+
// That's mostly no longer true, so now we detect cases where that would
226+
// have happened, and zero out the corresponding mappings here instead.
227+
let force_to_zero = match term {
228+
CovTerm::Counter(id) => !self.counters_seen.contains(id),
229+
CovTerm::Expression(id) => self.zero_expressions.contains(&id),
230+
CovTerm::Zero => false,
231+
};
232+
let counter = if force_to_zero { Counter::ZERO } else { Counter::from_term(term) };
254233
(counter, code_region)
255234
})
256235
}

compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
9696
fn define_unused_fn(&self, def_id: DefId, function_coverage_info: &'tcx FunctionCoverageInfo) {
9797
let instance = declare_unused_fn(self, def_id);
9898
codegen_unused_fn_and_counter(self, instance);
99-
add_unused_function_coverage(self, instance, def_id, function_coverage_info);
99+
add_unused_function_coverage(self, instance, function_coverage_info);
100100
}
101101
}
102102

@@ -116,10 +116,10 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
116116
.entry(instance)
117117
.or_insert_with(|| FunctionCoverage::new(instance, function_coverage_info));
118118

119-
let Coverage { kind, code_regions } = coverage;
119+
let Coverage { kind } = coverage;
120120
match *kind {
121121
CoverageKind::Counter { id } => {
122-
func_coverage.add_counter(id, code_regions);
122+
func_coverage.add_counter(id);
123123
// We need to explicitly drop the `RefMut` before calling into `instrprof_increment`,
124124
// as that needs an exclusive borrow.
125125
drop(coverage_map);
@@ -148,10 +148,7 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
148148
bx.instrprof_increment(fn_name, hash, num_counters, index);
149149
}
150150
CoverageKind::Expression { id, lhs, op, rhs } => {
151-
func_coverage.add_counter_expression(id, lhs, op, rhs, code_regions);
152-
}
153-
CoverageKind::Unreachable => {
154-
func_coverage.add_unreachable_regions(code_regions);
151+
func_coverage.add_counter_expression(id, lhs, op, rhs);
155152
}
156153
}
157154
}
@@ -214,16 +211,9 @@ fn codegen_unused_fn_and_counter<'tcx>(cx: &CodegenCx<'_, 'tcx>, instance: Insta
214211
fn add_unused_function_coverage<'tcx>(
215212
cx: &CodegenCx<'_, 'tcx>,
216213
instance: Instance<'tcx>,
217-
def_id: DefId,
218214
function_coverage_info: &'tcx FunctionCoverageInfo,
219215
) {
220-
let tcx = cx.tcx;
221-
222-
let mut function_coverage = FunctionCoverage::unused(instance, function_coverage_info);
223-
for &code_region in tcx.covered_code_regions(def_id) {
224-
let code_region = std::slice::from_ref(code_region);
225-
function_coverage.add_unreachable_regions(code_region);
226-
}
216+
let function_coverage = FunctionCoverage::unused(instance, function_coverage_info);
227217

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

compiler/rustc_middle/src/mir/coverage.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,9 @@ impl ExpressionId {
4444
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
4545
#[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)]
4646
pub enum CovTerm {
47-
// Coverage codegen relies on this variant order when it sorts a function's mappings.
47+
Zero,
4848
Counter(CounterId),
4949
Expression(ExpressionId),
50-
Zero,
5150
}
5251

5352
impl Debug for CovTerm {
@@ -75,7 +74,6 @@ pub enum CoverageKind {
7574
op: Op,
7675
rhs: CovTerm,
7776
},
78-
Unreachable,
7977
}
8078

8179
impl Debug for CoverageKind {
@@ -94,7 +92,6 @@ impl Debug for CoverageKind {
9492
},
9593
rhs,
9694
),
97-
Unreachable => write!(fmt, "Unreachable"),
9895
}
9996
}
10097
}
@@ -139,6 +136,7 @@ impl Op {
139136
}
140137

141138
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
139+
#[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)]
142140
pub struct Mapping {
143141
// Coverage codegen relies on this field order when it sorts a function's mappings.
144142
pub code_region: CodeRegion,
@@ -161,4 +159,6 @@ pub struct FunctionCoverageInfo {
161159
pub function_source_hash: u64,
162160
pub num_counters: usize,
163161
pub num_expressions: usize,
162+
163+
pub mappings: Vec<Mapping>,
164164
}

compiler/rustc_middle/src/mir/mod.rs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1484,12 +1484,8 @@ impl Debug for Statement<'_> {
14841484
AscribeUserType(box (ref place, ref c_ty), ref variance) => {
14851485
write!(fmt, "AscribeUserType({place:?}, {variance:?}, {c_ty:?})")
14861486
}
1487-
Coverage(box self::Coverage { ref kind, ref code_regions }) => {
1488-
if code_regions.is_empty() {
1489-
write!(fmt, "Coverage::{kind:?}")
1490-
} else {
1491-
write!(fmt, "Coverage::{kind:?} for {code_regions:?}")
1492-
}
1487+
Coverage(box self::Coverage { ref kind }) => {
1488+
write!(fmt, "Coverage::{kind:?}")
14931489
}
14941490
Intrinsic(box ref intrinsic) => write!(fmt, "{intrinsic}"),
14951491
ConstEvalCounter => write!(fmt, "ConstEvalCounter"),

compiler/rustc_middle/src/mir/syntax.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
66
use super::{BasicBlock, Constant, Local, SwitchTargets, UserTypeProjection};
77

8-
use crate::mir::coverage::{CodeRegion, CoverageKind};
8+
use crate::mir::coverage::CoverageKind;
99
use crate::traits::Reveal;
1010
use crate::ty::adjustment::PointerCoercion;
1111
use crate::ty::GenericArgsRef;
@@ -523,7 +523,6 @@ pub enum FakeReadCause {
523523
#[derive(TypeFoldable, TypeVisitable)]
524524
pub struct Coverage {
525525
pub kind: CoverageKind,
526-
pub code_regions: Vec<CodeRegion>,
527526
}
528527

529528
#[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)]

compiler/rustc_middle/src/query/mod.rs

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -575,17 +575,6 @@ rustc_queries! {
575575
arena_cache
576576
}
577577

578-
/// Returns the `CodeRegions` for a function that has instrumented coverage, in case the
579-
/// function was optimized out before codegen, and before being added to the Coverage Map.
580-
query covered_code_regions(key: DefId) -> &'tcx Vec<&'tcx mir::coverage::CodeRegion> {
581-
desc {
582-
|tcx| "retrieving the covered `CodeRegion`s, if instrumented, for `{}`",
583-
tcx.def_path_str(key)
584-
}
585-
arena_cache
586-
cache_on_disk_if { key.is_local() }
587-
}
588-
589578
/// The `DefId` is the `DefId` of the containing MIR body. Promoteds do not have their own
590579
/// `DefId`. This function returns all promoteds in the specified body. The body references
591580
/// promoteds by the `DefId` and the `mir::Promoted` index. This is necessary, because

compiler/rustc_mir_transform/src/coverage/mod.rs

Lines changed: 13 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ struct Instrumentor<'a, 'tcx> {
107107
function_source_hash: u64,
108108
basic_coverage_blocks: CoverageGraph,
109109
coverage_counters: CoverageCounters,
110+
mappings: Vec<Mapping>,
110111
}
111112

112113
impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
@@ -148,6 +149,7 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
148149
function_source_hash,
149150
basic_coverage_blocks,
150151
coverage_counters,
152+
mappings: Vec::new(),
151153
}
152154
}
153155

@@ -281,6 +283,7 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
281283
function_source_hash: self.function_source_hash,
282284
num_counters: self.coverage_counters.num_counters(),
283285
num_expressions: self.coverage_counters.num_expressions(),
286+
mappings: std::mem::take(&mut self.mappings),
284287
}));
285288
}
286289

@@ -311,20 +314,17 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
311314
debug_used_expressions.add_expression_operands(&counter_kind);
312315
graphviz_data.add_bcb_coverage_spans_with_counter(bcb, bcb_spans, &counter_kind);
313316

314-
// Convert the coverage spans into a vector of code regions to be
315-
// associated with this BCB's coverage statement.
316-
let code_regions = bcb_spans
317-
.iter()
318-
.map(|coverage_span| {
319-
make_code_region(source_map, file_name, coverage_span.span, body_span)
320-
})
321-
.collect::<Vec<_>>();
317+
let term = counter_kind.as_term();
318+
self.mappings.extend(bcb_spans.iter().map(|coverage_span| {
319+
let code_region =
320+
make_code_region(source_map, file_name, coverage_span.span, body_span);
321+
Mapping { code_region, term }
322+
}));
322323

323324
inject_statement(
324325
self.mir_body,
325326
self.make_mir_coverage_kind(&counter_kind),
326327
self.bcb_leader_bb(bcb),
327-
code_regions,
328328
);
329329
}
330330
}
@@ -407,7 +407,6 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
407407
self.mir_body,
408408
self.make_mir_coverage_kind(&counter_kind),
409409
inject_to_bb,
410-
Vec::new(),
411410
);
412411
}
413412
BcbCounter::Expression { .. } => inject_intermediate_expression(
@@ -471,18 +470,13 @@ fn inject_edge_counter_basic_block(
471470
new_bb
472471
}
473472

474-
fn inject_statement(
475-
mir_body: &mut mir::Body<'_>,
476-
counter_kind: CoverageKind,
477-
bb: BasicBlock,
478-
code_regions: Vec<CodeRegion>,
479-
) {
480-
debug!(" injecting statement {counter_kind:?} for {bb:?} at code regions: {code_regions:?}");
473+
fn inject_statement(mir_body: &mut mir::Body<'_>, counter_kind: CoverageKind, bb: BasicBlock) {
474+
debug!(" injecting statement {counter_kind:?} for {bb:?}");
481475
let data = &mut mir_body[bb];
482476
let source_info = data.terminator().source_info;
483477
let statement = Statement {
484478
source_info,
485-
kind: StatementKind::Coverage(Box::new(Coverage { kind: counter_kind, code_regions })),
479+
kind: StatementKind::Coverage(Box::new(Coverage { kind: counter_kind })),
486480
};
487481
data.statements.insert(0, statement);
488482
}
@@ -496,10 +490,7 @@ fn inject_intermediate_expression(mir_body: &mut mir::Body<'_>, expression: Cove
496490
let source_info = data.terminator().source_info;
497491
let statement = Statement {
498492
source_info,
499-
kind: StatementKind::Coverage(Box::new(Coverage {
500-
kind: expression,
501-
code_regions: Vec::new(),
502-
})),
493+
kind: StatementKind::Coverage(Box::new(Coverage { kind: expression })),
503494
};
504495
data.statements.push(statement);
505496
}

0 commit comments

Comments
 (0)