@@ -28,11 +28,11 @@ them), and generate various reports for analysis, for example:
2828<br />
2929
3030Detailed instructions and examples are documented in the
31- [ Rust Unstable Book (under _ source-based-code- coverage_ )] [ unstable-book-sbcc ] .
31+ [ Rust Unstable Book (under _ compiler-flags/instrument- coverage_ )] [ unstable-book-instrument-coverage ] .
3232
3333[ llvm-instrprof-increment ] : https://llvm.org/docs/LangRef.html#llvm-instrprof-increment-intrinsic
34- [ Coverage Map ] : https://llvm.org/docs/CoverageMappingFormat.html
35- [ unstable-book-sbcc ] : https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/source-based-code -coverage.html
34+ [ coverage map ] : https://llvm.org/docs/CoverageMappingFormat.html
35+ [ unstable-book-instrument-coverage ] : https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/instrument -coverage.html
3636
3737## Rust symbol mangling
3838
@@ -82,7 +82,7 @@ a span of code ([`CodeRegion`][code-region]). It counts the number of times a
8282branch is executed, and also specifies the exact location of that code span in
8383the Rust source code.
8484
85- Note that many of these ` Coverage ` statements will * not * be converted into
85+ Note that many of these ` Coverage ` statements will _ not _ be converted into
8686physical counters (or any other executable instructions) in the final binary.
8787Some of them will be (see ` CoverageKind:: ` [ ` Counter ` ] [ counter-coverage-kind ] ),
8888but other counters can be computed on the fly, when generating a coverage
@@ -111,7 +111,7 @@ fn some_func(flag: bool) {
111111In this example, four contiguous code regions are counted while only
112112incrementing two counters.
113113
114- CFG analysis is used to not only determine * where * the branches are, for
114+ CFG analysis is used to not only determine _ where _ the branches are, for
115115conditional expressions like ` if ` , ` else ` , ` match ` , and ` loop ` , but also to
116116determine where expressions can be used in place of physical counters.
117117
@@ -150,50 +150,53 @@ MIR `Statement` into some backend-specific action or instruction.
150150 match statement . kind {
151151 ...
152152 mir :: StatementKind :: Coverage (box ref coverage ) => {
153- self . codegen_coverage (& mut bx , coverage . clone ());
153+ self . codegen_coverage (& mut bx , coverage . clone (), statement . source_info . scope );
154154 bx
155155 }
156156```
157157
158-
159158` codegen_coverage() ` handles each ` CoverageKind ` as follows:
160159
161- * For all ` CoverageKind ` s, Coverage data (counter ID, expression equation
160+ - For all ` CoverageKind ` s, Coverage data (counter ID, expression equation
162161 and ID, and code regions) are passed to the backend's ` Builder ` , to
163162 populate data structures that will be used to generate the crate's
164163 "Coverage Map". (See the [ ` FunctionCoverage ` ] [ function-coverage ] ` struct ` .)
165- * For ` CoverageKind::Counter ` s, an instruction is injected in the backend
164+ - For ` CoverageKind::Counter ` s, an instruction is injected in the backend
166165 IR to increment the physical counter, by calling the ` BuilderMethod `
167166 [ ` instrprof_increment() ` ] [ instrprof-increment ] .
168167
169168``` rust
170- pub fn codegen_coverage (& self , bx : & mut Bx , coverage : Coverage ) {
169+ pub fn codegen_coverage (& self , bx : & mut Bx , coverage : Coverage , scope : SourceScope ) {
170+ ...
171+ let instance = ... // the scoped instance (current or inlined function)
171172 let Coverage { kind , code_region } = coverage ;
172173 match kind {
173174 CoverageKind :: Counter { function_source_hash , id } => {
174- if let Some (code_region ) = code_region {
175- bx . add_coverage_counter (self . instance, id , code_region );
176- }
175+ ...
176+ bx . add_coverage_counter (instance , id , code_region );
177177 ...
178178 bx . instrprof_increment (fn_name , hash , num_counters , index );
179179 }
180180 CoverageKind :: Expression { id , lhs , op , rhs } => {
181- bx . add_coverage_counter_expression (self . instance, id , lhs , op , rhs , code_region );
181+ bx . add_coverage_counter_expression (instance , id , lhs , op , rhs , code_region );
182182 }
183183 CoverageKind :: Unreachable => {
184- ...
184+ bx . add_coverage_unreachable (
185+ instance ,
186+ code_region . expect (...
185187```
186- _ code snippet trimmed for brevity_
188+
189+ _code snippet abbreviated for brevity_
187190
188191> The function name `instrprof_increment ()` is taken from the LLVM intrinsic
189- call of the same name ([ ` llvm.instrprof.increment ` ] [ llvm-instrprof-increment ] ),
190- and uses the same arguments and types; but note that, up to and through this
191- stage (even though modeled after LLVM's implementation for code coverage
192- instrumentation), the data and instructions are not strictly LLVM-specific.
192+ > call of the same name ([`llvm . instrprof. increment`][llvm - instrprof - increment ]),
193+ > and uses the same arguments and types ; but note that , up to and through this
194+ > stage (even though modeled after LLVM 's implementation for code coverage
195+ > instrumentation ), the data and instructions are not strictly LLVM - specific .
193196>
194197> But since LLVM is the only Rust - supported backend with the tooling to
195- process this form of coverage instrumentation, the backend for ` Coverage `
196- statements is only implemented for LLVM, at this time.
198+ > process this form of coverage instrumentation , the backend for `Coverage `
199+ > statements is only implemented for LLVM , at this time .
197200
198201[backend - lowering - mir ]: backend / lowering - mir . md
199202[codegen - statement ]: https : // doc.rust-lang.org/nightly/nightly-rustc/rustc_codegen_ssa/mir/struct.FunctionCx.html#method.codegen_statement
@@ -221,25 +224,28 @@ properly-configured variables in LLVM IR, according to very specific
221224details of the [_LLVM Coverage Mapping Format_ ][coverage - mapping - format ]
222225(Version 4 ). [^ llvm - and - covmap - versions ]
223226
224- [ ^ llvm-and-covmap-versions ] : The Rust compiler (as of <!-- date: 2021-01 -->
225- January 2021) supports _ LLVM Coverage Mapping Format _ Version 4 (the most
226- up-to-date version of the format, at the time of this writing) for improved
227- compatibility with other LLVM-based compilers (like _ Clang _ ), and to take
228- advantage of some format optimizations. Version 4 was introduced in _ LLVM 11 _ ,
229- which is currently the default LLVM version for Rust. Note that the Rust
230- compiler optionally supports some earlier LLVM versions, prior to _ LLVM 11 _ . If
231- ` rustc ` is configured to use an incompatible version of LLVM, compiling with `-Z
232- instrument-coverage` will generate an error message.
227+ [^ llvm - and - covmap - versions ]:
228+ The Rust compiler ( as of < ! -- date : 2021 - 01 - ->
229+ January 2021 ) supports _LLVM Coverage Mapping Format_ Version 4 ( the most
230+ up - to - date version of the format , at the time of this writing ) for improved
231+ compatibility with other LLVM - based compilers ( like _Clang_ ), and to take
232+ advantage of some format optimizations . Version 4 was introduced in _LLVM 11_ ,
233+ which is currently the default LLVM version for Rust . Note that the Rust
234+ compiler optionally supports some earlier LLVM versions , prior to _LLVM 11_ . If
235+ ` rustc ` is configured to use an incompatible version of LLVM , compiling with ` - Z instrument- coverage` will generate an error message.
233236
234237```rust
235238pub fn finalize<'ll, 'tcx>(cx: & CodegenCx <'ll , 'tcx >) {
239+ ...
240+ if ! tcx. sess. instrument_coverage_except_unused_functions() {
241+ add_unused_functions(cx);
242+ }
243+
236244 let mut function_coverage_map = match cx . coverage_context () {
237245 Some (ctx ) => ctx . take_function_coverage_map (),
238246 None => return ,
239247 };
240248 ...
241- add_unreachable_coverage (tcx , & mut function_coverage_map );
242-
243249 let mut mapgen = CoverageMapGenerator :: new ();
244250
245251 for (instance , function_coverage ) in function_coverage_map {
@@ -248,66 +254,61 @@ pub fn finalize<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) {
248254 mapgen . write_coverage_mapping (expressions , counter_regions , coverage_mapping_buffer );
249255 });
250256```
257+
251258_ code snippet trimmed for brevity_
252259
253- One notable step, performed by ` mapgen::finalize() ` before processing the
254- ` Instance ` s and their ` FunctionCoverage ` s, is the call to
255- [ ` add_unreachable_functions() ` ] [ add-unreachable-coverage ] .
260+ One notable first step performed by ` mapgen::finalize() ` is the call to
261+ [ ` add_unused_functions() ` ] [ add-unused-functions ] .
256262
257263When finalizing the coverage map, ` FunctionCoverage ` only has the ` CodeRegion ` s and counters for
258264the functions that went through codegen; such as public functions and "used" functions
259- (functions referenced by other "used" or public items). Any other functions (considered unused
260- or "Unreachable") were still parsed and processed through the MIR stage.
265+ (functions referenced by other "used" or public items). Any other functions (considered unused)
266+ were still parsed and processed through the MIR stage.
261267
262- The set of unreachable functions is computed via the set difference of all MIR
268+ The set of unused functions is computed via the set difference of all MIR
263269` DefId ` s (` tcx ` query ` mir_keys ` ) minus the codegenned ` DefId ` s
264- (` tcx ` query ` collect_and_partition_mono_items ` ). ` add_unreachable_functions() `
265- computes the set of unreachable functions, queries the ` tcx ` for the
266- previously-computed ` CodeRegions ` , for each unreachable MIR, and adds those code
267- regions to one of the non-generic codegenned functions (non-generic avoids
268- potentially injecting the unreachable coverage multiple times for multiple
269- instantiations).
270+ (` tcx ` query ` codegened_and_inlined_items ` ). ` add_unused_functions() `
271+ computes the set of unused functions, queries the ` tcx ` for the
272+ previously-computed ` CodeRegions ` , for each unused MIR, synthesizes an
273+ LLVM function (with no internal statements, since it will not be called),
274+ and adds a new ` FunctionCoverage ` , with ` Unreachable ` code regions.
270275
271276[ compile-codegen-unit ] : https://doc.rust-lang.org/nightly/nightly-rustc/rustc_codegen_llvm/base/fn.compile_codegen_unit.html
272277[ coverageinfo-finalize ] : https://doc.rust-lang.org/nightly/nightly-rustc/rustc_codegen_llvm/context/struct.CodegenCx.html#method.coverageinfo_finalize
273278[ mapgen-finalize ] : https://doc.rust-lang.org/nightly/nightly-rustc/rustc_codegen_llvm/coverageinfo/mapgen/fn.finalize.html
274279[ coverage-mapping-format ] : https://llvm.org/docs/CoverageMappingFormat.html
275- [ add-unreachable-coverage ] : https://doc.rust-lang.org/nightly/nightly-rustc/rustc_codegen_llvm/coverageinfo/mapgen/fn.add_unreachable_coverage .html
280+ [ add-unused-functions ] : https://doc.rust-lang.org/nightly/nightly-rustc/rustc_codegen_llvm/coverageinfo/mapgen/fn.add_unused_functions .html
276281
277282## Testing LLVM Coverage
278283
279284Coverage instrumentation in the MIR is validated by a ` mir-opt ` test:
280285[ ` instrument-coverage ` ] [ mir-opt-test ] .
281286
282287More complete testing of end-to-end coverage instrumentation and reports are done
283- in the ` run-make-fulldeps ` tests, with sample Rust programs (to be instrumented)
284- in the [ ` coverage ` ] [ coverage-test-samples ] directory, and the actual tests and expected
288+ in the ` run-make ` tests, with sample Rust programs (to be instrumented) in the
289+ [ ` coverage ` ] [ coverage-test-samples ] directory, and the actual tests and expected
285290results in [ ` coverage-reports ` ] .
286291
287- In addition to testing the final result, two intermediate results are also validated
288- to catch potential regression errors early: Minimum ` CoverageSpan ` s computed during
289- the ` InstrumentCoverage ` MIR pass are saved in ` mir_dump ` [ Spanview] [ spanview-debugging ]
290- files and compared to expected results in [ ` coverage-spanview ` ] .
291-
292292Finally, the [ ` coverage-llvmir ` ] test compares compiles a simple Rust program with
293293` -Z instrument-coverage ` and compares the compiled program's LLVM IR to expected
294294LLVM IR instructions and structured data for a coverage-enabled program, including
295295various checks for Coverage Map-related metadata and the LLVM intrinsic calls to
296296increment the runtime counters.
297297
298298Expected results for both the ` mir-opt ` tests and the ` coverage* ` tests under
299- ` run-make-fulldeps ` can be refreshed by running:
299+ ` run-make ` can be refreshed by running:
300300
301301``` shell
302- $ ./x.py test src/test/< test-type> --blessed
302+ $ ./x.py test mir-opt --blessed
303+ $ ./x.py test src/test/run-make/coverage --blessed
303304```
304305
305306[ 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
307+ [ coverage-test-samples ] : https://github.com/rust-lang/rust/tree/master/src/test/run-make/coverage
308+ [ `coverage-reports` ] : https://github.com/rust-lang/rust/tree/master/src/test/run-make/coverage-reports
309+ [ `coverage-spanview` ] : https://github.com/rust-lang/rust/tree/master/src/test/run-make/coverage-spanview
309310[ 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+ [ `coverage-llvmir` ] : https://github.com/rust-lang/rust/tree/master/src/test/run-make/coverage-llvmir
311312
312313## Implementation Details of the ` InstrumentCoverage ` MIR Pass
313314
@@ -352,11 +353,12 @@ with the following steps:
352353 - ` inject_intermediate_expression() ` , called for each intermediate expression
353354 returned from ` make_bcb_counters() `
354355
355- [ ^ intermediate-expressions ] : Intermediate expressions are sometimes required
356- because ` Expression ` s are limited to binary additions or subtractions. For
357- example, ` A + (B - C) ` might represent an ` Expression ` count computed from three
358- other counters, ` A ` , ` B ` , and ` C ` , but computing that value requires an
359- intermediate expression for ` B - C ` .
356+ [ ^ intermediate-expressions ] :
357+ Intermediate expressions are sometimes required
358+ because ` Expression ` s are limited to binary additions or subtractions. For
359+ example, ` A + (B - C) ` might represent an ` Expression ` count computed from three
360+ other counters, ` A ` , ` B ` , and ` C ` , but computing that value requires an
361+ intermediate expression for ` B - C ` .
360362
361363[ instrumentor ] : https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/transform/coverage/struct.Instrumentor.html
362364[ coverage-graph ] : https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/transform/coverage/graph/struct.CoverageGraph.html
@@ -396,20 +398,21 @@ contrast with the [`SimplifyCfg`][simplify-cfg] MIR pass, this step does
396398not alter the MIR itself, because the ` CoverageGraph ` aggressively simplifies
397399the CFG, and ignores nodes that are not relevant to coverage. For example:
398400
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 ` BasicBlock ` .
406- * Some BasicBlock terminators support Rust-specific concerns--like borrow-checking--that are
407- not relevant to coverage analysis. ` FalseUnwind ` , for example, can be treated the same as
408- a ` Goto ` (potentially merged with its successor into the same BCB).
409-
410- [ ^ 78544 ] : (Note, however, that Issue [ #78544 ] [ rust-lang/rust#78544 ] considers
411- providing future support for coverage of programs that intentionally
412- ` panic ` , as an option, with some non-trivial cost.)
401+ - The BCB CFG ignores (excludes) branches considered not relevant
402+ to the current coverage solution. It excludes unwind-related code[ ^ 78544 ]
403+ that is injected by the Rust compiler but has no physical source
404+ code to count, which allows a ` Call ` -terminated BasicBlock
405+ to be merged with its successor, within a single BCB.
406+ - A ` Goto ` -terminated ` BasicBlock ` can be merged with its successor
407+ ** _ as long as_ ** it has the only incoming edge to the successor ` BasicBlock ` .
408+ - Some BasicBlock terminators support Rust-specific concerns--like borrow-checking--that are
409+ not relevant to coverage analysis. ` FalseUnwind ` , for example, can be treated the same as
410+ a ` Goto ` (potentially merged with its successor into the same BCB).
411+
412+ [ ^ 78544 ] :
413+ (Note, however, that Issue [ #78544 ] [ rust-lang/rust#78544 ] considers
414+ providing future support for coverage of programs that intentionally
415+ ` panic ` , as an option, with some non-trivial cost.)
413416
414417The BCB CFG is critical to simplifying the coverage analysis by ensuring graph path-based
415418queries (` is_dominated_by() ` , ` predecessors ` , ` successors ` , etc.) have branch (control flow)
@@ -418,10 +421,11 @@ significance.
418421To visualize the ` CoverageGraph ` , you can generate a _ graphviz_ ` *.dot `
419422file with the following ` rustc ` flags:[ ^ graphviz-dark-mode ]
420423
421- [ ^ graphviz-dark-mode ] : This image also applies ` -Z graphviz-dark-mode ` , to
422- produce a Graphviz document with "dark mode" styling. If you use a dark mode or
423- theme in your development environment, you will probably want to use this
424- option so you can review the graphviz output without straining your vision.
424+ [ ^ graphviz-dark-mode ] :
425+ This image also applies ` -Z graphviz-dark-mode ` , to
426+ produce a Graphviz document with "dark mode" styling. If you use a dark mode or
427+ theme in your development environment, you will probably want to use this
428+ option so you can review the graphviz output without straining your vision.
425429
426430``` shell
427431$ rustc -Z instrument-coverage -Z dump-mir=InstrumentCoverage \
@@ -448,19 +452,19 @@ directional edges (the arrows) leading from each node to its `successors()`.
448452The nodes contain information in sections:
449453
4504541 . The gray header has a label showing the BCB ID (or _ index_ for looking up
451- its ` BasicCoverageBlockData ` ).
455+ its ` BasicCoverageBlockData ` ).
4524562 . The first content section shows the assigned ` Counter ` or ` Expression ` for
453- each contiguous section of code. (There may be more than one ` Expression `
454- incremented by the same ` Counter ` for discontiguous sections of code representing
455- the same sequential actions.) Note the code is represented by the line and
456- column ranges (for example: ` 52:28-52:33 ` , representing the original source
457- line 52, for columns 28-33). These are followed by the MIR ` Statement ` or
458- ` Terminator ` represented by that source range. (How these coverage regions
459- are determined is discussed in the following section.)
457+ each contiguous section of code. (There may be more than one ` Expression `
458+ incremented by the same ` Counter ` for discontiguous sections of code representing
459+ the same sequential actions.) Note the code is represented by the line and
460+ column ranges (for example: ` 52:28-52:33 ` , representing the original source
461+ line 52, for columns 28-33). These are followed by the MIR ` Statement ` or
462+ ` Terminator ` represented by that source range. (How these coverage regions
463+ are determined is discussed in the following section.)
4604643 . The final section(s) show the MIR ` BasicBlock ` s (by ID/index and its
461- ` TerminatorKind ` ) contained in this BCB. The last BCB is separated out because
462- its ` successors() ` determine the edges leading out of the BCB, and into
463- the ` leading_bb() ` (first ` BasicBlock ` ) of each successor BCB.
465+ ` TerminatorKind ` ) contained in this BCB. The last BCB is separated out because
466+ its ` successors() ` determine the edges leading out of the BCB, and into
467+ the ` leading_bb() ` (first ` BasicBlock ` ) of each successor BCB.
464468
465469Note, to find the ` BasicCoverageBlock ` from a final BCB ` Terminator ` 's
466470successor ` BasicBlock ` , there is an index and helper
@@ -572,7 +576,7 @@ incoming edges. Given the following graph, for example, the count for
572576
573577In this situation, BCB node ` B ` may require an edge counter for its
574578"edge from A", and that edge might be computed from an ` Expression ` ,
575- ` Counter(A) - Counter(C) ` . But an expression for the BCB _ node_ ` B `
579+ ` Counter(A) - Counter(C) ` . But an expression for the BCB _ node_ ` B `
576580would be the sum of all incoming edges:
577581
578582``` text
0 commit comments