Skip to content

MC/DC Coverage re-introduction (3/3): Codegen - #161224

Open
RenjiSann wants to merge 13 commits into
rust-lang:mainfrom
RenjiSann:mcdc-step-codegen
Open

RenjiSann wants to merge 13 commits into
rust-lang:mainfrom
RenjiSann:mcdc-step-codegen

Conversation

@RenjiSann

Copy link
Copy Markdown
Contributor

Follow-up of #161223

Tracking issue: rust-lang/goals#638

Finalize MC/DC implementation for boolean expressions.

  1. Introduce FFI structures and functions for passing MC/DC mappings to LLVM
  2. Transform MC/DC MIR statements into their corresponding LLVM instructions
  3. Add tests

r? @davidtwco

@rustbot

rustbot commented Aug 17, 2026

Copy link
Copy Markdown
Collaborator

Some changes occurred in coverage instrumentation.

cc @Zalathar

Some changes occurred in match lowering

cc @Nadrieril

Some changes occurred to MIR optimizations

cc @rust-lang/wg-mir-opt

Some changes occurred in coverage instrumentation.

cc @Zalathar

Some changes occurred in coverage tests.

cc @Zalathar

Some changes occurred in coverage instrumentation.

cc @Zalathar

Some changes occurred in coverage instrumentation.

cc @Zalathar

@rustbot rustbot added A-LLVM Area: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues. S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Aug 17, 2026
@rust-log-analyzer

This comment has been minimized.

@RenjiSann
RenjiSann force-pushed the mcdc-step-codegen branch 2 times, most recently from 2c18611 to a0fc461 Compare August 17, 2026 10:09
@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@rust-bors

rust-bors Bot commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

☔ The latest upstream changes (presumably #162009) made this pull request unmergeable. Please resolve the merge conflicts by rebasing.

@gelintonx

Copy link
Copy Markdown

TLDR: with this stack, llvm-cov crashes (SIGILL in CoverageMapping::loadFunctionRecord) on binaries containing a matches! used as a condition inside a &&/|| decision. The same logic written as (v == 1 || v == 2) works.

Reproducer (repro.rs):

fn f(a: bool, v: u8, t: bool) -> bool {
   !a && matches!(v, 1 | 2) && t
}
fn main() {
  for (a, v, t) in [(false,1,true), (true,1,true), (false,3,true), (false,2,false)] {
   std::hint::black_box(f(a,v,t));
}
}
rustc -Cinstrument-coverage -Zcoverage-options=mcdc repro.rs              
LLVM_PROFILE_FILE=r.profraw ./repro                                       
llvm-profdata merge -o r.profdata r.profraw                               
llvm-cov show --show-mcdc ./repro -instr-profile=r.profdata   # Illegal instruction, exit code 132                          

Control: replacing matches!(v, 1 | 2) with (v == 1 || v == 2) gives exit code 0 and a normal MC/DC decision report.
Environment: this PR's head 1f916c0, stage 1 compiler (./x build --stage 1 library), x86_64 Ubuntu 24.04. llvm-cov/llvm-profdata are the LLVM 22.1.8 tools from the CI rust-dev artifact that bootstrap downloads, not a local LLVM build. I reproduced it on 2 fresh machines. This is agains current head per example before the rebase needed after #162009 (coverage struct renames in #161902).

Stack trace:

   #3 llvm::coverage::CoverageMapping::loadFunctionRecord(llvm::coverage::CoverageMappingRecord
  const&, std::optional<std::reference_wrapper<llvm::IndexedInstrProfReader>> 
  const&) (libLLVM.so.22.1-rust-1.99.0-nightly+0x825e026)                     
     #4 llvm::coverage::CoverageMapping::loadFromReaders(...) (libLLVM.so.22.1-
  rust-1.99.0-nightly+0x825e3fa)                                              
     #5 llvm::coverage::CoverageMapping::loadFromFile(...) (libLLVM.so.22.1-  
  rust-1.99.0-nightly+0x825e8d1)                                              
     #6 llvm::coverage::CoverageMapping::load(...) (libLLVM.so.22.1-rust-1.99.
  0-nightly+0x825ee6d)                                                        
     #7 (anonymous namespace)::CodeCoverageTool::load() CodeCoverage.cpp:0:0  
     #8 (anonymous namespace)::CodeCoverageTool::run(...) CodeCoverage.cpp:0:0
     #9 showMain(int, char const**) (llvm-cov+0x19d4a)   

Notes:

  • Since it fails while loading the mapping every llvm-cov view fails for the whole binary. In a larger crate report, export and show without --show-mcdc flag all crashed
  • These work with the same toolchain: match arms with guards, a tuple match with a _ if v guard, (a && !b && …).then_some(x), || inside a closure, h && (4..=7).contains(&t)
  • With the previous implementation nightly-2025-07-15 and LLVM 20 the file doesn't crash but that version has no MC/DC decision at all only branch counters for !a and t
  • I guess emitted mapping breaks an invariant loadFunctionRecord relies on but I could not manage to check it

Question:
Until pattern matching in decisions is supported should such a chain be skipped as before or should the matches! count as one opaque condition? Zaeske et al. (Arxiv:2409.08708 in 5.1) treats a nested match as its own decision and its result as a single condition of the outer one.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-LLVM Area: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues. S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants