Open Zalathar opened 1 year ago
@rustbot label -needs-triage
Fortunately for me, the changes can be reproduced on my ARM Mac, so I've looked into them a little bit.
$ RUSTC_LOG="rustc_mir_transform::coverage,rustc_codegen_llvm::coverageinfo" rustc +stage1 -Cinstrument-coverage --emit=llvm-ir --edition=2021 tests/coverage-map/status-quo/async2.rs 2> _stderr.txt
Looking at the logs, it seems that we do codegen the affected closures as normal, with corresponding covfun records. Yet for some reason they are missing from the coverage maps emitted by LLVM. So presumably something mysterious is happening inside LLVM that causes it to drop those functions, or at least drop their covfun records.
EDIT: This comment is bogus; I forgot to add -Copt-level=2
to my manual rustc invocation.
Looking at the LLVM IR, it seems that the closures have an unreachable body, with no remnant of the llvm.instrprof.increment
.
Perhaps that intrinsic is being optimized away before the InstrProfiling
pass sees it, so from the instrumentor's perspective it isn't instrumented at all.
Comparing the two LLVM IR dumps, it seems that the bodies for closure 0 are identical, and the bodies for closure 2 are identical. (Closure 1 is missing in both, presumably because it was merged with closure 2.)
So that's evidence against my hypothesis of the unreachable-only body being responsible.
If I set -Zmir-opt-level=1
(or lower), the problem doesn't occur, presumably because the changed MIR pass doesn't run.
If I go into unreachable_prop.rs
and comment out the loop that clears unreachable BBs, the problem also doesn't occur, though presumably that has the side-effect of making the MIR pass do less.
OK, I think I've found the problem.
If we instrument a function for coverage, but a MIR optimization later removes all of its CoverageKind::Counter
statements, LLVM treats it as not instrumented and it disappears from coverage reports.
A proper fix will need to wait until after #116046. Until then, the workaround is to avoid deleting StatementKind::Coverage
statements from mir::START_BLOCK
.
Actually, a better workaround is probably just to disable the UnreachablePropagation
pass entirely if coverage is enabled:
impl MirPass<'_> for UnreachablePropagation {
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
// Enable only under -Zmir-opt-level=2 as this can make programs less debuggable.
// Coverage gets confused by MIR passes that can remove all coverage statements
// from an instrumented function.
sess.mir_opt_level() >= 2 && !sess.instrument_coverage()
}
The changes in #113970 ended up changing the coverage mappings for
tests/coverage-map/status-quo/async2.rs
, but only on some targets.I wanted to create a place to put my notes from investigating that, without gunking up the original PR.
@rustbot label +A-code-coverage