-
Notifications
You must be signed in to change notification settings - Fork 12.8k
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
Mark other variants as uninitialized after switch on discriminant #68528
Conversation
The job Click to expand the log.
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 |
Just to see how slow this makes dataflow: @bors try |
Awaiting bors try build completion |
⌛ Trying commit 679b4238e793c197eacfe43b7fbc4781e948c36b with merge 3828cd570d1515093538246582353d44c84220db... |
☀️ Try build successful - checks-azure |
Queued 3828cd570d1515093538246582353d44c84220db with parent 8ad83af, future comparison URL. |
Finished benchmarking try commit 3828cd570d1515093538246582353d44c84220db, comparison URL. |
679b423
to
175fd0b
Compare
This comment has been minimized.
This comment has been minimized.
aa5dc91
to
64b1424
Compare
@bors try |
Awaiting bors try build completion |
⌛ Trying commit 64b1424dfbf7edd2d3b0e2190fbd85bb93753d8c with merge 0077a7aa11ebc2462851676f9f464d5221b17d6a... |
☀️ Try build successful - checks-azure |
Queued 0077a7aa11ebc2462851676f9f464d5221b17d6a with parent d55f3e9, future comparison URL. |
Finished benchmarking try commit 0077a7aa11ebc2462851676f9f464d5221b17d6a, comparison URL. |
This reduces the amount of time spent in LLVM. For incremental builds is also reduces the amount of time spent in |
@bjorn3 I added a summary of the changes to the OP, along with an explanation of the perf results for builds that don't involve codegen. They are indeed made slightly slower by this PR. A 10% improvement for |
Since I suggested this approach, I'd rather someone else review: |
📣 Toolstate changed by #68528! Tested on commit 49c68bd. 💔 book on windows: test-pass → test-fail (cc @carols10cents @steveklabnik). |
Tested on commit rust-lang/rust@49c68bd. Direct link to PR: <rust-lang/rust#68528> 💔 book on windows: test-pass → test-fail (cc @carols10cents @steveklabnik).
…s, r=matthewjasper Skip `Drop` terminators for enum variants without drop glue Split out from #68528. When doing drop elaboration for an `enum` that may or may not be moved out of (an open drop), we check the discriminant of the `enum` to see whether the live variant has any drop flags and then check the drop flags to see whether we need to drop each field. Sometimes, however, the live variant has no move paths and thus no drop flags. In this case, we still emit a drop terminator for the entire enum after checking the enum discriminant. This drop shim will check the discriminant of the enum *again* and then drop the fields of the active variant. If the active variant has no drop glue, nothing will be done. This commit skips emitting the drop terminator during drop elaboration when the "otherwise" variants, those without move paths, have no drop glue. A common example of this scenario is when an `Option` is moved from, since `Option::None` never needs drop glue. Below is a fragment the pre-codegen CFG for `Option::unwrap_or` in which we check the drop flag (`_5`) for `self` (`_1`), before and after the change. Before: ![image](https://user-images.githubusercontent.com/29463364/74078927-52942380-49e5-11ea-8e34-4b9d6d94ef25.png) After: ![image](https://user-images.githubusercontent.com/29463364/74078945-78b9c380-49e5-11ea-8302-b043c4a7515a.png) This change doesn't do much on its own, but it is a prerequisite to get the perf gains from #68528. cc @arielb1
…=oli-obk Handle inactive enum variants in `MaybeUninitializedPlaces` Resolves the first part of rust-lang#69715. This is the equivalent of rust-lang#68528 but for `MaybeUninitializedPlaces`. Because we now notify drop elaboration that inactive enum variants might be uninitialized, some drops get marked as ["open" that were previously "static"](https://github.com/rust-lang/rust/blob/e0e5d82e1677c82d209b214bbfc2cc5705c2336a/src/librustc_mir/transform/elaborate_drops.rs#L191). Unlike in rust-lang#69715, this isn't strictly better: An "open" drop expands to more MIR than a simple call to the drop shim. However, because drop elaboration considers each field of an "open" drop separately, it can sometimes eliminate unnecessary drops of moved-from or unit-like enum variants. This is the case for `Option::unwrap`, which is reflected in the `mir-opt` test. cc @eddyb r? @oli-obk
…=jonas-schievink Replace `discriminant_switch_effect` with more general version rust-lang#68528 added a new edge-specific effect for `SwitchInt` terminators, `discriminant_switch_effect`, to the dataflow framework. While this accomplished the short-term goal of making drop elaboration more precise, it wasn't really useful in other contexts: It only supported `SwitchInt`s on the discriminant of an `enum` and did not allow effects to be applied along the "otherwise" branch. In const-propagation, for example, arbitrary edge-specific effects for the targets of a `SwitchInt` can be used to remember the value a `match` scrutinee must have in each arm. This PR replaces `discriminant_switch_effect` with a more general `switch_int_edge_effects` method. The new method has a slightly different interface from the other edge-specific effect methods (e.g. `call_return_effect`). This divergence is explained in the new method's documentation, and reading the changes to the various dataflow impls as well as `direction.rs` should further clarify things. This PR should not change behavior.
During drop elaboration, which builds the drop ladder that handles destruction during stack unwinding, we attempt to remove MIR
Drop
terminators that will never be reached in practice. This reduces the number of basic blocks that are passed to LLVM, which should improve performance. In #66753, a user pointed out that unreachableDrop
terminators are common in functions likeOption::unwrap
, which move out of anenum
. While discussing possible remedies for that issue, @eddyb suggested moving const-checking after drop elaboration. This would allow the former, which looks forDrop
terminators and replicates a small amount of drop elaboration to determine whether a dropped local has been moved out, leverage the work done by the latter.However, it turns out that drop elaboration is not as precise as it could be when it comes to eliminating useless drop terminators. For example, let's look at the code for
unwrap_or
.opt
never needs to be dropped, since it is either moved out of (if it isSome
) or has no drop glue (if it isNone
), anddefault
only needs to be dropped ifopt
isSome
. This is not reflected in the MIR we currently pass to codegen.@eddyb also suggested the solution to this problem. When we switch on an enum discriminant, we should be marking all fields in other variants as definitely uninitialized. I implemented this on top of alongside a small optimization (split out into #68943) that suppresses drop terminators for enum variants with no fields (e.g.
Option::None
). This is the resulting MIR forunwrap_or
.In concert with #68943, this change speeds up many optimized and debug builds. We need to carefully investigate whether I have introduced any miscompilations before merging this. Code that never drops anything would be very fast indeed until memory is exhausted.