Rollup merge of #73011 - richkadel:llvm-count-from-mir-pass, r=tmandry
first stage of implementing LLVM code coverage
This PR replaces #70680 (WIP toward LLVM Code Coverage for Rust) since I am re-implementing the Rust LLVM code coverage feature in a different part of the compiler (in MIR pass(es) vs AST).
This PR updates rustc with `-Zinstrument-coverage` option that injects the llvm intrinsic `instrprof.increment()` for code generation.
This initial version only injects counters at the top of each function, and does not yet implement the required coverage map.
Upcoming PRs will add the coverage map, and add more counters and/or counter expressions for each conditional code branch.
Rust compiler MCP https://github.com/rust-lang/compiler-team/issues/278
Relevant issue: #34701 - Implement support for LLVMs code coverage instrumentation
***[I put together some development notes here, under a separate branch.](cfa0b21d34/src/test/codegen/coverage-experiments/README-THIS-IS-TEMPORARY.md)***
This commit is contained in:
commit
1dc6c3c4ad
25 changed files with 383 additions and 4 deletions
20
src/test/mir-opt/instrument_coverage.rs
Normal file
20
src/test/mir-opt/instrument_coverage.rs
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
// Test that the initial version of Rust coverage injects count_code_region() placeholder calls,
|
||||
// at the top of each function. The placeholders are later converted into LLVM instrprof.increment
|
||||
// intrinsics, during codegen.
|
||||
|
||||
// needs-profiler-support
|
||||
// compile-flags: -Zinstrument-coverage
|
||||
// EMIT_MIR rustc.main.InstrumentCoverage.diff
|
||||
// EMIT_MIR rustc.bar.InstrumentCoverage.diff
|
||||
fn main() {
|
||||
loop {
|
||||
if bar() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
fn bar() -> bool {
|
||||
true
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
- // MIR for `bar` before InstrumentCoverage
|
||||
+ // MIR for `bar` after InstrumentCoverage
|
||||
|
||||
fn bar() -> bool {
|
||||
let mut _0: bool; // return place in scope 0 at $DIR/instrument_coverage.rs:18:13: 18:17
|
||||
+ let mut _1: (); // in scope 0 at $DIR/instrument_coverage.rs:18:1: 20:2
|
||||
|
||||
bb0: {
|
||||
+ StorageLive(_1); // scope 0 at $DIR/instrument_coverage.rs:18:1: 20:2
|
||||
+ _1 = const std::intrinsics::count_code_region(const 0u32) -> bb2; // scope 0 at $DIR/instrument_coverage.rs:18:1: 20:2
|
||||
+ // ty::Const
|
||||
+ // + ty: unsafe extern "rust-intrinsic" fn(u32) {std::intrinsics::count_code_region}
|
||||
+ // + val: Value(Scalar(<ZST>))
|
||||
+ // mir::Constant
|
||||
+ // + span: $DIR/instrument_coverage.rs:18:1: 18:1
|
||||
+ // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(u32) {std::intrinsics::count_code_region}, val: Value(Scalar(<ZST>)) }
|
||||
+ // ty::Const
|
||||
+ // + ty: u32
|
||||
+ // + val: Value(Scalar(0x00000000))
|
||||
+ // mir::Constant
|
||||
+ // + span: $DIR/instrument_coverage.rs:18:1: 18:1
|
||||
+ // + literal: Const { ty: u32, val: Value(Scalar(0x00000000)) }
|
||||
+ }
|
||||
+
|
||||
+ bb1 (cleanup): {
|
||||
+ resume; // scope 0 at $DIR/instrument_coverage.rs:18:1: 20:2
|
||||
+ }
|
||||
+
|
||||
+ bb2: {
|
||||
+ StorageDead(_1); // scope 0 at $DIR/instrument_coverage.rs:19:5: 19:9
|
||||
_0 = const true; // scope 0 at $DIR/instrument_coverage.rs:19:5: 19:9
|
||||
// ty::Const
|
||||
// + ty: bool
|
||||
// + val: Value(Scalar(0x01))
|
||||
// mir::Constant
|
||||
// + span: $DIR/instrument_coverage.rs:19:5: 19:9
|
||||
// + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
|
||||
return; // scope 0 at $DIR/instrument_coverage.rs:20:2: 20:2
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
- // MIR for `main` before InstrumentCoverage
|
||||
+ // MIR for `main` after InstrumentCoverage
|
||||
|
||||
fn main() -> () {
|
||||
let mut _0: (); // return place in scope 0 at $DIR/instrument_coverage.rs:9:11: 9:11
|
||||
let mut _1: (); // in scope 0 at $DIR/instrument_coverage.rs:9:1: 15:2
|
||||
let mut _2: bool; // in scope 0 at $DIR/instrument_coverage.rs:11:12: 11:17
|
||||
let mut _3: !; // in scope 0 at $DIR/instrument_coverage.rs:11:18: 13:10
|
||||
+ let mut _4: (); // in scope 0 at $DIR/instrument_coverage.rs:9:1: 15:2
|
||||
|
||||
bb0: {
|
||||
- falseUnwind -> [real: bb1, cleanup: bb2]; // scope 0 at $DIR/instrument_coverage.rs:10:5: 14:6
|
||||
+ StorageLive(_4); // scope 0 at $DIR/instrument_coverage.rs:9:1: 15:2
|
||||
+ _4 = const std::intrinsics::count_code_region(const 0u32) -> bb7; // scope 0 at $DIR/instrument_coverage.rs:9:1: 15:2
|
||||
+ // ty::Const
|
||||
+ // + ty: unsafe extern "rust-intrinsic" fn(u32) {std::intrinsics::count_code_region}
|
||||
+ // + val: Value(Scalar(<ZST>))
|
||||
+ // mir::Constant
|
||||
+ // + span: $DIR/instrument_coverage.rs:9:1: 9:1
|
||||
+ // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(u32) {std::intrinsics::count_code_region}, val: Value(Scalar(<ZST>)) }
|
||||
+ // ty::Const
|
||||
+ // + ty: u32
|
||||
+ // + val: Value(Scalar(0x00000000))
|
||||
+ // mir::Constant
|
||||
+ // + span: $DIR/instrument_coverage.rs:9:1: 9:1
|
||||
+ // + literal: Const { ty: u32, val: Value(Scalar(0x00000000)) }
|
||||
}
|
||||
|
||||
bb1: {
|
||||
StorageLive(_2); // scope 0 at $DIR/instrument_coverage.rs:11:12: 11:17
|
||||
_2 = const bar() -> [return: bb3, unwind: bb2]; // scope 0 at $DIR/instrument_coverage.rs:11:12: 11:17
|
||||
// ty::Const
|
||||
// + ty: fn() -> bool {bar}
|
||||
// + val: Value(Scalar(<ZST>))
|
||||
// mir::Constant
|
||||
// + span: $DIR/instrument_coverage.rs:11:12: 11:15
|
||||
// + literal: Const { ty: fn() -> bool {bar}, val: Value(Scalar(<ZST>)) }
|
||||
}
|
||||
|
||||
bb2 (cleanup): {
|
||||
resume; // scope 0 at $DIR/instrument_coverage.rs:9:1: 15:2
|
||||
}
|
||||
|
||||
bb3: {
|
||||
FakeRead(ForMatchedPlace, _2); // scope 0 at $DIR/instrument_coverage.rs:11:12: 11:17
|
||||
switchInt(_2) -> [false: bb5, otherwise: bb4]; // scope 0 at $DIR/instrument_coverage.rs:11:9: 13:10
|
||||
}
|
||||
|
||||
bb4: {
|
||||
falseEdge -> [real: bb6, imaginary: bb5]; // scope 0 at $DIR/instrument_coverage.rs:11:9: 13:10
|
||||
}
|
||||
|
||||
bb5: {
|
||||
_1 = const (); // scope 0 at $DIR/instrument_coverage.rs:11:9: 13:10
|
||||
// ty::Const
|
||||
// + ty: ()
|
||||
// + val: Value(Scalar(<ZST>))
|
||||
// mir::Constant
|
||||
// + span: $DIR/instrument_coverage.rs:11:9: 13:10
|
||||
// + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
|
||||
StorageDead(_2); // scope 0 at $DIR/instrument_coverage.rs:14:5: 14:6
|
||||
goto -> bb0; // scope 0 at $DIR/instrument_coverage.rs:10:5: 14:6
|
||||
}
|
||||
|
||||
bb6: {
|
||||
_0 = const (); // scope 0 at $DIR/instrument_coverage.rs:12:13: 12:18
|
||||
// ty::Const
|
||||
// + ty: ()
|
||||
// + val: Value(Scalar(<ZST>))
|
||||
// mir::Constant
|
||||
// + span: $DIR/instrument_coverage.rs:12:13: 12:18
|
||||
// + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
|
||||
StorageDead(_2); // scope 0 at $DIR/instrument_coverage.rs:14:5: 14:6
|
||||
return; // scope 0 at $DIR/instrument_coverage.rs:15:2: 15:2
|
||||
+ }
|
||||
+
|
||||
+ bb7: {
|
||||
+ StorageDead(_4); // scope 0 at $DIR/instrument_coverage.rs:10:5: 14:6
|
||||
+ falseUnwind -> [real: bb1, cleanup: bb2]; // scope 0 at $DIR/instrument_coverage.rs:10:5: 14:6
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue