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

Clarify semantics of SetDiscriminant and change enum deaggregation to match those semantics #94590

Closed

Conversation

JakobDegen
Copy link
Contributor

@JakobDegen JakobDegen commented Mar 4, 2022

This PR clarifies the semantics of the SetDiscriminant MIR statement. Quoting from the updated documentation:

If place is an ADT, this corresponds to the Rust code place = Variant(uninit, uninit, uninit). If each of the fields is initialized after the SetDiscriminant, the place is
completely initialized. Of course, you cannot initialize the fields first, as
SetDiscriminant invalidates them.

...

If place is a generator, then this invalidates only those fields which are not also
present in another variant. Those fields that are present in another variant are unchanged.

Benefits of this change

  1. The MaybeLiveLocals analysis was previously somewhat broken in that it marked locals killed on SetDiscriminant, although this was obviously not true for any fields that had been set previously. This change makes that decision completely justified, without requiring any changes to the code.
  2. Deaggregation of enums is now unambiguously non-lossy. Previously, deaggregation of enums would set both the fields and the discriminant - however, under some interpretations of the semantics of SetDiscriminant this would be lossy, since now possibly padding has to be preserved. With the new semantics, that is clearly and unambiguously not the case.
  3. In a future PR, we can start emitting SetDiscriminant for structs as well, with the same semantics. This will have the benefit of making deaggregation for structs also non-lossy.

This PR does not yet "weaponize" this change by changing codegen to make use of this information. Since the old version of SetDiscriminant is a valid implementation of the new version, the existing codegen should not have to change.

This PR

The changes in code and documentation are made in the first and second commit. This causes a couple mir-opt tests to break. The broken tests can be divided into three categories, which are addressed in commits 3, 4, and 5:

  1. Tests that were broken in the expected trivial way. All of these tests just had a SetDiscriminant statement move a couple lines up.
  2. Const prop used to optimize the last statement in
    (p as Variant).field = ...;
    SetDiscriminant(p) = Variant;
    q = discriminant(p);
    However, since the statements have been re-ordered, it can no longer do this optimization. Commit 4 blesses the MIR opt test that this broke.
  3. Finally, the SimplifyArmIdentity pass relied on the old ordering and no longer works with this change. However, I have already put up Fix SimplifyArmIdentity MIR opt #94177 , which re-writes this pass completely. That will also need to be adjusted after this PR, but I don't think it makes much sense to try and fix the old version of this pass, especially given that it does not run. Because of that, I have disabled the tests that were affected. I will be able to re-enable them in Fix SimplifyArmIdentity MIR opt #94177 . I could also attach that PR to this one, but I feel like these are each big enough as is.

I'm not sure if this requires a FCP from T-Compiler for the MIR semantics change. I'll leave the decision of who to cc and what the right procedure is up to the reviewer.

@rustbot rustbot added the T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. label Mar 4, 2022
@rust-highfive
Copy link
Collaborator

r? @nagisa

