Skip to content

Commit ebf1e00

Browse files
committed
WIP attempt to add coverage 0 of dead blocks
...by saving dead counters/expressions. Unfortunately, I'm still getting the same result, when trying to get coverage from Fuchsia apps (at least those using fuchsia_async, but that may not be the specific cause): When running `llvm-cov` to get the coverage report, I get the well known and still useless message: ``` Failed to load coverage: Malformed instrumentation profile data ``` I can change CoverageMappingReader.cpp to avoid failing and I will see some coverage results (maybe most of the coverage results) but there is missing coverage as well. I don't know why the function name is not found. The "hack" is, change this: ```c++ if (Error Err = CFR->template getFuncName<Endian>(ProfileNames, FuncName)) return Err; if (FuncName.empty()) return make_error<InstrProfError>(instrprof_error::malformed); ++CovMapNumUsedRecords; ``` to this: ```c++ if (Error Err = CFR->template getFuncName<Endian>(ProfileNames, FuncName)) return Err; if (FuncName.empty()) FuncName = "MissingFuncNameForCoverage"; ++CovMapNumUsedRecords; ``` I did learn that the original implementation (replacing counters and expressions with Zero/unreachable counters), so this PR addresses that issue. I hoped that it would fix the problem, but it didn't. Specifically regarding the LLVM coverage adjustment (improvement?) made in this version, compared to the reverted PR (rust-lang#84797): LLVM requires all counters with code regions be added to the coverage map. The original dead block fix replaced the counters and expressions with a Zero (unreachable) code region. This commit saves the original counter or expression, without adding a statement to increment the counter for the eliminated dead block.
1 parent 4e4751b commit ebf1e00

File tree

5 files changed

+65
-32
lines changed

5 files changed

+65
-32
lines changed

compiler/rustc_codegen_ssa/src/coverageinfo/map.rs

