Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

first stage of implementing LLVM code coverage #73011

Merged
merged 17 commits into from
Jun 19, 2020

Conversation

richkadel
Copy link
Contributor

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 rust-lang/compiler-team#278
Relevant issue: #34701 - Implement support for LLVMs code coverage instrumentation

I put together some development notes here, under a separate branch.

@rust-highfive
Copy link
Collaborator

r? @davidtwco

(rust_highfive has picked a reviewer for you, use r? to override)

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Jun 5, 2020
@richkadel
Copy link
Contributor Author

r? @davidtwco

(rust_highfive has picked a reviewer for you, use r? to override)

r? @tmandry @wesleywiser

@richkadel
Copy link
Contributor Author

(rust_highfive has picked a reviewer for you, use r? to override)

r? @tmandry @wesleywiser

@richkadel
Copy link
Contributor Author

@wesleywiser - PTAL.

Note that Tyler and I also discussed the possibility of implementing the code generation with a custom Statement (rather than injecting a Call Terminator, as I did in this PR).

The Call Terminator allowed me to model the injected intrinsic the way that other intrinsics are handled (with a few important differences).

An alternative, suggested by Tyler, would be to define a new, custom StatementKind. Knowing that the llvm.instrprof.increment intrinsic will never panic, its BasicBlock does not branch, so a Statement would potentially avoid the need to inject a new BB.

My only hesitation is that a new StatementKind for this intrinsic becomes a very special case, different from all other intrinsics, and there may be hidden expectations and assumptions in the compiler that could add unexpected complexity.

But, I'm open to this alternative approach if there's a good reason to make that change.

Let us know your thoughts.

@tmandry - Please feel free to expand on or correct my explanation here. Thank you!

src/libcore/intrinsics.rs Outdated Show resolved Hide resolved
src/libcore/intrinsics.rs Outdated Show resolved Hide resolved
Copy link
Member

@tmandry tmandry left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great! Left a couple comments but otherwise I think this is ready to land.

src/librustc_mir/interpret/intrinsics.rs Show resolved Hide resolved
src/librustc_mir/transform/instrument_coverage.rs Outdated Show resolved Hide resolved
src/librustc_mir/transform/mod.rs Outdated Show resolved Hide resolved
src/librustc_codegen_llvm/intrinsic.rs Show resolved Hide resolved
@tmandry
Copy link
Member

tmandry commented Jun 8, 2020

@bors d+

r=me after comments

@tmandry
Copy link
Member

tmandry commented Jun 8, 2020

@bors r+

@bors
Copy link
Contributor

bors commented Jun 8, 2020

📌 Commit 84d4424ff88db00736e940da9443c29ef5911101 has been approved by tmandry

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jun 8, 2020
@richkadel richkadel closed this Jun 9, 2020
@richkadel richkadel reopened this Jun 9, 2020
@richkadel
Copy link
Contributor Author

Did not mean to close the PR. The GitHub app on Android has a Pull Request status window with a "Close" button. It looks like that button is how you close the window, but it closes the PR... Ach!

@oli-obk
Copy link
Contributor

oli-obk commented Jun 10, 2020

Please add tests in src/tests/mir-opt that show various things that get annotated by the annotation pass.

You'll need to add // compile-flags: -Zinstrument-coverage and // EMIT_MIR rustc.some_function_you_want_to_see_the_mir_of.InstrumentCoverage.diff to the test file in order to get dumps.

@richkadel
Copy link
Contributor Author

@oli-obk

Please add tests in src/tests/mir-opt that show various things that get annotated by the annotation pass.

Done

Co-authored-by: bjorn3 <bjorn3@users.noreply.github.com>
@tmandry
Copy link
Member

tmandry commented Jun 17, 2020

@bors r+

@bors
Copy link
Contributor

bors commented Jun 17, 2020

📌 Commit c338729 has been approved by tmandry

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Jun 17, 2020
@richkadel
Copy link
Contributor Author

@Dylan-DPC - Would you be willing to include this in the next rollup? Thanks!

@richkadel
Copy link
Contributor Author

@Dylan-DPC - Would you be willing to include this in the next rollup? Thanks!

Please hold off. We're going to do another bors try with macos and windows tests enabled, to make sure there are no more surprises.

testing platform-specific changes
@richkadel richkadel force-pushed the llvm-count-from-mir-pass branch from 2238705 to b9f0304 Compare June 17, 2020 18:40
@tmandry
Copy link
Member

tmandry commented Jun 17, 2020

@bors try

@bors
Copy link
Contributor

bors commented Jun 17, 2020

⌛ Trying commit b9f0304 with merge 7e5ef77edd62e7082b227400416e103834f1ef1a...

@mati865
Copy link
Contributor

mati865 commented Jun 17, 2020

This PR is next in bors queue. It'd be safer for rollups to not include it.

@Dylan-DPC-zz
Copy link

it's not next on the queue 🤔 it's on "try" which is separate so it won't be merged

@mati865
Copy link
Contributor

mati865 commented Jun 17, 2020

@Dylan-DPC right, I mistook 73011 for 70311 😮

@bors
Copy link
Contributor

bors commented Jun 17, 2020

☀️ Try build successful - checks-azure
Build commit: 7e5ef77edd62e7082b227400416e103834f1ef1a (7e5ef77edd62e7082b227400416e103834f1ef1a)

@richkadel
Copy link
Contributor Author

I removed the "try" config changes (PR passes on all platforms now!).

This version should be good to merge, assuming no new merge conflicts.

Thanks!

@tmandry
Copy link
Member

tmandry commented Jun 17, 2020

@bors r+

@bors
Copy link
Contributor

bors commented Jun 17, 2020

📌 Commit 36c9014 has been approved by tmandry

bors added a commit to rust-lang-ci/rust that referenced this pull request Jun 19, 2020
Rollup of 10 pull requests

Successful merges:

 - rust-lang#72280 (Fix up autoderef when reborrowing)
 - rust-lang#72785 (linker: MSVC supports linking static libraries as a whole archive)
 - rust-lang#73011 (first stage of implementing LLVM code coverage)
 - rust-lang#73044 (compiletest: Add directives to detect sanitizer support)
 - rust-lang#73054 (memory access sanity checks: abort instead of panic)
 - rust-lang#73136 (Change how compiler-builtins gets many CGUs)
 - rust-lang#73280 (Add E0763)
 - rust-lang#73317 (bootstrap: read config from $RUST_BOOTSTRAP_CONFIG)
 - rust-lang#73350 (bootstrap/install.rs: support a nonexistent `prefix` in `x.py install`)
 - rust-lang#73352 (Speed up bootstrap a little.)

Failed merges:

r? @ghost
@bors bors merged commit 1dc6c3c into rust-lang:master Jun 19, 2020
Manishearth added a commit to Manishearth/rust that referenced this pull request Jun 23, 2020
…tmandry

code coverage foundation for hash and num_counters

This PR is the next iteration after PR rust-lang#73011 (which is still waiting on bors to merge).

@wesleywiser - PTAL
r? @tmandry

(FYI, I'm also working on injecting the coverage maps, in another branch, while waiting for these to merge.)

Thanks!
Manishearth added a commit to Manishearth/rust that referenced this pull request Jun 23, 2020
…tmandry

code coverage foundation for hash and num_counters

This PR is the next iteration after PR rust-lang#73011 (which is still waiting on bors to merge).

@wesleywiser - PTAL
r? @tmandry

(FYI, I'm also working on injecting the coverage maps, in another branch, while waiting for these to merge.)

Thanks!
@@ -389,6 +389,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
);
self.copy_op(self.operand_index(args[0], index)?, dest)?;
}
// FIXME(#73156): Handle source code coverage in const eval
sym::count_code_region => (),
Copy link
Member

@RalfJung RalfJung Jun 27, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please always ping @rust-lang/wg-const-eval for new intrinsics in CTFE.
It is not great when I realize by mere accident that we have a new intrinsic here. It's just a stub this time, so no big deal, but who knows what it might be next time. ;)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, note that as per this comment, T-lang should have been involved as well:

//! Note: any changes to the constness of intrinsics should be discussed with the language team.
//! This includes changes in the stability of the constness.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

amusingly this intrinsic is not marked as const at all. The static checks preventing non-const intrinsics from being invoked happen before mir optimizations. Since instrumentation is a MIR transformation... this isn't caught. Maybe instrumentation should happen before const checking and such?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, so this intrinsic is not called by users, but the call is inserted by an instrumentation pass later? Interesting. That reduces my T-lang concern.

Maybe instrumentation should happen before const checking and such?

Maybe -- I am not sure to what extend it would be useful to check the instrumented code as if it was user-written.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I write

const fn a() -> u8 {
    42
}

const A: u8 = a();

fn main() {
    println!("{}", A);
}

Then currently a will contribute towards coverage, yet it is not marked as executed. I think the count_code_region intrinsic should also mark code as executed during CTFE.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bjorn3 that is a separate issue though from the other discussion here? Namely, it is #73156.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Didn't see that issue, thanks.

Copy link
Member

@wesleywiser wesleywiser Jun 27, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry about that @RalfJung! That was my fault; I didn't realize we should be pinging that group. I will try to keep that in mind in the future.

Do you think we still need to get the lang team involved? This intrinsic is used by an unstable -Z compiler flag which generates code coverage data using LLVM features. The compiler team already signed off on this approach via an MCP.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I doubt they will have any objections, but sending T-lang an "FYI this is what we did here" would still be a good idea I think.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for flagging the issue @RalfJung ...

Note also, the next PR increment is under review, and adds some additional Rust intrinsics that I believe we need for coverage map generation.

See this related note:

#73684 (comment)

Since the MIR analysis is minimal at the moment (injecting at the function level only) I'm not generating calls to these intrinsics yet, but when I do, I suspect I may need to add these new intrinsics to src/librustc_mir/interpret/intrinsics.rs as well, similarly stubbed out.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion.
Projects
None yet
Development

Successfully merging this pull request may close these issues.