(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 Mar 4, 2022
compiler/rustc_mir_transform/src/prop_disc.rs Outdated Show resolved Hide resolved
compiler/rustc_middle/src/mir/mod.rs Outdated Show resolved Hide resolved
src/test/mir-opt/issue-73223.rs Show resolved Hide resolved
@nagisa
Copy link
Member

nagisa commented Mar 5, 2022

cc @rust-lang/wg-mir-opt

@JakobDegen
Copy link
Contributor Author

Last two commits are gone, CI is going to fail but I can fix that later depending on the results of perf. @nagisa can you start the run?

@tmiasko
Copy link
Contributor

tmiasko commented Mar 5, 2022

@bors try @rust-timer queue

@rust-timer
Copy link
Collaborator

Awaiting bors try build completion.

@rustbot label: +S-waiting-on-perf

@rustbot rustbot added the S-waiting-on-perf Status: Waiting on a perf run to be completed. label Mar 5, 2022
@bors
Copy link
Contributor

bors commented Mar 5, 2022

⌛ Trying commit 14f6cfb9d9b0b61cb8c9013b28b654a857f3afac with merge c055b10fc96f5cb03cd95d0257c65ca194dcc278...

@rust-log-analyzer

This comment has been minimized.

@bors
Copy link
Contributor

bors commented Mar 5, 2022

☀️ Try build successful - checks-actions
Build commit: c055b10fc96f5cb03cd95d0257c65ca194dcc278 (c055b10fc96f5cb03cd95d0257c65ca194dcc278)

@rust-timer
Copy link
Collaborator

Queued c055b10fc96f5cb03cd95d0257c65ca194dcc278 with parent ab2bd41, future comparison URL.

@rust-timer
Copy link
Collaborator

Finished benchmarking commit (c055b10fc96f5cb03cd95d0257c65ca194dcc278): comparison url.

Summary: This benchmark run did not return any relevant results.

If you disagree with this performance assessment, please file an issue in rust-lang/rustc-perf.

Benchmarking this pull request likely means that it is perf-sensitive, so we're automatically marking it as not fit for rolling up. While you can manually mark this PR as fit for rollup, we strongly recommend not doing so since this PR led to changes in compiler perf.

@bors rollup=never
@rustbot label: +S-waiting-on-review -S-waiting-on-perf -perf-regression

@rustbot rustbot removed the S-waiting-on-perf Status: Waiting on a perf run to be completed. label Mar 6, 2022
…ore precisely.

The changed semantics also make one analysis work better as written, so we remove the documentation
in it that is now out of date.
This test had some regressions due to the change in enum deaggregation. For now we accept these, as
they do not show up on perf, and hope that future improvements can recover the previous result.
All of these tests are directly or indirectly broken by the `simplify-arm` and `simplify-branch`
optimizations no longer firing. Unfortunately, this is a non-trivial thing to fix. Furthermore,
there is an existing open PR that completely re-writes the `simplify-arm` optimization. As such,
it doesn't make sense to try and fix the soon-to-be-replaced pass.
@JakobDegen
Copy link
Contributor Author

Extra optimization pass is gone. One test blessed with a note that improvements to ConstProp should fix it. I've also pointed out in the documentation that there is a difference between ADTs and generators, and that SetDiscriminant potentially applies to both.

@JakobDegen
Copy link
Contributor Author

The additional commit modifies const eval to implement these changes, and adds a test that detects UB which we did not detect before.

@JakobDegen
Copy link
Contributor Author

I believe the remaining concerns here have been addressed. I brought the issue about the difference between ADTs and generators up on Zulip, where I suggested that in the future we replace SetDiscriminant on generators with a .discriminant field projection. If this is still too great a concern, we can delay this change until then

@@ -14,7 +14,8 @@ type R = Result<u64, i32>;
#[no_mangle]
pub fn try_identity(x: R) -> R {
// CHECK: start:
// CHECK-NOT: br {{.*}}
// FIXME(JakobDegen CHECK-NOT): br {{.*}} . This test was broken by changes to enum deaggregation,
Copy link
Member

Choose a reason for hiding this comment

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

All of these should get an issue filed, though more generally this test in particular seems quite awkward to me, given that it relies on -Zunsound-mir-opts...

@bors
Copy link
Contributor

bors commented Mar 31, 2022

☔ The latest upstream changes (presumably #95506) made this pull request unmergeable. Please resolve the merge conflicts.

@JakobDegen
Copy link
Contributor Author

Closing in favor of something like #95125

@JakobDegen JakobDegen closed this Apr 1, 2022
bors added a commit to rust-lang-ci/rust that referenced this pull request Apr 11, 2022
…li-obk

Add new `Deinit` statement

This rvalue replaces `SetDiscriminant` for ADTs. This PR is an alternative to rust-lang#94590 , which only specifies that the behavior of `SetDiscriminant` is the same as what this rvalue would do. The motivation for this change are discussed in that PR and [on Zulip](https://rust-lang.zulipchat.com/#narrow/stream/189540-t-compiler.2Fwg-mir-opt/topic/SetDiscriminant.20and.20aggregate.20initialization.20.2394590)

r? `@oli-obk`
@JakobDegen JakobDegen deleted the change-enum-deaggregate branch April 11, 2022 20:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. 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.

9 participants