+10-1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ pub struct Expression {
2828
/// only whitespace or comments). According to LLVM Code Coverage Mapping documentation, "A count
2929
/// for a gap area is only used as the line execution count if there are no other regions on a
3030
/// line."
31+
#[derive(Debug)]
3132
pub struct FunctionCoverage<'tcx> {
3233
instance: Instance<'tcx>,
3334
source_hash: u64,
@@ -51,7 +52,7 @@ impl<'tcx> FunctionCoverage<'tcx> {
5152
fn create(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>, is_used: bool) -> Self {
5253
let coverageinfo = tcx.coverageinfo(instance.def_id());
5354
debug!(
54-
"FunctionCoverage::new(instance={:?}) has coverageinfo={:?}. is_used={}",
55+
"FunctionCoverage::create(instance={:?}) has coverageinfo={:?}. is_used={}",
5556
instance, coverageinfo, is_used
5657
);
5758
Self {
@@ -113,6 +114,14 @@ impl<'tcx> FunctionCoverage<'tcx> {
113114
expression_id, lhs, op, rhs, region
114115
);
115116
let expression_index = self.expression_index(u32::from(expression_id));
117+
debug_assert!(
118+
expression_index.as_usize() < self.expressions.len(),
119+
"expression_index {} is out of range for expressions.len() = {}
120+
for {:?}",
121+
expression_index.as_usize(),
122+
self.expressions.len(),
123+
self,
124+
);
116125
if let Some(previous_expression) = self.expressions[expression_index].replace(Expression {
117126
lhs,
118127
op,

compiler/rustc_codegen_ssa/src/mir/coverageinfo.rs

+23-13
Original file line numberDiff line numberDiff line change
@@ -20,28 +20,38 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
2020

2121
let Coverage { kind, code_region } = coverage;
2222
match kind {
23-
CoverageKind::Counter { function_source_hash, id } => {
23+
CoverageKind::Counter { function_source_hash, id, is_dead } => {
2424
if bx.set_function_source_hash(instance, function_source_hash) {
2525
// If `set_function_source_hash()` returned true, the coverage map is enabled,
2626
// so continue adding the counter.
2727
if let Some(code_region) = code_region {
2828
// Note: Some counters do not have code regions, but may still be referenced
29-
// from expressions. In that case, don't add the counter to the coverage map,
30-
// but do inject the counter intrinsic.
29+
// from expressions. In that case, don't add the counter to the coverage
30+
// map, but do inject the counter intrinsic.
31+
if is_dead {
32+
debug!(
33+
"Adding coverage counter for dead code region: instance={:?},
34+
function_source_hash={:?}, id={:?}, code_region={:?}",
35+
instance, function_source_hash, id, code_region
36+
);
37+
}
3138
bx.add_coverage_counter(instance, id, code_region);
3239
}
3340

34-
let coverageinfo = bx.tcx().coverageinfo(instance.def_id());
41+
if !is_dead {
42+
let coverageinfo = bx.tcx().coverageinfo(instance.def_id());
3543

36-
let fn_name = bx.get_pgo_func_name_var(instance);
37-
let hash = bx.const_u64(function_source_hash);
38-
let num_counters = bx.const_u32(coverageinfo.num_counters);
39-
let index = bx.const_u32(id.zero_based_index());
40-
debug!(
41-
"codegen intrinsic instrprof.increment(fn_name={:?}, hash={:?}, num_counters={:?}, index={:?})",
42-
fn_name, hash, num_counters, index,
43-
);
44-
bx.instrprof_increment(fn_name, hash, num_counters, index);
44+
let fn_name = bx.get_pgo_func_name_var(instance);
45+
let hash = bx.const_u64(function_source_hash);
46+
let num_counters = bx.const_u32(coverageinfo.num_counters);
47+
let index = bx.const_u32(id.zero_based_index());
48+
debug!(
49+
"codegen intrinsic instrprof.increment(fn_name={:?}, hash={:?},
50+
num_counters={:?}, index={:?})",
51+
fn_name, hash, num_counters, index,
52+
);
53+
bx.instrprof_increment(fn_name, hash, num_counters, index);
54+
}
4555
}
4656
}
4757
CoverageKind::Expression { id, lhs, op, rhs } => {

compiler/rustc_middle/src/mir/coverage.rs

+20-5
Original file line numberDiff line numberDiff line change
@@ -102,16 +102,25 @@ impl From<InjectedExpressionId> for ExpressionOperandId {
102102

103103
#[derive(Clone, PartialEq, TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable)]
104104
pub enum CoverageKind {
105-
Counter {
106-
function_source_hash: u64,
107-
id: CounterValueReference,
108-
},
105+
/// A live `Counter` will codegen statements to increment the counter when
106+
/// its block is executed at runtime. A dead counter will not codegen
107+
/// anything, but will still be added to the coverage map, so it can still
108+
/// be referenced by expressions, and its code region will show up as
109+
/// uncovered.
110+
Counter { function_source_hash: u64, id: CounterValueReference, is_dead: bool },
111+
112+
/// A counter whose value can be computed when generating a coverage report.
113+
/// This statement does not codegen anything, but the expression and code
114+
/// region are added to the coverage map.
109115
Expression {
110116
id: InjectedExpressionId,
111117
lhs: ExpressionOperandId,
112118
op: Op,
113119
rhs: ExpressionOperandId,
114120
},
121+
122+
/// A code region that is never executed, and is never part of an
123+
/// expression.
115124
Unreachable,
116125
}
117126

@@ -134,7 +143,13 @@ impl Debug for CoverageKind {
134143
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
135144
use CoverageKind::*;
136145
match self {
137-
Counter { id, .. } => write!(fmt, "Counter({:?})", id.index()),
146+
Counter { id, is_dead, .. } => {
147+
if *is_dead {
148+
write!(fmt, "Counter({:?}/dead)", id.index())
149+
} else {
150+
write!(fmt, "Counter({:?})", id.index())
151+
}
152+
}
138153
Expression { id, lhs, op, rhs } => write!(
139154
fmt,
140155
"Expression({:?}) = {} {} {}",

compiler/rustc_mir/src/transform/coverage/counters.rs

+1
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ impl CoverageCounters {
5656
let counter = CoverageKind::Counter {
5757
function_source_hash: self.function_source_hash,
5858
id: self.next_counter(),
59+
is_dead: false,
5960
};
6061
if self.debug_counters.is_enabled() {
6162
self.debug_counters.add_counter(&counter, (debug_block_label_fn)());

compiler/rustc_mir/src/transform/simplify.rs

+11-13
Original file line numberDiff line numberDiff line change
@@ -329,24 +329,22 @@ fn save_unreachable_coverage(
329329
// report `0` executions for the uncovered code regions.
330330
let mut dropped_coverage = Vec::new();
331331
for dead_block in first_dead_block..basic_blocks.len() {
332-
for statement in basic_blocks[BasicBlock::new(dead_block)].statements.iter() {
333-
if let StatementKind::Coverage(coverage) = &statement.kind {
334-
if let Some(code_region) = &coverage.code_region {
335-
dropped_coverage.push((statement.source_info, code_region.clone()));
336-
}
332+
for statement in basic_blocks[BasicBlock::new(dead_block)].statements.drain(..) {
333+
if let StatementKind::Coverage(box coverage) = statement.kind {
334+
dropped_coverage.push((statement.source_info, coverage));
337335
}
338336
}
339337
}
340-
for (source_info, code_region) in dropped_coverage {
341-
basic_blocks[START_BLOCK].statements.push(Statement {
342-
source_info,
343-
kind: StatementKind::Coverage(box Coverage {
344-
kind: CoverageKind::Unreachable,
345-
code_region: Some(code_region),
346-
}),
347-
})
338+
for (source_info, mut coverage) in dropped_coverage {
339+
if let CoverageKind::Counter { ref mut is_dead, .. } = coverage.kind {
340+
*is_dead = true;
341+
}
342+
basic_blocks[START_BLOCK]
343+
.statements
344+
.push(Statement { source_info, kind: StatementKind::Coverage(box coverage) })
348345
}
349346
}
347+
350348
pub struct SimplifyLocals;
351349

352350
impl<'tcx> MirPass<'tcx> for SimplifyLocals {

0 commit comments

Comments
 (0)