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

Add support for MIR opt unit tests via a new -Z flag #502

Closed
1 of 3 tasks
JakobDegen opened this issue Mar 27, 2022 · 3 comments
Closed
1 of 3 tasks

Add support for MIR opt unit tests via a new -Z flag #502

JakobDegen opened this issue Mar 27, 2022 · 3 comments
Labels
major-change A proposal to make a major change to rustc major-change-accepted A major change proposal that was accepted T-compiler Add this label so rfcbot knows to poll the compiler team

Comments

@JakobDegen
Copy link

Proposal

Motivation

MIR opt tests currently suffer from being somewhat brittle. Each test indirectly includes the output of every pass that runs before the pass that test is targeting. Changing pass order or the behavior of some passes can hence break the tests for unrelated subsequent passes. Furthermore, many (most?) of the MIR tests are intended to be "unit tests" - that is, they intend to verify that a particular pass behaves in a particular way on particular input.

In some cases, when unrelated passes change these unit tests can be broken in trivial ways that can just be blessed. This is not a huge deal, but it increases the size of the diff and requires the contributor to evaluate the change to a test unrelated to the code they are writing. Other times, the test changes in a non-trivial way - most commonly, this is in the form of the input to the pass being tested having changed and the test no longer demonstrating what it was supposed to. The contributor then has to go and change the test in such a way as to reproduce the old behavior. Depending on the nature of the conflict, this can be difficult to do either at all or in a clean way. Of course, even if successful, this once more causes an increase in the size of the diff, increased review burden, etc.

Proposal

The proposal consists of two parts:

  1. Add support for a new, permanently unstable -Zmir-enable-passes=+DestProp,-InstCombine flag. MIR passes currently specify their own behavior for when to be enabled; this flag would override that behavior. This also means it ignores -Zunsound-mir-opts and -Zmir-opt-level.

  2. Add a new header directive to MIR opt tests that looks something like this: // unit-test MyPassName. This would cause compiletest to emit -Zmir-opt-level=0, -Zmir-enable-passes=+MyPassName, and the remaining flags that it currently emits. The effect would be that the only optimization pass that runs is the named one. Non-optimization passes would of course still run.

    These tests will continue to use // EMIT-MIR annotations for their output. However, the meaningful set of annotations that could be used would basically be reduced to MyPassName.diff and MyPassName.after, since no other passes run.

    If a test requires other passes to run as well then such passes could additionally be specified with -Zmir-enable-passes flags via the compiler flags header directive. At some point in the future we may want to consider enabling some small set of passes by default, if it becomes common for other passes to depend on the MIR having been brought into some canonicalized state - I do not propose adding such a thing now.

Drawbacks and Alternatives

  1. This adds an additional requirement to the MIR pass manager that may impact our ability to refactor it in the future. If the logic for enabling/disabling passes becomes more complicated, there may be no simple way to implement the -Zmir-enable-passes flag. However, I believe that a concept of "MIR opt unit tests" will be necessary regardless of how the pass manager is implemented. I do not think that any pass manager which prevents such tests from existing without supplying an alternative would be a good idea.
  2. An MIR parser - either as in Implement a MIR parser for testing purposes rust#91669 or via some of the stable MIR work - might reduce the need for such a test mode. However, I do not think it would eliminate it - possibly it would even increase the need for such a test mode, due to "I wrote this MIR in the test file but another pass mangled it before it got to me."

Mentors or Reviewers

I am planning to implement these changes myself and do not expect to require significant mentoring to do so.

@nagisa has said that they would be willing to review. I also do not expect this to require particularly complex implementation though, so the review burden should not be too great.

Process

The main points of the Major Change Process are as follows:

  • File an issue describing the proposal.
  • A compiler team member or contributor who is knowledgeable in the area can second by writing @rustbot second.
    • Finding a "second" suffices for internal changes. If however, you are proposing a new public-facing feature, such as a -C flag, then full team check-off is required.
    • Compiler team members can initiate a check-off via @rfcbot fcp merge on either the MCP or the PR.
  • Once an MCP is seconded, the Final Comment Period begins. If no objections are raised after 10 days, the MCP is considered approved.

You can read more about Major Change Proposals on forge.

Comments

This issue is not meant to be used for technical discussion. There is a Zulip stream for that. Use this issue to leave procedural comments, such as volunteering to review, indicating that you second the proposal (or third, etc), or raising a concern that you would like to be addressed.

@JakobDegen JakobDegen added major-change A proposal to make a major change to rustc T-compiler Add this label so rfcbot knows to poll the compiler team labels Mar 27, 2022
@rustbot
Copy link
Collaborator

rustbot commented Mar 27, 2022

This issue is not meant to be used for technical discussion. There is a Zulip stream for that. Use this issue to leave procedural comments, such as volunteering to review, indicating that you second the proposal (or third, etc), or raising a concern that you would like to be addressed.

cc @rust-lang/compiler @rust-lang/compiler-contributors

@rustbot rustbot added the to-announce Announce this issue on triage meeting label Mar 27, 2022
@nagisa
Copy link
Member

nagisa commented Mar 28, 2022

@rustbot second

@rustbot rustbot added the final-comment-period The FCP has started, most (if not all) team members are in agreement label Mar 28, 2022
@apiraino apiraino removed the to-announce Announce this issue on triage meeting label Mar 31, 2022
@apiraino
Copy link
Contributor

@rustbot label -final-comment-period +major-change-accepted

@rustbot rustbot added major-change-accepted A major change proposal that was accepted to-announce Announce this issue on triage meeting and removed final-comment-period The FCP has started, most (if not all) team members are in agreement labels Apr 13, 2022
@apiraino apiraino removed the to-announce Announce this issue on triage meeting label Apr 21, 2022
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this issue Apr 24, 2022
Implement MIR opt unit tests

This implements rust-lang/compiler-team#502 .

There's not much to say here, this implementation does everything as proposed. I also added the flag to a bunch of existing tests (mostly those to which I could add it without causing huge diffs due to changes in line numbers). Summarizing the changes to test outputs:
 - Every time an `MirPatch` is created, it adds a cleanup block to the body if it did not exist already. If this block is unused (as is usually the case), it usually gets removed soon after by some pass calling `SimplifyCFG` for unrelated reasons (in many cases this cycle happens quite a few times for a single body). We now run `SimplifyCFG` less often, so those blocks end up in some of our outputs. I looked at changing `MirPatch` to not do this, but that seemed too complicated for this PR. I may still do that in a follow-up.
 - The `InstCombine` test had set `-C opt-level=0` in its flags and so there were no storage markers. I don't really see a good motivation for doing this, so bringing it back in line with what everything else does seems correct.
 - One of the `EarlyOtherwiseBranch` tests had `UnreachableProp` running on it. Preventing that kind of thing is the goal of this feature, so this seems fine.

For the remaining tests for which this feature might be useful, we can gradually migrate them as opportunities present themselves.

In terms of documentation, I plan on submitting a PR to the rustc dev guide in the near future documenting this and other recent changes to MIR. If there's any other places to update, do let me know

r? `@nagisa`
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
major-change A proposal to make a major change to rustc major-change-accepted A major change proposal that was accepted T-compiler Add this label so rfcbot knows to poll the compiler team
Projects
None yet
Development

No branches or pull requests

4 participants