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

WIP toward LLVM Code Coverage for Rust #70680

Closed
wants to merge 8 commits into from

Conversation

richkadel
Copy link
Contributor

I work on Google's Fuchsia OS, and was recently asked to implement code coverage for Rust with output to LLVM's coverage tooling.

I've completed a working prototype for instrumenting Rust programs with calls to coverage counters, and generating reports (coverage region map output from the compiler, and coverage counts upon exiting the instrumented executable.

If someone with more experience developing in rustc can give this an early look and send feedback, that would be really helpful.

Apologies in advance for the current lack of tests and limited documentation. I'll be working on this full time for a while, so it will improve rapidly.

Thanks!

rust-lang#34701

Prototype coverage implementation with partial support for the various
branch types to be covered.

    cargo -vv rustc -- -Z instrument-coverage

With the `-Z instrument-coverage` flag, the compiler injects calls to a
new std::coverage module, adding counters at various points in the code.

At the end of the compile, a list of coverage regions (`Span`s) and
corresponding coverage retion IDs are printed to stdout.

When executing the program, the counters increment statically, and upon
normal exit, the counters are printed to stdout with the same
corresponding coverage region IDs.

The stdout results will be replaced by output files in a format
compatible with LLVM coverage reports.

Currently counts the following coverage regions:
    * All blocks ending in a semicolon or expression
    * break, return, and yield statements, with or without a value
      expression
    * continue statment

Not yet supported are:
    * match pattern arms without a block
    * closures without a block
    * expressions ending in '?' (that return on Result::Err)
    * lazy boolean right-hand-side expressions that may not be invoked
rust-lang#34701

Prototype coverage implementation with partial support for the various
branch types to be covered.

    cargo -vv rustc -- -Z instrument-coverage

With the `-Z instrument-coverage` flag, the compiler injects calls to a
new std::coverage module, adding counters at various points in the code.

At the end of the compile, a list of coverage regions (`Span`s) and
corresponding coverage retion IDs are printed to stdout.

When executing the program, the counters increment statically, and upon
normal exit, the counters are printed to stdout with the same
corresponding coverage region IDs.

The stdout results will be replaced by output files in a format
compatible with LLVM coverage reports.

Currently counts the following coverage regions:
    * All blocks ending in a semicolon or expression
    * break, return, and yield statements, with or without a value
      expression
    * continue statment

Not yet supported are:
    * match pattern arms without a block
    * closures without a block
    * expressions ending in '?' (that return on Result::Err)
    * lazy boolean right-hand-side expressions that may not be invoked
@rust-highfive
Copy link
Collaborator

Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @varkor (or someone else) soon.

If any changes to this PR are deemed necessary, please add them as extra commits. This ensures that the reviewer can see what has changed since they last reviewed the code. Due to the way GitHub handles out-of-date commits, this should also make it reasonably obvious what issues have or haven't been addressed. Large or tricky changes may require several passes of review and changes.

Please see the contribution instructions for more information.

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Apr 2, 2020
@rust-highfive
Copy link
Collaborator

The job mingw-check of your PR failed (pretty log, raw log). Through arcane magic we have determined that the following fragments from the build log may contain information about the problem.

