-
Notifications
You must be signed in to change notification settings - Fork 14k
GVN: Support unions. #146355
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
GVN: Support unions. #146355
Conversation
|
@bors try @rust-timer queue |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
Finished benchmarking commit (366a987): comparison URL. Overall result: ❌✅ regressions and improvements - no action neededBenchmarking this pull request means it may be perf-sensitive – we'll automatically label it not fit for rolling up. You can override this, but we strongly advise not to, due to possible changes in compiler perf. @bors rollup=never Instruction countOur most reliable metric. Used to determine the overall result above. However, even this metric can be noisy.
Max RSS (memory usage)Results (primary 2.9%, secondary 2.5%)A less reliable metric. May be of interest, but not used to determine the overall result above.
CyclesResults (secondary 2.8%)A less reliable metric. May be of interest, but not used to determine the overall result above.
Binary sizeResults (primary 0.1%)A less reliable metric. May be of interest, but not used to determine the overall result above.
Bootstrap: 467.433s -> 467.12s (-0.07%) |
|
Some changes occurred to MIR optimizations cc @rust-lang/wg-mir-opt |
|
r? compiler |
|
@bors r+ |
GVN: Support unions. Supporting union values is not very hard, and allows to const-prop them. r? `@ghost` for perf
This comment has been minimized.
This comment has been minimized.
|
💔 Test failed - checks-actions |
This comment has been minimized.
This comment has been minimized.
|
@bors r=jackh726 |
|
This PR was rebased onto a different master commit. Here's a range-diff highlighting what actually changed. Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers. |
|
☀️ Test successful - checks-actions |
What is this?This is an experimental post-merge analysis report that shows differences in test outcomes between the merged PR and its parent PR.Comparing 68ad253 (parent) -> ff5be13 (this PR) Test differencesShow 6 test diffsStage 1
Stage 2
Additionally, 2 doctest diffs were found. These are ignored, as they are noisy. Job group index
Test dashboardRun cargo run --manifest-path src/ci/citool/Cargo.toml -- \
test-dashboard ff5be13e2d9f398c38215958021e4c7970f88914 --output-dir test-dashboardAnd then open Job duration changes
How to interpret the job duration changes?Job durations can vary a lot, based on the actual runner instance |
|
Finished benchmarking commit (ff5be13): comparison URL. Overall result: ❌ regressions - no action needed@rustbot label: -perf-regression Instruction countOur most reliable metric. Used to determine the overall result above. However, even this metric can be noisy.
Max RSS (memory usage)Results (primary -2.4%, secondary -0.3%)A less reliable metric. May be of interest, but not used to determine the overall result above.
CyclesResults (secondary 1.9%)A less reliable metric. May be of interest, but not used to determine the overall result above.
Binary sizeResults (primary 0.1%)A less reliable metric. May be of interest, but not used to determine the overall result above.
Bootstrap: 473.761s -> 473.87s (0.02%) |
|
What exactly does this assume about unions? I see something involving an "active field" and my alarm bells go off; unions in Rust do not have a notion of active field, they are basically just syntactic sugar for transmutes. |
|
The two simplifications we perform are:
We do no assume any behaviour if the projection field is not the construction field. For the "active" terminology, I saw it inside rustc, so I thought it ok. |
|
Okay, that sounds good, thanks.
|
| /// A union aggregate value. | ||
| Union(FieldIdx, VnIndex), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cc @saethlin -- I wonder if you can use this to solve your uninit-array problem now that GVN tracks unions?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. Working on it.
Fix MaybeUninit codegen using GVN This is an alternative to #142837, based on #146355 (comment). The general approach I took here is to aggressively propagate anything that is entirely uninitialized. GVN generally takes the approach of only synthesizing small types, but we need to generate large consts to fix the codegen issue. I also added a special case to MIR dumps for this where now an entirely uninit const is printed as `const <uninit>`, because otherwise we end up with extremely verbose dumps of the new consts. After GVN though, we still end up with a lot of MIR that looks like this: ``` StorageLive(_1); _1 = const <uninit>; _2 = &raw mut _1; ``` Which will break tests/codegen-llvm/maybeuninit-rvo.rs with the naive lowering. I think the ideal fix here is to somehow omit these `_1 = const <uninit>` assignments that come directly after a StorageLive, but I'm not sure how to do that. For now at least, ignoring such assignments (even if they don't come right after a StorageLive) in codegen seems to work. Note that since GVN is based on synthesizing a `ConstValue` which has a defined layout, this scenario still gets deoptimized by LLVM. ```rust #![feature(rustc_attrs)] #![crate_type = "lib"] use std::mem::MaybeUninit; #[unsafe(no_mangle)] pub fn oof() -> [[MaybeUninit<u8>; 8]; 8] { #[rustc_no_mir_inline] pub fn inner<T: Copy>() -> [[MaybeUninit<T>; 8]; 8] { [[MaybeUninit::uninit(); 8]; 8] } inner() } ``` This case can be handled correctly if enough inlining has happened, or it could be handled by post-mono GVN. Synthesizing `UnevaluatedConst` or some other special kind of const seems dubious.
…cottmcm Fix MaybeUninit codegen using GVN This is an alternative to rust-lang#142837, based on rust-lang#146355 (comment). The general approach I took here is to aggressively propagate anything that is entirely uninitialized. GVN generally takes the approach of only synthesizing small types, but we need to generate large consts to fix the codegen issue. I also added a special case to MIR dumps for this where now an entirely uninit const is printed as `const <uninit>`, because otherwise we end up with extremely verbose dumps of the new consts. After GVN though, we still end up with a lot of MIR that looks like this: ``` StorageLive(_1); _1 = const <uninit>; _2 = &raw mut _1; ``` Which will break tests/codegen-llvm/maybeuninit-rvo.rs with the naive lowering. I think the ideal fix here is to somehow omit these `_1 = const <uninit>` assignments that come directly after a StorageLive, but I'm not sure how to do that. For now at least, ignoring such assignments (even if they don't come right after a StorageLive) in codegen seems to work. Note that since GVN is based on synthesizing a `ConstValue` which has a defined layout, this scenario still gets deoptimized by LLVM. ```rust #![feature(rustc_attrs)] #![crate_type = "lib"] use std::mem::MaybeUninit; #[unsafe(no_mangle)] pub fn oof() -> [[MaybeUninit<u8>; 8]; 8] { #[rustc_no_mir_inline] pub fn inner<T: Copy>() -> [[MaybeUninit<T>; 8]; 8] { [[MaybeUninit::uninit(); 8]; 8] } inner() } ``` This case can be handled correctly if enough inlining has happened, or it could be handled by post-mono GVN. Synthesizing `UnevaluatedConst` or some other special kind of const seems dubious.
Fix MaybeUninit codegen using GVN This is an alternative to #142837, based on #146355 (comment). The general approach I took here is to aggressively propagate anything that is entirely uninitialized. GVN generally takes the approach of only synthesizing small types, but we need to generate large consts to fix the codegen issue. I also added a special case to MIR dumps for this where now an entirely uninit const is printed as `const <uninit>`, because otherwise we end up with extremely verbose dumps of the new consts. After GVN though, we still end up with a lot of MIR that looks like this: ``` StorageLive(_1); _1 = const <uninit>; _2 = &raw mut _1; ``` Which will break tests/codegen-llvm/maybeuninit-rvo.rs with the naive lowering. I think the ideal fix here is to somehow omit these `_1 = const <uninit>` assignments that come directly after a StorageLive, but I'm not sure how to do that. For now at least, ignoring such assignments (even if they don't come right after a StorageLive) in codegen seems to work. Note that since GVN is based on synthesizing a `ConstValue` which has a defined layout, this scenario still gets deoptimized by LLVM. ```rust #![feature(rustc_attrs)] #![crate_type = "lib"] use std::mem::MaybeUninit; #[unsafe(no_mangle)] pub fn oof() -> [[MaybeUninit<u8>; 8]; 8] { #[rustc_no_mir_inline] pub fn inner<T: Copy>() -> [[MaybeUninit<T>; 8]; 8] { [[MaybeUninit::uninit(); 8]; 8] } inner() } ``` This case can be handled correctly if enough inlining has happened, or it could be handled by post-mono GVN. Synthesizing `UnevaluatedConst` or some other special kind of const seems dubious.
Fix MaybeUninit codegen using GVN This is an alternative to rust-lang/rust#142837, based on rust-lang/rust#146355 (comment). The general approach I took here is to aggressively propagate anything that is entirely uninitialized. GVN generally takes the approach of only synthesizing small types, but we need to generate large consts to fix the codegen issue. I also added a special case to MIR dumps for this where now an entirely uninit const is printed as `const <uninit>`, because otherwise we end up with extremely verbose dumps of the new consts. After GVN though, we still end up with a lot of MIR that looks like this: ``` StorageLive(_1); _1 = const <uninit>; _2 = &raw mut _1; ``` Which will break tests/codegen-llvm/maybeuninit-rvo.rs with the naive lowering. I think the ideal fix here is to somehow omit these `_1 = const <uninit>` assignments that come directly after a StorageLive, but I'm not sure how to do that. For now at least, ignoring such assignments (even if they don't come right after a StorageLive) in codegen seems to work. Note that since GVN is based on synthesizing a `ConstValue` which has a defined layout, this scenario still gets deoptimized by LLVM. ```rust #![feature(rustc_attrs)] #![crate_type = "lib"] use std::mem::MaybeUninit; #[unsafe(no_mangle)] pub fn oof() -> [[MaybeUninit<u8>; 8]; 8] { #[rustc_no_mir_inline] pub fn inner<T: Copy>() -> [[MaybeUninit<T>; 8]; 8] { [[MaybeUninit::uninit(); 8]; 8] } inner() } ``` This case can be handled correctly if enough inlining has happened, or it could be handled by post-mono GVN. Synthesizing `UnevaluatedConst` or some other special kind of const seems dubious.
Fix MaybeUninit codegen using GVN This is an alternative to rust-lang/rust#142837, based on rust-lang/rust#146355 (comment). The general approach I took here is to aggressively propagate anything that is entirely uninitialized. GVN generally takes the approach of only synthesizing small types, but we need to generate large consts to fix the codegen issue. I also added a special case to MIR dumps for this where now an entirely uninit const is printed as `const <uninit>`, because otherwise we end up with extremely verbose dumps of the new consts. After GVN though, we still end up with a lot of MIR that looks like this: ``` StorageLive(_1); _1 = const <uninit>; _2 = &raw mut _1; ``` Which will break tests/codegen-llvm/maybeuninit-rvo.rs with the naive lowering. I think the ideal fix here is to somehow omit these `_1 = const <uninit>` assignments that come directly after a StorageLive, but I'm not sure how to do that. For now at least, ignoring such assignments (even if they don't come right after a StorageLive) in codegen seems to work. Note that since GVN is based on synthesizing a `ConstValue` which has a defined layout, this scenario still gets deoptimized by LLVM. ```rust #![feature(rustc_attrs)] #![crate_type = "lib"] use std::mem::MaybeUninit; #[unsafe(no_mangle)] pub fn oof() -> [[MaybeUninit<u8>; 8]; 8] { #[rustc_no_mir_inline] pub fn inner<T: Copy>() -> [[MaybeUninit<T>; 8]; 8] { [[MaybeUninit::uninit(); 8]; 8] } inner() } ``` This case can be handled correctly if enough inlining has happened, or it could be handled by post-mono GVN. Synthesizing `UnevaluatedConst` or some other special kind of const seems dubious.
Supporting union values is not very hard, and allows to const-prop them.
r? @ghost for perf