@@ -28,11 +28,12 @@ them), and generate various reports for analysis, for example:
28
28
<br />
29
29
30
30
Detailed instructions and examples are documented in the
31
- [ Rust Unstable Book (under _ source-based-code-coverage_ )] [ unstable-book-sbcc ] .
31
+ [ Rust Unstable Book (under
32
+ _ compiler-flags/instrument-coverage_ )] [ unstable-book-instrument-coverage ] .
32
33
33
34
[ 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
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
36
37
37
38
## Rust symbol mangling
38
39
@@ -82,7 +83,7 @@ a span of code ([`CodeRegion`][code-region]). It counts the number of times a
82
83
branch is executed, and also specifies the exact location of that code span in
83
84
the Rust source code.
84
85
85
- Note that many of these ` Coverage ` statements will * not * be converted into
86
+ Note that many of these ` Coverage ` statements will _ not _ be converted into
86
87
physical counters (or any other executable instructions) in the final binary.
87
88
Some of them will be (see ` CoverageKind:: ` [ ` Counter ` ] [ counter-coverage-kind ] ),
88
89
but other counters can be computed on the fly, when generating a coverage
@@ -111,7 +112,7 @@ fn some_func(flag: bool) {
111
112
In this example, four contiguous code regions are counted while only
112
113
incrementing two counters.
113
114
114
- CFG analysis is used to not only determine * where * the branches are, for
115
+ CFG analysis is used to not only determine _ where _ the branches are, for
115
116
conditional expressions like ` if ` , ` else ` , ` match ` , and ` loop ` , but also to
116
117
determine where expressions can be used in place of physical counters.
117
118
@@ -150,40 +151,42 @@ MIR `Statement` into some backend-specific action or instruction.
150
151
match statement . kind {
151
152
...
152
153
mir :: StatementKind :: Coverage (box ref coverage ) => {
153
- self . codegen_coverage (& mut bx , coverage . clone ());
154
+ self . codegen_coverage (& mut bx , coverage . clone (), statement . source_info . scope );
154
155
bx
155
156
}
156
157
```
157
158
158
-
159
159
` codegen_coverage() ` handles each ` CoverageKind ` as follows:
160
160
161
- * For all ` CoverageKind ` s, Coverage data (counter ID, expression equation
161
+ - For all ` CoverageKind ` s, Coverage data (counter ID, expression equation
162
162
and ID, and code regions) are passed to the backend's ` Builder ` , to
163
163
populate data structures that will be used to generate the crate's
164
164
"Coverage Map". (See the [ ` FunctionCoverage ` ] [ function-coverage ] ` struct ` .)
165
- * For ` CoverageKind::Counter ` s, an instruction is injected in the backend
165
+ - For ` CoverageKind::Counter ` s, an instruction is injected in the backend
166
166
IR to increment the physical counter, by calling the ` BuilderMethod `
167
167
[ ` instrprof_increment() ` ] [ instrprof-increment ] .
168
168
169
169
``` rust
170
- pub fn codegen_coverage (& self , bx : & mut Bx , coverage : Coverage ) {
170
+ pub fn codegen_coverage (& self , bx : & mut Bx , coverage : Coverage , scope : SourceScope ) {
171
+ ...
172
+ let instance = ... // the scoped instance (current or inlined function)
171
173
let Coverage { kind , code_region } = coverage ;
172
174
match kind {
173
175
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
- }
176
+ ...
177
+ bx . add_coverage_counter (instance , id , code_region );
177
178
...
178
179
bx . instrprof_increment (fn_name , hash , num_counters , index );
179
180
}
180
181
CoverageKind :: Expression { id , lhs , op , rhs } => {
181
- bx . add_coverage_counter_expression (self . instance, id , lhs , op , rhs , code_region );
182
+ bx . add_coverage_counter_expression (instance , id , lhs , op , rhs , code_region );
182
183
}
183
184
CoverageKind :: Unreachable => {
184
- ...
185
+ bx . add_coverage_unreachable (
186
+ instance ,
187
+ code_region . expect (...
185
188
```
186
- _ code snippet trimmed for brevity_
189
+ _code snippet abbreviated for brevity_
187
190
188
191
> The function name `instrprof_increment ()` is taken from the LLVM intrinsic
189
192
call of the same name ([`llvm . instrprof. increment`][llvm - instrprof - increment ]),
@@ -221,7 +224,7 @@ properly-configured variables in LLVM IR, according to very specific
221
224
details of the [_LLVM Coverage Mapping Format_ ][coverage - mapping - format ]
222
225
(Version 4 ). [^ llvm - and - covmap - versions ]
223
226
224
- [ ^ llvm-and-covmap-versions ] : The Rust compiler (as of <!-- date: 2021-01 -->
227
+ [^ llvm - and - covmap - versions ]: The Rust compiler (as of
225
228
January 2021 ) supports _LLVM Coverage Mapping Format_ Version 4 (the most
226
229
up - to - date version of the format , at the time of this writing ) for improved
227
230
compatibility with other LLVM - based compilers (like _Clang_ ), and to take
@@ -233,13 +236,16 @@ instrument-coverage` will generate an error message.
233
236
234
237
```rust
235
238
pub 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
+
236
244
let mut function_coverage_map = match cx . coverage_context () {
237
245
Some (ctx ) => ctx . take_function_coverage_map (),
238
246
None => return ,
239
247
};
240
248
...
241
- add_unreachable_coverage (tcx , & mut function_coverage_map );
242
-
243
249
let mut mapgen = CoverageMapGenerator :: new ();
244
250
245
251
for (instance , function_coverage ) in function_coverage_map {
@@ -250,64 +256,59 @@ pub fn finalize<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) {
250
256
```
251
257
_ code snippet trimmed for brevity_
252
258
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 ] .
259
+ One notable first step performed by ` mapgen::finalize() ` is the call to
260
+ [ ` add_unused_functions() ` ] [ add-unused-functions ] :
256
261
257
- When finalizing the coverage map, ` FunctionCoverage ` only has the ` CodeRegion ` s and counters for
258
- the 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.
262
+ When finalizing the coverage map, ` FunctionCoverage ` only has the ` CodeRegion ` s
263
+ and counters for the functions that went through codegen; such as public
264
+ functions and "used" functions (functions referenced by other "used" or public
265
+ items). Any other functions (considered unused) were still parsed and processed
266
+ through the MIR stage.
261
267
262
- The set of unreachable functions is computed via the set difference of all MIR
263
- ` 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).
268
+ The set of unused functions is computed via the set difference of all MIR
269
+ ` DefId ` s (` tcx ` query ` mir_keys ` ) minus the codegenned ` DefId ` s (` tcx ` query
270
+ ` codegened_and_inlined_items ` ). ` add_unused_functions() ` computes the set of
271
+ unused functions, queries the ` tcx ` for the previously-computed ` CodeRegions ` ,
272
+ for each unused MIR, synthesizes an LLVM function (with no internal statements,
273
+ since it will not be called), and adds a new ` FunctionCoverage ` , with
274
+ ` Unreachable ` code regions.
270
275
271
276
[ compile-codegen-unit ] : https://doc.rust-lang.org/nightly/nightly-rustc/rustc_codegen_llvm/base/fn.compile_codegen_unit.html
272
277
[ coverageinfo-finalize ] : https://doc.rust-lang.org/nightly/nightly-rustc/rustc_codegen_llvm/context/struct.CodegenCx.html#method.coverageinfo_finalize
273
278
[ mapgen-finalize ] : https://doc.rust-lang.org/nightly/nightly-rustc/rustc_codegen_llvm/coverageinfo/mapgen/fn.finalize.html
274
279
[ 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
276
281
277
282
## Testing LLVM Coverage
278
283
279
284
Coverage instrumentation in the MIR is validated by a ` mir-opt ` test:
280
285
[ ` instrument-coverage ` ] [ mir-opt-test ] .
281
286
282
- More 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
285
- results in [ ` coverage-reports ` ] .
286
-
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 ` ] .
287
+ More complete testing of end-to-end coverage instrumentation and reports are
288
+ done in the ` run-make ` tests, with sample Rust programs (to be instrumented) in
289
+ the [ ` coverage ` ] [ coverage-test-samples ] directory, and the actual tests and
290
+ expected results in [ ` coverage-reports ` ] .
291
291
292
- Finally, the [ ` coverage-llvmir ` ] test compares compiles a simple Rust program with
293
- ` -Z instrument-coverage ` and compares the compiled program's LLVM IR to expected
294
- LLVM IR instructions and structured data for a coverage-enabled program, including
295
- various checks for Coverage Map-related metadata and the LLVM intrinsic calls to
296
- increment the runtime counters.
292
+ Finally, the [ ` coverage-llvmir ` ] test compares compiles a simple Rust program
293
+ with ` -Z instrument-coverage ` and compares the compiled program's LLVM IR to
294
+ expected LLVM IR instructions and structured data for a coverage-enabled
295
+ program, including various checks for Coverage Map-related metadata and the LLVM
296
+ intrinsic calls to increment the runtime counters.
297
297
298
298
Expected 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:
300
300
301
301
``` 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
303
304
```
304
305
305
306
[ 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
309
310
[ 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
311
312
312
313
## Implementation Details of the ` InstrumentCoverage ` MIR Pass
313
314
@@ -396,16 +397,18 @@ contrast with the [`SimplifyCfg`][simplify-cfg] MIR pass, this step does
396
397
not alter the MIR itself, because the ` CoverageGraph ` aggressively simplifies
397
398
the CFG, and ignores nodes that are not relevant to coverage. For example:
398
399
399
- * The BCB CFG ignores (excludes) branches considered not relevant
400
+ - The BCB CFG ignores (excludes) branches considered not relevant
400
401
to the current coverage solution. It excludes unwind-related code[ ^ 78544 ]
401
402
that is injected by the Rust compiler but has no physical source
402
403
code to count, which allows a ` Call ` -terminated BasicBlock
403
404
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).
405
+ - A ` Goto ` -terminated ` BasicBlock ` can be merged with its successor
406
+ ** _ as long as_ ** it has the only incoming edge to the successor
407
+ ` BasicBlock ` .
408
+ - Some BasicBlock terminators support Rust-specific concerns--like
409
+ borrow-checking--that are not relevant to coverage analysis. ` FalseUnwind ` ,
410
+ for example, can be treated the same as a ` Goto ` (potentially merged with
411
+ its successor into the same BCB).
409
412
410
413
[ ^ 78544 ] : (Note, however, that Issue [ #78544 ] [ rust-lang/rust#78544 ] considers
411
414
providing future support for coverage of programs that intentionally
@@ -448,24 +451,24 @@ directional edges (the arrows) leading from each node to its `successors()`.
448
451
The nodes contain information in sections:
449
452
450
453
1 . The gray header has a label showing the BCB ID (or _ index_ for looking up
451
- its ` BasicCoverageBlockData ` ).
454
+ its ` BasicCoverageBlockData ` ).
452
455
2 . 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.)
456
+ each contiguous section of code. (There may be more than one ` Expression `
457
+ incremented by the same ` Counter ` for discontiguous sections of code
458
+ representing the same sequential actions.) Note the code is represented by
459
+ the line and column ranges (for example: ` 52:28-52:33 ` , representing the
460
+ original source line 52, for columns 28-33). These are followed by the MIR
461
+ ` Statement ` or ` Terminator ` represented by that source range. (How these
462
+ coverage regions are determined is discussed in the following section.)
460
463
3 . 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.
464
+ ` TerminatorKind ` ) contained in this BCB. The last BCB is separated out
465
+ because its ` successors() ` determine the edges leading out of the BCB, and
466
+ into the ` leading_bb() ` (first ` BasicBlock ` ) of each successor BCB.
464
467
465
468
Note, to find the ` BasicCoverageBlock ` from a final BCB ` Terminator ` 's
466
469
successor ` BasicBlock ` , there is an index and helper
467
- function--[ ` bcb_from_bb() ` ] [ bcb-from-bb ] --to look up a ` BasicCoverageBlock ` from _ any _
468
- contained ` BasicBlock ` .
470
+ function--[ ` bcb_from_bb() ` ] [ bcb-from-bb ] --to look up a ` BasicCoverageBlock ` from
471
+ * any * contained ` BasicBlock ` .
469
472
470
473
[ directed-graph ] : https://doc.rust-lang.org/nightly/nightly-rustc/rustc_data_structures/graph/trait.DirectedGraph.html
471
474
[ graph-traits ] : https://doc.rust-lang.org/nightly/nightly-rustc/rustc_data_structures/graph/index.html#traits
@@ -572,7 +575,7 @@ incoming edges. Given the following graph, for example, the count for
572
575
573
576
In this situation, BCB node ` B ` may require an edge counter for its
574
577
"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 `
578
+ ` Counter(A) - Counter(C) ` . But an expression for the BCB _ node_ ` B `
576
579
would be the sum of all incoming edges:
577
580
578
581
``` text
0 commit comments