Click to expand the log.
2020-04-02T04:05:06.9419656Z ========================== Starting Command Output ===========================
2020-04-02T04:05:06.9422184Z [command]/bin/bash --noprofile --norc /home/vsts/work/_temp/ff10246a-1943-4fb5-9373-ca84465489fd.sh
2020-04-02T04:05:06.9422396Z 
2020-04-02T04:05:06.9425786Z ##[section]Finishing: Disable git automatic line ending conversion
2020-04-02T04:05:06.9443037Z ##[section]Starting: Checkout rust-lang/rust@refs/pull/70680/merge to s
2020-04-02T04:05:06.9445994Z Task         : Get sources
2020-04-02T04:05:06.9446237Z Description  : Get sources from a repository. Supports Git, TfsVC, and SVN repositories.
2020-04-02T04:05:06.9446470Z Version      : 1.0.0
2020-04-02T04:05:06.9446626Z Author       : Microsoft
---
2020-04-02T04:05:08.2085037Z ##[command]git remote add origin https://github.com/rust-lang/rust
2020-04-02T04:05:08.2091107Z ##[command]git config gc.auto 0
2020-04-02T04:05:08.2096641Z ##[command]git config --get-all http.https://github.com/rust-lang/rust.extraheader
2020-04-02T04:05:08.2102865Z ##[command]git config --get-all http.proxy
2020-04-02T04:05:08.2113562Z ##[command]git -c http.extraheader="AUTHORIZATION: basic ***" fetch --force --tags --prune --progress --no-recurse-submodules --depth=2 origin +refs/heads/*:refs/remotes/origin/* +refs/pull/70680/merge:refs/remotes/pull/70680/merge
---
2020-04-02T04:07:22.9331798Z  ---> 3fc1b512c57b
2020-04-02T04:07:22.9332054Z Step 6/7 : ENV RUN_CHECK_WITH_PARALLEL_QUERIES 1
2020-04-02T04:07:22.9332484Z  ---> Using cache
2020-04-02T04:07:22.9332851Z  ---> 5ee4295733f4
2020-04-02T04:07:22.9334290Z Step 7/7 : ENV SCRIPT python2.7 ../x.py test src/tools/expand-yaml-anchors &&            python2.7 ../x.py check --target=i686-pc-windows-gnu --host=i686-pc-windows-gnu &&            python2.7 ../x.py build --stage 0 src/tools/build-manifest &&            python2.7 ../x.py test --stage 0 src/tools/compiletest &&            python2.7 ../x.py test src/tools/tidy &&            /scripts/validate-toolstate.sh
2020-04-02T04:07:22.9335771Z  ---> 3d07a0fa42fe
2020-04-02T04:07:22.9362724Z Successfully built 3d07a0fa42fe
2020-04-02T04:07:22.9405398Z Successfully tagged rust-ci:latest
2020-04-02T04:07:23.1072535Z Built container sha256:3d07a0fa42feb5754fc13bb2f7010ebe13e4b8b8cdbebed0c75d8da320c8c8ad
2020-04-02T04:07:23.1072535Z Built container sha256:3d07a0fa42feb5754fc13bb2f7010ebe13e4b8b8cdbebed0c75d8da320c8c8ad
2020-04-02T04:07:23.1086973Z Looks like docker image is the same as before, not uploading
2020-04-02T04:07:29.8840106Z [CI_JOB_NAME=mingw-check]
2020-04-02T04:07:29.9116329Z [CI_JOB_NAME=mingw-check]
2020-04-02T04:07:29.9151407Z == clock drift check ==
2020-04-02T04:07:29.9161110Z   local time: Thu Apr  2 04:07:29 UTC 2020
2020-04-02T04:07:30.0104135Z   network time: Thu, 02 Apr 2020 04:07:30 GMT
2020-04-02T04:07:30.0149872Z Starting sccache server...
2020-04-02T04:07:30.1082344Z configure: processing command line
2020-04-02T04:07:30.1082624Z configure: 
2020-04-02T04:07:30.1083585Z configure: rust.parallel-compiler := True
---
2020-04-02T04:07:43.3289939Z   No such file or directory (os error 2)
2020-04-02T04:07:43.3291498Z failed to run: /checkout/obj/build/x86_64-unknown-linux-gnu/stage0/bin/cargo build --manifest-path /checkout/src/bootstrap/Cargo.toml
2020-04-02T04:07:43.3292306Z Build completed unsuccessfully in 0:00:13
2020-04-02T04:07:43.3339152Z == clock drift check ==
2020-04-02T04:07:43.3347607Z   local time: Thu Apr  2 04:07:43 UTC 2020
2020-04-02T04:07:43.4939337Z   network time: Thu, 02 Apr 2020 04:07:43 GMT
2020-04-02T04:07:51.2343189Z 
2020-04-02T04:07:51.2343189Z 
2020-04-02T04:07:51.2449133Z ##[error]Bash exited with code '1'.
2020-04-02T04:07:51.2463248Z ##[section]Finishing: Run build
2020-04-02T04:07:51.2508216Z ##[section]Starting: Checkout rust-lang/rust@refs/pull/70680/merge to s
2020-04-02T04:07:51.2513539Z Task         : Get sources
2020-04-02T04:07:51.2513924Z Description  : Get sources from a repository. Supports Git, TfsVC, and SVN repositories.
2020-04-02T04:07:51.2514255Z Version      : 1.0.0
2020-04-02T04:07:51.2514504Z Author       : Microsoft
2020-04-02T04:07:51.2514504Z Author       : Microsoft
2020-04-02T04:07:51.2514866Z Help         : [More Information](https://go.microsoft.com/fwlink/?LinkId=798199)
2020-04-02T04:07:51.2515289Z ==============================================================================
2020-04-02T04:07:51.6032862Z Cleaning any cached credential from repository: rust-lang/rust (GitHub)
2020-04-02T04:07:51.6083147Z ##[section]Finishing: Checkout rust-lang/rust@refs/pull/70680/merge to s
2020-04-02T04:07:51.6177833Z Cleaning up task key
2020-04-02T04:07:51.6180811Z Start cleaning up orphan processes.
2020-04-02T04:07:51.6388174Z Terminate orphan process: pid (3442) (python)
2020-04-02T04:07:51.6603007Z ##[section]Finishing: Finalize Job

I'm a bot! I can only do what humans tell me to, so if this was not helpful or you have suggestions for improvements, please ping or otherwise contact @rust-lang/infra. (Feature Requests)

@@ -0,0 +1,83 @@
//! Code coverage counters and report
Copy link
Contributor

Choose a reason for hiding this comment

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

Why is this being added to the standard library?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I need to add the library of rustc-injected coverage APIs to a reserved namespace available only to rustc. "core" doesn't make sense to me. I'm not sure if there are any alternatives?

Copy link
Contributor

Choose a reason for hiding this comment

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

One approach is a dedicated crate that is distributed along with the rustc and injected as a dependency when requested during compilation. For example, -Zprofile injects profiler_builtins crate, which you might potentially also find useful here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I actually started with "coverage_builtins" following that model, but wasn't sure if/how that would make it into the program's library dependencies, and since "coverage_builtins" is not a truly reserved namespace, it made me uneasy.

builtins::coverage would be great, perhaps, if the Rust community is open to reserving the "builtins" namespace for instrumentation APIs. (Or is it already?)

WDYT?

Choose a reason for hiding this comment

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

I suggest using LLVM's runtime support in compiler_rt instead (along with the llvm.instrprof.increment intrinsic).

@mominul
Copy link
Contributor

mominul commented Apr 2, 2020

Relevant issue #34701

@eddyb
Copy link
Member

eddyb commented Apr 2, 2020

I'm surprised this is not using the LLVM intrinsics at all.

Also, I don't think "statements" are that meaningful in Rust.


Back in 2018 when a client wanted instrumentation-based code coverage (which didn't actually end up happening), I did a bit of research and had some plans.

IIRC, I wanted to instrument Rust code at the MIR level, and have counters for each basic block and for each branch edge, that matched the respective features of LLVM coverage tooling.
I could go digging through that information again but I'm worried some of it is out of date.


Either way, I would prefer not to instrument Rust code before MIR, as much as possible.
The earliest point where I could see us inserting anything coverage-specific would be MIR building (which has access to the HIR and type-checking results).

@richkadel
Copy link
Contributor Author

The most recent recommendations in the discussion last year at #34701 was to use pre-lowered (and post-macro-expansion) ASTs, and so far I think it is working well. It gives a good mapping of regions to the actual source, so when users view the source with coverage annotations, it's clear what was and was not executed. The coverage regions will (eventually) be hashed representations of the source locations (file, function, and some best-attempt at identifying internal branches based on the original source code content).

I'm no expert on MIR though. I just didn't invest a lot of time into it since that wasn't the recommendation.

But based on this approach, I think that explains why LLVM intrinsics are not relevant to the instrumentation.

The plan is to export the coverage regions and the counters to LLVM-compatible formats so LLVM coverage analysis tools can be used.

@eddyb
Copy link
Member

eddyb commented Apr 2, 2020

It gives a good mapping of regions to the actual source, so when users view the source with coverage annotations, it's clear what was and was not executed.

That can be done from the MIR, using Spans (afterall, debuginfo is computed from the MIR).

The most recent recommendations in the discussion last year at #34701 was to use pre-lowered (and post-macro-expansion) ASTs

Ah, nobody pointed me to #34701 so I had no idea there was discussion on this topic already.
From a quick skim I agree most with @hanna-kruppe's #34701 (comment):

However, inserting it during MIR construction might make sense.

@richkadel
Copy link
Contributor Author

@eddyb - Thanks for these recommendations. There's time to consider migrating the instrumentation to the MIR if it turns out to have some strong advantages.

I would point out one other comment that particularly caught my eye since it was from @eggyal, who did attempt coverage instrumentation at the MIR level initially:

@bob-wilson: I'm delighted to say that I now recognise the folly of trying to generate these mappings from the MIR: it's not practical to comprehend program flow through the BasicBlocks well enough to establish the code regions. Nevertheless I'm pleased that I undertook the exercise to understand the problem better—thank you for patiently indulging me whilst I caught up with you!

Reading this and @bob-wilson's other comments pushed me toward my current approach.

@bob-wilson
Copy link

Great timing! Since I hadn't seen any recent progress on #34701 , I just spent the last few days trying to start an implementation following the same approach that we used in Clang. I'll take a look at this soon. I still think the coverage should be based on the ASTs, not MIR or even HIR.

@richkadel
Copy link
Contributor Author

That's great Bob! Following your recommendation, I looked at and drew inspiration form the Clang implementation.

@richkadel
Copy link
Contributor Author

@bob-wilson I'm working with llvm developers our our team, and we discussed leveraging the existing llvm intrinsic counters (@eddyb, FYI, it does look like llvm intrinsics will help me here!):

declare void @llvm.instrprof.increment(i8* <name>, i64 <hash>,
                                       i32 <num-counters>, i32 <index>)

I think this will fit well into my implementation. We discussed ways I might implement the parameters to this function, and had a question or two you might be able to answer.

Per the docs, the name "should generally be the (mangled) function name".

How important this recommendation? Do any downstream coverage tools actually use the function name? (Especially since this is not C++ code?)

If it is assumed to be a function name, and interpreted as such, what are the use cases for that?

I'm asking because my assumption was that the downstream tools really only need the coverage regions (source file and span) and the counts. Let me know if that's not enough (if you know).

Thanks!

Comment on lines +298 to +301
// add more visit_???() functions for language constructs that are branched statements without
// blocks, such as:
// visit match arm expr
// if not block, wrap expr in block and inject counter
Copy link
Member

Choose a reason for hiding this comment

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

I'm not sure we care much about blocks in particular at all (unless they happen to be the block which defines a function body). Looking directly for branch expressions seems like what we want.

In clang focusing on blocks makes a bit more sense, since blocks usually correspond to some kind of branch in C++. (Even then it doesn't seem like exactly the right thing to me, but maybe I'm missing something.)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

that's a good point and simplifies the solution by not making non-block branch expressions a special case. Cool!

I still need to support function blocks though, I believe.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

On second thought, I need to give that more thought ;-)

return (and yield), break, and continue may complicate the idea that this is simpler. I'll think about it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Just following up on this: I've been experimenting with various ways to inject the counters, in a number of different (and some obscure) branch types, and as it turns out (as best I can tell), my initial approach seems to be the best way to handle block expressions.

Non-block expressions are straightforward enough, but I can't apply the same simplicity to blocks because of the possibility that the block might contain a return, break, or continue.

(If the block doesn't contain a return, break, or continue, I think the block can be handled just like a non-block expression, but intuitively I think it's better to handle all blocks the same and not worry about what might or might not be inside them.)

For example:

match var1 {
    Pattern1 => expr(),
...

I can count the execution of the Pattern1 arm with:

match var1 {
    Pattern1 => count(..., expr()),
...

But (if I interpretted your suggestion correctly), to ignore blocks and just inject counters based on expressions, I tried the following (which certainly looks tempting):

match var1 {
    Pattern1 => count(..., {
        do_one_thing();
        get_result()
    }),
...

No problem there, but:

match var1 {
    Pattern1 => count(..., {
        println!("Bad pattern");
        return Err(...);
    }),
...

This will not compile because it is clear (to the compiler) that count() will never be executed.

So this is what led me to the current prototype solution for blocks, in this case:

match var1 {
    Pattern1 => {
        println!("Bad pattern");
        return count(..., Err(...));
    },
...

There are a few other edge cases like this that require handling blocks differently from non-block branched expressions. I'll try to cover these in future documentation, with my branch analysis.

Let me know if I missed something about your suggestion.

Thanks!

src/librustc_coverage/Cargo.toml Outdated Show resolved Hide resolved
src/librustc_interface/passes.rs Outdated Show resolved Hide resolved
src/librustc_interface/queries.rs Outdated Show resolved Hide resolved
@bob-wilson
Copy link

Per the docs, the name "should generally be the (mangled) function name".

How important this recommendation? Do any downstream coverage tools actually use the function name? (Especially since this is not C++ code?)

If it is assumed to be a function name, and interpreted as such, what are the use cases for that?

I'm asking because my assumption was that the downstream tools really only need the coverage regions (source file and span) and the counts. Let me know if that's not enough (if you know).

Definitely we should use the LLVM intrinsics!

The runtime support in LLVM organizes the execution count data by function name. I'm sure there are other ways to do it, but I recommend following the precedent. If the Rust implementation fits into the existing usage, it will probably save some trouble in the initial implementation and should also be easier to maintain going forward.

There are some other LLVM functions that we should also use. At least some of these are not currently exported in the LLVM C APIs, but it shouldn't be a problem to fix that:

  • llvm::createPGOFuncNameVar: See below for where the function name argument should come from. The result of this call is the first argument to the instrprof.increment intrinsic.
  • llvm::createPGOFuncNameMetadata
  • llvm::getPGOFuncName: There are 2 versions of this with different arguments, but the one we need just calls through to GlobalValue::getGlobalIdentifier. The code there is pretty simple, especially because I don't think we'll need to worry about value names, so it would be OK to reimplement this one in Rust.

One complication here is that I don't think the Rust compiler should be calling these LLVM functions outside of the librustc_codegen_llvm crate. I don't know the architecture of the Rust compiler, but calling those functions directly in a pass over the AST seems like a bad idea. I was thinking to insert the instrprof.increment intrinsic calls with a dummy argument for the variable and then swap in the real value when handling the intrinsic in librustc_codegen_llvm.

It would make sense to generate the coverage mapping directly from the code walking the AST, and that will also need to use the same function naming scheme. If we can reimplement the equivalent of llvm::getPGOFuncName in Rust, that will be fine. I believe that's the only LLVM function that is needed outside of librustc_codegen_llvm.

@richkadel
Copy link
Contributor Author

I was thinking to insert the instrprof.increment intrinsic calls with a dummy argument for the variable and then swap in the real value when handling the intrinsic in librustc_codegen_llvm.

Yes! I suggested the same idea yesterday with my team. I'll pursue that idea and see where it goes.

Thanks for the suggestions!

@Centril Centril added I-nominated T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Apr 8, 2020
Cargo.lock Outdated Show resolved Hide resolved
@pnkfelix
Copy link
Member

pnkfelix commented Apr 10, 2020

Discussed in today's T-compiler ad-hoc triage meeting.

We think that a change like this warrants at least a Major Change Proposal aka "MCP" (*)

It may also warrant a design meeting, but for now we can start with an MCP since that is lighter weight and won't require waiting for a synchronous design meeting.

(*) a protocol that is in the midst of being finalized via a proposed final comment period ("FCP"), but I think you can safely create such proposals now, before the FCP has finished.

@richkadel
Copy link
Contributor Author

We think that a change like this warrants at least a Major Change Proposal aka "MCP" (*)

Sounds good. I was already planning to put together some kind of RFC, but will use the MCP format instead.

Thanks for providing this guidance!

@richkadel
Copy link
Contributor Author

@pnkfelix - Just a quick note to let you know I've completed a draft of the MCP. I'm circulating it to my internal team to make sure it addresses the requirements we need for Fuchsia's toolchain (the main reason I've been asked to work on this), and to ensure I'm addressing any concerns, before posting the MCP for the Rust compiler team's review.

I expect to be able to post the MCP in the next couple of business days.

Thanks!

@varkor varkor added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Apr 19, 2020
@crlf0710
Copy link
Member

crlf0710 commented May 2, 2020

@richkadel Ping from triage, any updates here? Thanks!

@crlf0710 crlf0710 added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels May 2, 2020
@richkadel
Copy link
Contributor Author

@richkadel Ping from triage, any updates here? Thanks!

@crlf0710 - Thanks for the ping. Apologies if the status is not clear.

I followed the steps required by the compiler team--as requested by @pnkfelix on this thread--and submitted an MCP (linked just above your comment):

Implement LLVM-compatible source-based code coverage #278

I am waiting for someone on the compiler team to "second" the proposed feature.

There are a variety of opinions on where coverage regions should be calculated, and coverage instrumentation should be integrated, both in the original issue, and in the Zulip thread associated with the above MCP.

Some good arguments were made by one participant in the Zulip chat for moving the instrumentation to a MIR-MIR pass, so I am attempting to prototype a MIR->MIR solution (with guidance from @tmandry ). I've also started to implement the LLVM intrinsic integration.

The MCP proposal was intentionally written to be open to recommended alternatives per feedback from the compiler team, if feasible. I acknowledged this in the Zulip chat, I said I am willing to try some of the alternatives proposed.

But to make this even more clear, I will edit the MCP to refine it based on the recent Zulip chat. (The MCP process does not say if editing the MCP is required, in response to the Zulip discussions, but I want to make sure the compiler team sees the adjustments I agreed to make.)

It may be counterproductive to update this PR until the compiler team seconds, reviews, and accepts the MCP.

Thanks!

@richkadel
Copy link
Contributor Author

I finished updating the MCP. Waiting for feedback on the MCP from the compiler team.

Thanks!
Rich

@richkadel
Copy link
Contributor Author

Quick update: The MCP was seconded by a member of the compiler team and has entered a 10 day waiting period before final approval (if there are objections). In the mean time, I continue to make changes based on the new approach described in the revised MCP, and will update the PR if there is anything significant to share. Thanks!

@crlf0710 crlf0710 added S-blocked Status: Marked as blocked ❌ on something else such as an RFC or other implementation work. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels May 10, 2020
@richkadel
Copy link
Contributor Author

Based on feedback during the MCP process, I'm changing the approach from an AST-based solution to an implementation on MIR. Since the new approach is significantly different, I'm abandoning this PR. Please follow the new changes, starting with PR #73011.

@richkadel richkadel closed this Jun 5, 2020
Dylan-DPC-zz pushed a commit to Dylan-DPC-zz/rust that referenced this pull request Jun 15, 2020
… r=tmandry

first stage of implementing LLVM code coverage

This PR replaces rust-lang#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: rust-lang#34701 - Implement support for LLVMs code coverage instrumentation

***[I put together some development notes here, under a separate branch.](https://github.com/richkadel/rust/blob/cfa0b21d34ee64e4ebee226101bd2ef0c6757865/src/test/codegen/coverage-experiments/README-THIS-IS-TEMPORARY.md)***
Dylan-DPC-zz pushed a commit to Dylan-DPC-zz/rust that referenced this pull request Jun 16, 2020
… r=tmandry

first stage of implementing LLVM code coverage

This PR replaces rust-lang#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: rust-lang#34701 - Implement support for LLVMs code coverage instrumentation

***[I put together some development notes here, under a separate branch.](https://github.com/richkadel/rust/blob/cfa0b21d34ee64e4ebee226101bd2ef0c6757865/src/test/codegen/coverage-experiments/README-THIS-IS-TEMPORARY.md)***
RalfJung added a commit to RalfJung/rust that referenced this pull request Jun 19, 2020
… r=tmandry

first stage of implementing LLVM code coverage

This PR replaces rust-lang#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: rust-lang#34701 - Implement support for LLVMs code coverage instrumentation

***[I put together some development notes here, under a separate branch.](https://github.com/richkadel/rust/blob/cfa0b21d34ee64e4ebee226101bd2ef0c6757865/src/test/codegen/coverage-experiments/README-THIS-IS-TEMPORARY.md)***
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-blocked Status: Marked as blocked ❌ on something else such as an RFC or other implementation work. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet