1# LLVM Source-Based Code Coverage 2 3<!-- toc --> 4 5`rustc` supports detailed source-based code and test coverage analysis 6with a command line option (`-Z instrument-coverage`) that instruments Rust 7libraries and binaries with additional instructions and data, at compile time. 8 9The coverage instrumentation injects calls to the LLVM intrinsic instruction 10[`llvm.instrprof.increment`][llvm-instrprof-increment] at code branches 11(based on a MIR-based control flow analysis), and LLVM converts these to 12instructions that increment static counters, when executed. The LLVM coverage 13instrumentation also requires a [Coverage Map] that encodes source metadata, 14mapping counter IDs--directly and indirectly--to the file locations (with 15start and end line and column). 16 17Rust libraries, with or without coverage instrumentation, can be linked into 18instrumented binaries. When the program is executed and cleanly terminates, 19LLVM libraries write the final counter values to a file (`default.profraw` or 20a custom file set through environment variable `LLVM_PROFILE_FILE`). 21 22Developers use existing LLVM coverage analysis tools to decode `.profraw` 23files, with corresponding Coverage Maps (from matching binaries that produced 24them), and generate various reports for analysis, for example: 25 26<img alt="Screenshot of sample `llvm-cov show` result, for function add_quoted_string" 27 src="img/llvm-cov-show-01.png" class="center"/> 28<br/> 29 30Detailed instructions and examples are documented in the 31[Rust Unstable Book (under 32_compiler-flags/instrument-coverage_)][unstable-book-instrument-coverage]. 33 34[llvm-instrprof-increment]: https://llvm.org/docs/LangRef.html#llvm-instrprof-increment-intrinsic 35[coverage map]: https://llvm.org/docs/CoverageMappingFormat.html 36[unstable-book-instrument-coverage]: https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/instrument-coverage.html 37 38## Rust symbol mangling 39 40`-Z instrument-coverage` automatically enables Rust symbol mangling `v0` (as 41if the user specified `-Z symbol-mangling-version=v0` option when invoking 42`rustc`) to ensure consistent and reversible name mangling. This has two 43important benefits: 44 451. LLVM coverage tools can analyze coverage over multiple runs, including some 46 changes to source code; so mangled names must be consistent across compilations. 472. LLVM coverage reports can report coverage by function, and even separates 48 out the coverage counts of each unique instantiation of a generic function, 49 if invoked with multiple type substitution variations. 50 51## Components of LLVM Coverage Instrumentation in `rustc` 52 53### LLVM Runtime Dependency 54 55Coverage data is only generated by running the executable Rust program. `rustc` 56statically links coverage-instrumented binaries with LLVM runtime code 57([compiler-rt][compiler-rt-profile]) that implements program hooks 58(such as an `exit` hook) to write the counter values to the `.profraw` file. 59 60In the `rustc` source tree, `library/profiler_builtins` bundles the LLVM 61`compiler-rt` code into a Rust library crate. (When building `rustc`, the 62`profiler_builtins` library is only included when `profiler = true` is set 63in `rustc`'s `config.toml`.) 64 65When compiling with `-Z instrument-coverage`, 66[`CrateLoader::postprocess()`][crate-loader-postprocess] dynamically loads the 67`profiler_builtins` library by calling `inject_profiler_runtime()`. 68 69[compiler-rt-profile]: https://github.com/llvm/llvm-project/tree/main/compiler-rt/lib/profile 70[crate-loader-postprocess]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_metadata/creader/struct.CrateLoader.html#method.postprocess 71 72### MIR Pass: `InstrumentCoverage` 73 74Coverage instrumentation is performed on the MIR with a [MIR pass][mir-passes] 75called [`InstrumentCoverage`][mir-instrument-coverage]. This MIR pass analyzes 76the control flow graph (CFG)--represented by MIR `BasicBlock`s--to identify 77code branches, and injects additional [`Coverage`][coverage-statement] 78statements into the `BasicBlock`s. 79 80A MIR `Coverage` statement is a virtual instruction that indicates a counter 81should be incremented when its adjacent statements are executed, to count 82a span of code ([`CodeRegion`][code-region]). It counts the number of times a 83branch is executed, and also specifies the exact location of that code span in 84the Rust source code. 85 86Note that many of these `Coverage` statements will _not_ be converted into 87physical counters (or any other executable instructions) in the final binary. 88Some of them will be (see `CoverageKind::`[`Counter`][counter-coverage-kind]), 89but other counters can be computed on the fly, when generating a coverage 90report, by mapping a `CodeRegion` to a 91`CoverageKind`::[`Expression`][expression-coverage-kind]. 92 93As an example: 94 95```rust 96fn some_func(flag: bool) { 97 // increment Counter(1) 98 ... 99 if flag { 100 // increment Counter(2) 101 ... 102 } else { 103 // count = Expression(1) = Counter(1) - Counter(2) 104 ... 105 } 106 // count = Expression(2) = Counter(1) + Zero 107 // or, alternatively, Expression(2) = Counter(2) + Expression(1) 108 ... 109} 110``` 111 112In this example, four contiguous code regions are counted while only 113incrementing two counters. 114 115CFG analysis is used to not only determine _where_ the branches are, for 116conditional expressions like `if`, `else`, `match`, and `loop`, but also to 117determine where expressions can be used in place of physical counters. 118 119The advantages of optimizing coverage through expressions are more pronounced 120with loops. Loops generally include at least one conditional branch that 121determines when to break out of a loop (a `while` condition, or an `if` or 122`match` with a `break`). In MIR, this is typically lowered to a `SwitchInt`, 123with one branch to stay in the loop, and another branch to break out of the 124loop. The branch that breaks out will almost always execute less often, 125so `InstrumentCoverage` chooses to add a `Counter` to that branch, and an 126`Expression(continue) = Counter(loop) - Counter(break)` to the branch that 127continues. 128 129The `InstrumentCoverage` MIR pass is documented in 130[more detail below][instrument-coverage-pass-details]. 131 132[mir-passes]: mir/passes.md 133[mir-instrument-coverage]: https://github.com/rust-lang/rust/tree/master/compiler/rustc_mir_transform/src/coverage 134[code-region]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/mir/coverage/struct.CodeRegion.html 135[counter-coverage-kind]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/mir/coverage/enum.CoverageKind.html#variant.Counter 136[expression-coverage-kind]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/mir/coverage/enum.CoverageKind.html#variant.Expression 137[coverage-statement]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/mir/enum.StatementKind.html#variant.Coverage 138[instrument-coverage-pass-details]: #implementation-details-of-the-instrumentcoverage-mir-pass 139 140### Counter Injection and Coverage Map Pre-staging 141 142When the compiler enters [the Codegen phase][backend-lowering-mir], with a 143coverage-enabled MIR, [`codegen_statement()`][codegen-statement] converts each 144MIR `Statement` into some backend-specific action or instruction. 145`codegen_statement()` forwards `Coverage` statements to 146[`codegen_coverage()`][codegen-coverage]: 147 148```rust 149 pub fn codegen_statement(&mut self, mut bx: Bx, statement: &mir::Statement<'tcx>) -> Bx { 150 ... 151 match statement.kind { 152 ... 153 mir::StatementKind::Coverage(box ref coverage) => { 154 self.codegen_coverage(&mut bx, coverage.clone(), statement.source_info.scope); 155 bx 156 } 157``` 158 159`codegen_coverage()` handles each `CoverageKind` as follows: 160 161- For all `CoverageKind`s, Coverage data (counter ID, expression equation 162 and ID, and code regions) are passed to the backend's `Builder`, to 163 populate data structures that will be used to generate the crate's 164 "Coverage Map". (See the [`FunctionCoverage`][function-coverage] `struct`.) 165- For `CoverageKind::Counter`s, an instruction is injected in the backend 166 IR to increment the physical counter, by calling the `BuilderMethod` 167 [`instrprof_increment()`][instrprof-increment]. 168 169```rust 170 pub fn codegen_coverage(&self, bx: &mut Bx, coverage: Coverage, scope: SourceScope) { 171 ... 172 let instance = ... // the scoped instance (current or inlined function) 173 let Coverage { kind, code_region } = coverage; 174 match kind { 175 CoverageKind::Counter { function_source_hash, id } => { 176 ... 177 bx.add_coverage_counter(instance, id, code_region); 178 ... 179 bx.instrprof_increment(fn_name, hash, num_counters, index); 180 } 181 CoverageKind::Expression { id, lhs, op, rhs } => { 182 bx.add_coverage_counter_expression(instance, id, lhs, op, rhs, code_region); 183 } 184 CoverageKind::Unreachable => { 185 bx.add_coverage_unreachable( 186 instance, 187 code_region.expect(... 188``` 189 190> The function name `instrprof_increment()` is taken from the LLVM intrinsic 191call of the same name ([`llvm.instrprof.increment`][llvm-instrprof-increment]), 192and uses the same arguments and types; but note that, up to and through this 193stage (even though modeled after LLVM's implementation for code coverage 194instrumentation), the data and instructions are not strictly LLVM-specific. 195> 196> But since LLVM is the only Rust-supported backend with the tooling to 197process this form of coverage instrumentation, the backend for `Coverage` 198statements is only implemented for LLVM, at this time. 199 200[backend-lowering-mir]: backend/lowering-mir.md 201[codegen-statement]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_codegen_ssa/mir/struct.FunctionCx.html#method.codegen_statement 202[codegen-coverage]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_codegen_ssa/mir/struct.FunctionCx.html#method.codegen_coverage 203[function-coverage]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_codegen_ssa/coverageinfo/map/struct.FunctionCoverage.html 204[instrprof-increment]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_codegen_ssa/traits/trait.BuilderMethods.html#tymethod.instrprof_increment 205 206### Coverage Map Generation 207 208With the instructions to increment counters now implemented in LLVM IR, 209the last remaining step is to inject the LLVM IR variables that hold the 210static data for the coverage map. 211 212`rustc_codegen_llvm`'s [`compile_codegen_unit()`][compile-codegen-unit] calls 213[`coverageinfo_finalize()`][coverageinfo-finalize], 214which delegates its implementation to the 215[`rustc_codegen_llvm::coverageinfo::mapgen`][mapgen-finalize] module. 216 217For each function `Instance` (code-generated from MIR, including multiple 218instances of the same MIR for generic functions that have different type 219substitution combinations), `mapgen`'s `finalize()` method queries the 220`Instance`-associated `FunctionCoverage` for its `Counter`s, `Expression`s, 221and `CodeRegion`s; and calls LLVM codegen APIs to generate 222properly-configured variables in LLVM IR, according to very specific 223details of the [_LLVM Coverage Mapping Format_][coverage-mapping-format] 224(Version 4).[^llvm-and-covmap-versions] 225 226[^llvm-and-covmap-versions]: The Rust compiler (as of 227January 2021) supports _LLVM Coverage Mapping Format_ Version 4 (the most 228up-to-date version of the format, at the time of this writing) for improved 229compatibility with other LLVM-based compilers (like _Clang_), and to take 230advantage of some format optimizations. Version 4 was introduced in _LLVM 11_, 231which is currently the default LLVM version for Rust. Note that the Rust 232compiler optionally supports some earlier LLVM versions, prior to _LLVM 11_. If 233`rustc` is configured to use an incompatible version of LLVM, compiling with `-Z 234instrument-coverage` will generate an error message. 235 236```rust 237pub fn finalize<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) { 238 ... 239 if !tcx.sess.instrument_coverage_except_unused_functions() { 240 add_unused_functions(cx); 241 } 242 243 let mut function_coverage_map = match cx.coverage_context() { 244 Some(ctx) => ctx.take_function_coverage_map(), 245 None => return, 246 }; 247 ... 248 let mut mapgen = CoverageMapGenerator::new(); 249 250 for (instance, function_coverage) in function_coverage_map { 251 ... 252 let coverage_mapping_buffer = llvm::build_byte_buffer(|coverage_mapping_buffer| { 253 mapgen.write_coverage_mapping(expressions, counter_regions, coverage_mapping_buffer); 254 }); 255``` 256_code snippet trimmed for brevity_ 257 258One notable first step performed by `mapgen::finalize()` is the call to 259[`add_unused_functions()`][add-unused-functions]: 260 261When finalizing the coverage map, `FunctionCoverage` only has the `CodeRegion`s 262and counters for the functions that went through codegen; such as public 263functions and "used" functions (functions referenced by other "used" or public 264items). Any other functions (considered unused) were still parsed and processed 265through the MIR stage. 266 267The set of unused functions is computed via the set difference of all MIR 268`DefId`s (`tcx` query `mir_keys`) minus the codegenned `DefId`s (`tcx` query 269`codegened_and_inlined_items`). `add_unused_functions()` computes the set of 270unused functions, queries the `tcx` for the previously-computed `CodeRegions`, 271for each unused MIR, synthesizes an LLVM function (with no internal statements, 272since it will not be called), and adds a new `FunctionCoverage`, with 273`Unreachable` code regions. 274 275[compile-codegen-unit]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_codegen_llvm/base/fn.compile_codegen_unit.html 276[coverageinfo-finalize]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_codegen_llvm/context/struct.CodegenCx.html#method.coverageinfo_finalize 277[mapgen-finalize]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_codegen_llvm/coverageinfo/mapgen/fn.finalize.html 278[coverage-mapping-format]: https://llvm.org/docs/CoverageMappingFormat.html 279[add-unused-functions]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_codegen_llvm/coverageinfo/mapgen/fn.add_unused_functions.html 280 281## Testing LLVM Coverage 282 283Coverage instrumentation in the MIR is validated by a `mir-opt` test: 284[`instrument-coverage`][mir-opt-test]. 285 286More complete testing of end-to-end coverage instrumentation and reports are 287done in the `run-make-fulldeps` tests, with sample Rust programs (to be 288instrumented) in the [`coverage`][coverage-test-samples] directory, and the 289actual tests and expected results in [`coverage-reports`]. 290 291Finally, the [`coverage-llvmir`] test compares compiles a simple Rust program 292with `-Z instrument-coverage` and compares the compiled program's LLVM IR to 293expected LLVM IR instructions and structured data for a coverage-enabled 294program, including various checks for Coverage Map-related metadata and the LLVM 295intrinsic calls to increment the runtime counters. 296 297Expected results for both the `mir-opt` tests and the `coverage*` tests under 298`run-make-fulldeps` can be refreshed by running: 299 300```shell 301$ ./x.py test mir-opt --bless 302$ ./x.py test src/test/run-make-fulldeps/coverage --bless 303``` 304 305[mir-opt-test]: https://github.com/rust-lang/rust/blob/master/src/test/mir-opt/instrument_coverage.rs 306[coverage-test-samples]: https://github.com/rust-lang/rust/tree/master/src/test/run-make-fulldeps/coverage 307[`coverage-reports`]: https://github.com/rust-lang/rust/tree/master/src/test/run-make-fulldeps/coverage-reports 308[`coverage-spanview`]: https://github.com/rust-lang/rust/tree/master/src/test/run-make-fulldeps/coverage-spanview 309[spanview-debugging]: compiler-debugging.md#viewing-spanview-output 310[`coverage-llvmir`]: https://github.com/rust-lang/rust/tree/master/src/test/run-make-fulldeps/coverage-llvmir 311 312## Implementation Details of the `InstrumentCoverage` MIR Pass 313 314The bulk of the implementation of the `InstrumentCoverage` MIR pass is performed 315by the [`Instrumentor`][instrumentor]. For each MIR (each non-const, non-inlined 316function, generic, or closure), the `Instrumentor`'s constructor prepares a 317[`CoverageGraph`][coverage-graph] and then executes 318[`inject_counters()`][inject-counters]. 319 320```rust 321 Instrumentor::new(&self.name(), tcx, mir_body).inject_counters(); 322``` 323 324The `CoverageGraph` is a coverage-specific simplification of the MIR control 325flow graph (CFG). Its nodes are [`BasicCoverageBlock`s][bcb], which 326encompass one or more sequentially-executed MIR `BasicBlock`s 327(with no internal branching), plus a `CoverageKind` counter (to 328be added, via coverage analysis), and an optional set of additional counters 329to count incoming edges (if there are more than one). 330 331The `Instrumentor`'s `inject_counters()` uses the `CoverageGraph` to 332compute the best places to inject coverage counters, as MIR `Statement`s, 333with the following steps: 334 3351. Depending on the debugging configurations in `rustc`'s, `config.toml`, 336 and `rustc` command line flags, various debugging features may be enabled 337 to enhance `debug!()` messages in logs, and to generate various "dump" files, 338 to help developers understand the MIR transformation process for coverage. 339 Most of the debugging features are implemented in the [`debug`][debug] 340 sub-module. 3412. [`generate_coverage_spans()`][generate-coverage-spans] computes the minimum set of distinct, 342 non-branching code regions, from the MIR. These `CoverageSpan`s 343 represent a span of code that must be counted. 3443. [`make_bcb_counters()`][make-bcb-counters] generates `CoverageKind::Counter`s and 345 `CoverageKind::Expression`s for each `CoverageSpan`, plus additional 346 `intermediate_expressions`[^intermediate-expressions], not associated with any `CodeRegion`, but 347 are required to compute a final `Expression` value for a `CodeRegion`. 3484. Inject the new counters into the MIR, as new `StatementKind::Coverage` 349 statements. This is done by three distinct functions: 350 - `inject_coverage_span_counters()` 351 - `inject_indirect_counters()` 352 - `inject_intermediate_expression()`, called for each intermediate expression 353 returned from `make_bcb_counters()` 354 355[^intermediate-expressions]: Intermediate expressions are sometimes required 356because `Expression`s are limited to binary additions or subtractions. For 357example, `A + (B - C)` might represent an `Expression` count computed from three 358other counters, `A`, `B`, and `C`, but computing that value requires an 359intermediate expression for `B - C`. 360 361[instrumentor]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_transform/coverage/struct.Instrumentor.html 362[coverage-graph]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_transform/coverage/graph/struct.CoverageGraph.html 363[inject-counters]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_transform/coverage/struct.Instrumentor.html#method.inject_counters 364[bcb]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_transform/coverage/graph/struct.BasicCoverageBlock.html 365[debug]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_transform/coverage/debug 366[generate-coverage-spans]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_transform/coverage/spans/struct.CoverageSpans.html#method.generate_coverage_spans 367[make-bcb-counters]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_transform/coverage/counters/struct.BcbCounters.html#method.make_bcb_counters 368 369### The `CoverageGraph` 370 371The [`CoverageGraph`][coverage-graph] is derived from the MIR (`mir::Body`). 372 373```rust 374 let basic_coverage_blocks = CoverageGraph::from_mir(mir_body); 375``` 376 377Like `mir::Body`, the `CoverageGraph` is also a 378[`DirectedGraph`][directed-graph]. Both graphs represent the function's 379fundamental control flow, with many of the same 380[`graph trait`][graph-traits]s, supporting `start_node()`, `num_nodes()`, 381`successors()`, `predecessors()`, and `is_dominated_by()`. 382 383For anyone that knows how to work with the [MIR, as a CFG][mir-dev-guide], the 384`CoverageGraph` will be familiar, and can be used in much the same way. 385The nodes of the `CoverageGraph` are `BasicCoverageBlock`s (BCBs), which 386index into an `IndexVec` of `BasicCoverageBlockData`. This is analogous 387to the MIR CFG of `BasicBlock`s that index `BasicBlockData`. 388 389Each `BasicCoverageBlockData` captures one or more MIR `BasicBlock`s, 390exclusively, and represents the maximal-length sequence of `BasicBlocks` 391without conditional branches. 392 393[`compute_basic_coverage_blocks()`][compute-basic-coverage-blocks] builds the 394`CoverageGraph` as a coverage-specific simplification of the MIR CFG. In 395contrast with the [`SimplifyCfg`][simplify-cfg] MIR pass, this step does 396not alter the MIR itself, because the `CoverageGraph` aggressively simplifies 397the CFG, and ignores nodes that are not relevant to coverage. For example: 398 399 - The BCB CFG ignores (excludes) branches considered not relevant 400 to the current coverage solution. It excludes unwind-related code[^78544] 401 that is injected by the Rust compiler but has no physical source 402 code to count, which allows a `Call`-terminated BasicBlock 403 to be merged with its successor, within a single BCB. 404 - A `Goto`-terminated `BasicBlock` can be merged with its successor 405 **_as long as_** it has the only incoming edge to the successor 406 `BasicBlock`. 407 - Some BasicBlock terminators support Rust-specific concerns--like 408 borrow-checking--that are not relevant to coverage analysis. `FalseUnwind`, 409 for example, can be treated the same as a `Goto` (potentially merged with 410 its successor into the same BCB). 411 412[^78544]: (Note, however, that Issue [#78544][rust-lang/rust#78544] considers 413providing future support for coverage of programs that intentionally 414`panic`, as an option, with some non-trivial cost.) 415 416The BCB CFG is critical to simplifying the coverage analysis by ensuring graph path-based 417queries (`is_dominated_by()`, `predecessors`, `successors`, etc.) have branch (control flow) 418significance. 419 420To visualize the `CoverageGraph`, you can generate a _graphviz_ `*.dot` 421file with the following `rustc` flags:[^graphviz-dark-mode] 422 423[^graphviz-dark-mode]: This image also applies `-Z graphviz-dark-mode`, to 424produce a Graphviz document with "dark mode" styling. If you use a dark mode or 425theme in your development environment, you will probably want to use this 426option so you can review the graphviz output without straining your vision. 427 428```shell 429$ rustc -Z instrument-coverage -Z dump-mir=InstrumentCoverage \ 430 -Z dump-mir-graphviz some_rust_source.rs 431``` 432 433The `-Z dump-mir` flag requests [MIR debugging 434output][mir-debugging] (generating `*.mir` files, by default). 435`-Z dump-mir-graphviz` additionally generates `*.dot` files. 436`-Z dump-mir=InstrumentCoverage` restricts these files to the 437`InstrumentCoverage` pass. All files are written to the `./mir_dump/` 438directory, by default. 439 440Files with names ending in `.-------.InstrumentCoverage.0.dot` contain the 441_graphviz_ representations of a `CoverageGraph` (one for each MIR, that is, 442for each function and closure): 443 444<img alt="cropped image of a sample CoverageGraph in graphviz format" 445 src="img/coverage-graphviz-01.png" style="border: 1px solid gray" class="center"/> 446<br/> 447 448This image shows each `BasicCoverageBlock` as a rectangular _node_, with 449directional edges (the arrows) leading from each node to its `successors()`. 450The nodes contain information in sections: 451 4521. The gray header has a label showing the BCB ID (or _index_ for looking up 453 its `BasicCoverageBlockData`). 4542. The first content section shows the assigned `Counter` or `Expression` for 455 each contiguous section of code. (There may be more than one `Expression` 456 incremented by the same `Counter` for noncontiguous sections of code 457 representing the same sequential actions.) Note the code is represented by 458 the line and column ranges (for example: `52:28-52:33`, representing the 459 original source line 52, for columns 28-33). These are followed by the MIR 460 `Statement` or `Terminator` represented by that source range. (How these 461 coverage regions are determined is discussed in the following section.) 4623. The final section(s) show the MIR `BasicBlock`s (by ID/index and its 463 `TerminatorKind`) contained in this BCB. The last BCB is separated out 464 because its `successors()` determine the edges leading out of the BCB, and 465 into the `leading_bb()` (first `BasicBlock`) of each successor BCB. 466 467Note, to find the `BasicCoverageBlock` from a final BCB `Terminator`'s 468successor `BasicBlock`, there is an index and helper 469function--[`bcb_from_bb()`][bcb-from-bb]--to look up a `BasicCoverageBlock` from 470*any* contained `BasicBlock`. 471 472[directed-graph]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_data_structures/graph/trait.DirectedGraph.html 473[graph-traits]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_data_structures/graph/index.html#traits 474[mir-dev-guide]: mir/index.md 475[compute-basic-coverage-blocks]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_transform/coverage/graph/struct.CoverageGraph.html#method.compute_basic_coverage_blocks 476[simplify-cfg]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_transform/simplify/struct.SimplifyCfg.html 477[rust-lang/rust#78544]: https://github.com/rust-lang/rust/issues/78544 478[mir-debugging]: mir/debugging.md 479[bcb-from-bb]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_transform/coverage/graph/struct.CoverageGraph.html#method.bcb_from_bb 480 481### `CoverageSpans` 482 483The `struct` [`CoverageSpans`][coverage-spans] builds and refines a final set of 484[`CoverageSpan`][coverage-span]s, each representing the largest contiguous `Span` 485of source within a single BCB. By definition--since each `Span` falls within a 486BCB, the `Span` is also non-branching; so if any code in that `Span` has executed, 487all code in the `Span` will have executed, the same number of times. 488 489[`CoverageSpans::generate_coverage_spans()`][generate-coverage-spans] constructs 490an initial set of `CoverageSpan`s from the `Span`s associated with each MIR 491`Statement` and `Terminator`. 492 493The final stage of `generate_coverage_spans()` is handled by 494[`to_refined_spans()`][to-refined-spans], which iterates through the `CoverageSpan`s, 495merges and de-duplicates them, and returns an optimal, minimal set of `CoverageSpan`s 496that can be used to assign coverage `Counter`s or `Expression`s, one-for-one. 497 498An visual, interactive representation of the final `CoverageSpan`s can be 499generated with the following `rustc` flags: 500 501```shell 502$ rustc -Z instrument-coverage -Z dump-mir=InstrumentCoverage \ 503 -Z dump-mir-spanview some_rust_source.rs 504``` 505 506These flags request Spanview output for the `InstrumentCoverage` pass, and the 507resulting files (one for each MIR, that is, for each function or closure) can be 508found in the `mir_dump` directory (by default), with the extension: 509`.-------.InstrumentCoverage.0.html`. 510 511<img alt="cropped image of a sample Spanview in a browser" 512 src="img/coverage-spanview-01.png" style="border: 1px solid gray" class="center"/> 513<br/> 514 515The image above shows one such example. The orange and blue backgrounds 516highlight alternating `CoverageSpan`s from the refined set. Hovering over a 517line expands the output on that line to show the MIR `BasicBlock` IDs covered 518by each `CoverageSpan`. While hovering, the `CoverageSpan` under the pointer 519also has a _tooltip_ block of text, showing even more detail, including the 520MIR `Statement`s and `Terminator`s contributing to the `CoverageSpan`, and 521their individual `Span`s (which should be encapsulated within the code region 522of the refined `CoverageSpan`) 523 524[coverage-spans]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_transform/coverage/spans/struct.CoverageSpans.html 525[coverage-span]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_transform/coverage/spans/struct.CoverageSpan.html 526[to-refined-spans]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_transform/coverage/spans/struct.CoverageSpans.html#method.to_refined_spans 527 528### `make_bcb_counters()` 529 530[`make_bcb_counters()`][make-bcb-counters] traverses the `CoverageGraph` and adds a 531`Counter` or `Expression` to every BCB. It uses _Control Flow Analysis_ 532to determine where an `Expression` can be used in place of a `Counter`. 533`Expressions` have no runtime overhead, so if a viable expression (adding or 534subtracting two other counters or expressions) can compute the same result as 535an embedded counter, an `Expression` is preferred. 536 537[`TraverseCoverageGraphWithLoops`][traverse-coverage-graph-with-loops] 538provides a traversal order that ensures all `BasicCoverageBlock` nodes in a 539loop are visited before visiting any node outside that loop. The traversal 540state includes a `context_stack`, with the current loop's context information 541(if in a loop), as well as context for nested loops. 542 543Within loops, nodes with multiple outgoing edges (generally speaking, these 544are BCBs terminated in a `SwitchInt`) can be optimized when at least one 545branch exits the loop and at least one branch stays within the loop. (For an 546`if` or `while`, there are only two branches, but a `match` may have more.) 547 548A branch that does not exit the loop should be counted by `Expression`, if 549possible. Note that some situations require assigning counters to BCBs before 550they are visited by traversal, so the `counter_kind` (`CoverageKind` for 551a `Counter` or `Expression`) may have already been assigned, in which case 552one of the other branches should get the `Expression`. 553 554For a node with more than two branches (such as for more than two 555`match` patterns), only one branch can be optimized by `Expression`. All 556others require a `Counter` (unless its BCB `counter_kind` was previously 557assigned). 558 559A branch expression is derived from the equation: 560 561```text 562Counter(branching_node) = SUM(Counter(branches)) 563``` 564 565It's important to 566be aware that the `branches` in this equation are the outgoing _edges_ 567from the `branching_node`, but a `branch`'s target node may have other 568incoming edges. Given the following graph, for example, the count for 569`B` is the sum of its two incoming edges: 570 571<img alt="Example graph with multiple incoming edges to a branch node" 572 src="img/coverage-branch-counting-01.png" class="center" style="width: 25%"> 573<br/> 574 575In this situation, BCB node `B` may require an edge counter for its 576"edge from A", and that edge might be computed from an `Expression`, 577`Counter(A) - Counter(C)`. But an expression for the BCB _node_ `B` 578would be the sum of all incoming edges: 579 580```text 581Expression((Counter(A) - Counter(C)) + SUM(Counter(remaining_edges))) 582``` 583 584Note that this is only one possible configuration. The actual choice 585of `Counter` vs. `Expression` also depends on the order of counter 586assignments, and whether a BCB or incoming edge counter already has 587its `Counter` or `Expression`. 588 589[bcb-counters]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_transform/coverage/counters/struct.BcbCounters.html 590[traverse-coverage-graph-with-loops]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_transform/coverage/graph/struct.TraverseCoverageGraphWithLoops.html 591 592### Injecting counters into a MIR `BasicBlock` 593 594With the refined `CoverageSpan`s, and after all `Counter`s and `Expression`s are 595created, the final step is to inject the `StatementKind::Coverage` statements 596into the MIR. There are three distinct sources, handled by the following 597functions: 598 599- [`inject_coverage_span_counters()`][inject-coverage-span-counters] injects the 600 counter from each `CoverageSpan`'s BCB. 601- [`inject_indirect_counters()`][inject-indirect-counters] injects counters 602 for any BCB not assigned to a `CoverageSpan`, and for all edge counters. 603 These counters don't have `CoverageSpan`s. 604- [`inject_intermediate_expression()`][inject-intermediate-expression] injects 605 the intermediate expressions returned from `make_bcb_counters()`. These 606 counters aren't associated with any BCB, edge, or `CoverageSpan`. 607 608These three functions inject the `Coverage` statements into the MIR. 609`Counter`s and `Expression`s with `CoverageSpan`s add `Coverage` statements 610to a corresponding `BasicBlock`, with a `CodeRegion` computed from the 611refined `Span` and current `SourceMap`. 612 613All other `Coverage` statements have a `CodeRegion` of `None`, but they 614still must be injected because they contribute to other `Expression`s. 615 616Finally, edge's with a `CoverageKind::Counter` require a new `BasicBlock`, 617so the counter is only incremented when traversing the branch edge. 618 619[inject-coverage-span-counters]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_transform/coverage/struct.Instrumentor.html#method.inject_coverage_span_counters 620[inject-indirect-counters]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_transform/coverage/struct.Instrumentor.html#method.inject_indirect_counters 621[inject-intermediate-expression]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_transform/coverage/fn.inject_intermediate_expression.html 622 623### Additional Debugging Support 624 625See the 626[crate documentation for `rustc_mir::transform::coverage::debug`][coverage-debugging] 627for a detailed description of the debug output, logging, and configuration options 628available to developers working on the `InstrumentCoverage` pass. 629 630[coverage-debugging]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_transform/coverage/debug/index.html 631