Skip to content

Commit 11a1e99

Browse files
committed
coverage: Store all of a function's mappings in function coverage info
1 parent 30e0910 commit 11a1e99

File tree

13 files changed

+62
-230
lines changed

13 files changed

+62
-230
lines changed

compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs

+28-47
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,10 @@ 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>>,
30-
mappings: Vec<Mapping>,
3130
}
3231

3332
impl<'tcx> FunctionCoverage<'tcx> {
@@ -63,7 +62,6 @@ impl<'tcx> FunctionCoverage<'tcx> {
6362
is_used,
6463
counters_seen: BitSet::new_empty(num_counters),
6564
expressions: IndexVec::from_elem_n(None, num_expressions),
66-
mappings: Vec::new(),
6765
}
6866
}
6967

@@ -72,28 +70,20 @@ impl<'tcx> FunctionCoverage<'tcx> {
7270
self.is_used
7371
}
7472

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

83-
/// Adds information about a coverage expression, along with zero or more
84-
/// code regions mapped to that expression.
85-
///
86-
/// Both counters and "counter expressions" (or simply, "expressions") can be operands in other
87-
/// expressions. These are tracked as separate variants of `CovTerm`, so there is no ambiguity
88-
/// between operands that are counter IDs and operands that are expression IDs.
79+
/// Adds information about a coverage expression.
8980
#[instrument(level = "debug", skip(self))]
9081
pub(crate) fn add_counter_expression(
9182
&mut self,
9283
expression_id: ExpressionId,
9384
lhs: CovTerm,
9485
op: Op,
9586
rhs: CovTerm,
96-
code_regions: &[CodeRegion],
9787
) {
9888
debug_assert!(
9989
expression_id.as_usize() < self.expressions.len(),
@@ -107,10 +97,7 @@ impl<'tcx> FunctionCoverage<'tcx> {
10797
let expression = Expression { lhs, op, rhs };
10898
let slot = &mut self.expressions[expression_id];
10999
match slot {
110-
None => {
111-
*slot = Some(expression);
112-
self.add_mappings(CovTerm::Expression(expression_id), code_regions);
113-
}
100+
None => *slot = Some(expression),
114101
// If this expression ID slot has already been filled, it should
115102
// contain identical information.
116103
Some(ref previous_expression) => assert_eq!(
@@ -120,29 +107,6 @@ impl<'tcx> FunctionCoverage<'tcx> {
120107
}
121108
}
122109

123-
/// Adds regions that will be marked as "unreachable", with a constant "zero counter".
124-
#[instrument(level = "debug", skip(self))]
125-
pub(crate) fn add_unreachable_regions(&mut self, code_regions: &[CodeRegion]) {
126-
assert!(!code_regions.is_empty(), "unreachable regions always have code regions");
127-
self.add_mappings(CovTerm::Zero, code_regions);
128-
}
129-
130-
#[instrument(level = "debug", skip(self))]
131-
fn add_mappings(&mut self, term: CovTerm, code_regions: &[CodeRegion]) {
132-
self.mappings
133-
.extend(code_regions.iter().cloned().map(|code_region| Mapping { term, code_region }));
134-
}
135-
136-
pub(crate) fn finalize(&mut self) {
137-
// Reorder the collected mappings so that counter mappings are first and
138-
// zero mappings are last, matching the historical order.
139-
self.mappings.sort_by_key(|mapping| match mapping.term {
140-
CovTerm::Counter(_) => 0,
141-
CovTerm::Expression(_) => 1,
142-
CovTerm::Zero => u8::MAX,
143-
});
144-
}
145-
146110
/// Identify expressions that will always have a value of zero, and note
147111
/// their IDs in `zero_expressions`. Mappings that refer to a zero expression
148112
/// can instead become mappings to a constant zero value.
@@ -222,7 +186,7 @@ impl<'tcx> FunctionCoverage<'tcx> {
222186
// the two vectors should correspond 1:1.
223187
assert_eq!(self.expressions.len(), counter_expressions.len());
224188

225-
let counter_regions = self.counter_regions();
189+
let counter_regions = self.counter_regions(zero_expressions);
226190

227191
(counter_expressions, counter_regions)
228192
}
@@ -267,9 +231,26 @@ impl<'tcx> FunctionCoverage<'tcx> {
267231

268232
/// Converts this function's coverage mappings into an intermediate form
269233
/// that will be used by `mapgen` when preparing for FFI.
270-
fn counter_regions(&self) -> impl Iterator<Item = (Counter, &CodeRegion)> {
271-
self.mappings.iter().map(|&Mapping { term, ref code_region }| {
272-
let counter = Counter::from_term(term);
234+
fn counter_regions(
235+
&self,
236+
zero_expressions: ZeroExpressions,
237+
) -> impl Iterator<Item = (Counter, &CodeRegion)> {
238+
// Historically, mappings were stored directly in counter/expression
239+
// statements in MIR, and MIR optimizations would sometimes remove them.
240+
// That's mostly no longer true, so now we detect cases where that would
241+
// have happened, and zero out the corresponding mappings here instead.
242+
let counter_for_term = move |term: CovTerm| {
243+
let force_to_zero = match term {
244+
CovTerm::Counter(id) => !self.counters_seen.contains(id),
245+
CovTerm::Expression(id) => zero_expressions.contains(id),
246+
CovTerm::Zero => false,
247+
};
248+
if force_to_zero { Counter::ZERO } else { Counter::from_term(term) }
249+
};
250+
251+
self.function_coverage_info.mappings.iter().map(move |mapping| {
252+
let &Mapping { term, ref code_region } = mapping;
253+
let counter = counter_for_term(term);
273254
(counter, code_region)
274255
})
275256
}

compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,8 @@ pub fn finalize(cx: &CodegenCx<'_, '_>) {
5959

6060
// Encode coverage mappings and generate function records
6161
let mut function_data = Vec::new();
62-
for (instance, mut function_coverage) in function_coverage_map {
62+
for (instance, function_coverage) in function_coverage_map {
6363
debug!("Generate function coverage for {}, {:?}", cx.codegen_unit.name(), instance);
64-
function_coverage.finalize();
65-
let function_coverage = function_coverage;
6664

6765
let mangled_function_name = tcx.symbol_name(instance).name;
6866
let source_hash = function_coverage.source_hash();

compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs

+7-15
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,11 @@ 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+
// An unused function's mappings will automatically be rewritten to map to
217+
// zero, because none of its counters/expressions are marked as seen.
218+
let function_coverage = FunctionCoverage::unused(instance, function_coverage_info);
227219

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

compiler/rustc_middle/src/mir/coverage.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,6 @@ pub enum CoverageKind {
7474
op: Op,
7575
rhs: CovTerm,
7676
},
77-
Unreachable,
7877
}
7978

8079
impl Debug for CoverageKind {
@@ -93,7 +92,6 @@ impl Debug for CoverageKind {
9392
},
9493
rhs,
9594
),
96-
Unreachable => write!(fmt, "Unreachable"),
9795
}
9896
}
9997
}
@@ -158,4 +156,6 @@ pub struct FunctionCoverageInfo {
158156
pub function_source_hash: u64,
159157
pub num_counters: usize,
160158
pub num_expressions: usize,
159+
160+
pub mappings: Vec<Mapping>,
161161
}

compiler/rustc_middle/src/mir/pretty.rs

+1-7
Original file line numberDiff line numberDiff line change
@@ -685,13 +685,7 @@ impl Debug for Statement<'_> {
685685
AscribeUserType(box (ref place, ref c_ty), ref variance) => {
686686
write!(fmt, "AscribeUserType({place:?}, {variance:?}, {c_ty:?})")
687687
}
688-
Coverage(box mir::Coverage { ref kind, ref code_regions }) => {
689-
if code_regions.is_empty() {
690-
write!(fmt, "Coverage::{kind:?}")
691-
} else {
692-
write!(fmt, "Coverage::{kind:?} for {code_regions:?}")
693-
}
694-
}
688+
Coverage(box mir::Coverage { ref kind }) => write!(fmt, "Coverage::{kind:?}"),
695689
Intrinsic(box ref intrinsic) => write!(fmt, "{intrinsic}"),
696690
ConstEvalCounter => write!(fmt, "ConstEvalCounter"),
697691
Nop => write!(fmt, "nop"),

compiler/rustc_middle/src/mir/syntax.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
66
use super::{BasicBlock, Const, Local, 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;
@@ -513,7 +513,6 @@ pub enum FakeReadCause {
513513
#[derive(TypeFoldable, TypeVisitable)]
514514
pub struct Coverage {
515515
pub kind: CoverageKind,
516-
pub code_regions: Vec<CodeRegion>,
517516
}
518517

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

compiler/rustc_middle/src/query/mod.rs

-11
Original file line numberDiff line numberDiff line change
@@ -574,17 +574,6 @@ rustc_queries! {
574574
arena_cache
575575
}
576576

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

compiler/rustc_mir_transform/src/coverage/mod.rs

+12-20
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ struct Instrumentor<'a, 'tcx> {
104104
function_source_hash: u64,
105105
basic_coverage_blocks: CoverageGraph,
106106
coverage_counters: CoverageCounters,
107+
mappings: Vec<Mapping>,
107108
}
108109

109110
impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
@@ -144,6 +145,7 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
144145
function_source_hash,
145146
basic_coverage_blocks,
146147
coverage_counters,
148+
mappings: Vec::new(),
147149
}
148150
}
149151

@@ -216,6 +218,7 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
216218
function_source_hash: self.function_source_hash,
217219
num_counters: self.coverage_counters.num_counters(),
218220
num_expressions: self.coverage_counters.num_expressions(),
221+
mappings: std::mem::take(&mut self.mappings),
219222
}));
220223
}
221224

@@ -232,18 +235,16 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
232235
bug!("Every BasicCoverageBlock should have a Counter or Expression");
233236
});
234237

235-
// Convert the coverage spans into a vector of code regions to be
236-
// associated with this BCB's coverage statement.
237-
let code_regions = spans
238-
.iter()
239-
.map(|&span| make_code_region(source_map, file_name, span, body_span))
240-
.collect::<Vec<_>>();
238+
let term = counter_kind.as_term();
239+
self.mappings.extend(spans.iter().map(|&span| {
240+
let code_region = make_code_region(source_map, file_name, span, body_span);
241+
Mapping { code_region, term }
242+
}));
241243

242244
inject_statement(
243245
self.mir_body,
244246
self.make_mir_coverage_kind(&counter_kind),
245247
self.bcb_leader_bb(bcb),
246-
code_regions,
247248
);
248249
}
249250
}
@@ -301,7 +302,6 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
301302
self.mir_body,
302303
self.make_mir_coverage_kind(&counter_kind),
303304
inject_to_bb,
304-
Vec::new(),
305305
);
306306
}
307307
BcbCounter::Expression { .. } => inject_intermediate_expression(
@@ -360,18 +360,13 @@ fn inject_edge_counter_basic_block(
360360
new_bb
361361
}
362362

363-
fn inject_statement(
364-
mir_body: &mut mir::Body<'_>,
365-
counter_kind: CoverageKind,
366-
bb: BasicBlock,
367-
code_regions: Vec<CodeRegion>,
368-
) {
369-
debug!(" injecting statement {counter_kind:?} for {bb:?} at code regions: {code_regions:?}");
363+
fn inject_statement(mir_body: &mut mir::Body<'_>, counter_kind: CoverageKind, bb: BasicBlock) {
364+
debug!(" injecting statement {counter_kind:?} for {bb:?}");
370365
let data = &mut mir_body[bb];
371366
let source_info = data.terminator().source_info;
372367
let statement = Statement {
373368
source_info,
374-
kind: StatementKind::Coverage(Box::new(Coverage { kind: counter_kind, code_regions })),
369+
kind: StatementKind::Coverage(Box::new(Coverage { kind: counter_kind })),
375370
};
376371
data.statements.insert(0, statement);
377372
}
@@ -385,10 +380,7 @@ fn inject_intermediate_expression(mir_body: &mut mir::Body<'_>, expression: Cove
385380
let source_info = data.terminator().source_info;
386381
let statement = Statement {
387382
source_info,
388-
kind: StatementKind::Coverage(Box::new(Coverage {
389-
kind: expression,
390-
code_regions: Vec::new(),
391-
})),
383+
kind: StatementKind::Coverage(Box::new(Coverage { kind: expression })),
392384
};
393385
data.statements.push(statement);
394386
}

0 commit comments

Comments
 (0)