-
Notifications
You must be signed in to change notification settings - Fork 13.5k
Simplify discriminant codegen for niche-encoded variants which don't wrap across an integer boundary #143784
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
base: master
Are you sure you want to change the base?
Conversation
These are from 139729, updated to pass on master.
Some changes occurred in compiler/rustc_codegen_ssa |
// CHECK: %[[A_REL_DISCR:.+]] = xor i8 %a, -128 | ||
// CHECK: %[[A_IS_NICHE:.+]] = icmp ult i8 %[[A_REL_DISCR]], 3 | ||
// CHECK: %[[A_IS_NICHE:.+]] = icmp slt i8 %a, 0 |
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.
ascii::Char
also makes a nice demo here. "Is it one of the variants that's not an ascii::Char
" with this PR is phrased as the obvious SLT(a, 0)
, rather than the previous ULT(XOR(a, -128), 3)
.
This comment has been minimized.
This comment has been minimized.
7ccf81a
to
da52d97
Compare
This comment has been minimized.
This comment has been minimized.
da52d97
to
400c6a7
Compare
This comment has been minimized.
This comment has been minimized.
400c6a7
to
d5bcfb3
Compare
@bors try @rust-timer queue |
This comment has been minimized.
This comment has been minimized.
Simplify codegen for niche-encoded variant tests Inspired by #139729, this attempts to be a much-simpler and more-localized change while still making a difference. (Specifically, this does not try to solve the problem with select-sinking, leaving that to be fixed by llvm/llvm-project#134024 -- once it gets released -- instead of in rustc's codegen.) What this *does* improve is checking for the variant in a 3+ variant enum when that variant is the type providing the niche. Something like `if let Foo::WithBool(_) = ...` previously compiled to `ugt(add(x, -2), 2)`, which is non-trivial to think about because it's depending on the unsigned wrapping to shift the 0/1 up above 2. With this PR it compiles to just `ult(x, 2)`, which is probably what you'd have written yourself if you were doing it by hand to look for "is this byte a bool?". That's done by leaving most of the codegen alone, but adding a couple new special cases to the `is_niche` check. The default looks at the relative discriminant, but in the common cases where there's no wraparound involved, we can just check the original value, rather than the offsetted one. The first commit just adds some tests, so the best way to see the effect of this change is to look at the second commit and [how it updates the test expectations](da52d97#diff-14bab05dc3e3448a531a97fafed38bf775095cc68f7997af1721a4c3dc58eb47R218-R223).
☀️ Try build successful - checks-actions |
This comment has been minimized.
This comment has been minimized.
Finished benchmarking commit (4f0f4c7): comparison URL. Overall result: ❌✅ regressions and improvements - please read the text belowBenchmarking 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. Next Steps: If you can justify the regressions found in this try perf run, please do so in sufficient writing along with @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)This benchmark run did not return any relevant results for this metric. CyclesThis benchmark run did not return any relevant results for this metric. Binary sizeResults (primary -0.0%, secondary -0.2%)A less reliable metric. May be of interest, but not used to determine the overall result above.
Bootstrap: 464.174s -> 465.167s (0.21%) |
At first glance those perf numbers are mixed, but I think they're actually pretty good.
|
If you can wait, I can take a look at it this week. |
No rush, @dianqk -- this week would be great. |
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.
The first commit just adds some tests, so the best way to see the effect of this change is to look at the second commit and how it updates the test expectations.
Nits: This link is no longer valid, so maybe just remove it.
How about we mention non-wrapping ranges in the title?
Then r=me. Nice improvements!
@@ -511,35 +512,44 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { | |||
// } else { | |||
// untagged_variant | |||
// } | |||
let niche_start = bx.cx().const_uint_big(tag_llty, niche_start); | |||
let is_niche = bx.icmp(IntPredicate::IntEQ, tag, niche_start); | |||
let is_niche = bx.icmp(IntPredicate::IntEQ, tag, niche_start_const); | |||
let tagged_discr = | |||
bx.cx().const_uint(cast_to, niche_variants.start().as_u32() as u64); | |||
(is_niche, tagged_discr, 0) | |||
} else { | |||
// The special cases don't apply, so we'll have to go with | |||
// the general algorithm. |
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.
Should the comment be repositioned?
let ne = bx.icmp(IntPredicate::IntNE, relative_discr, impossible); | ||
bx.assume(ne); | ||
} | ||
let is_niche = if tag_range.no_unsigned_wraparound(tag_size) == Ok(true) { |
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.
Can you add some description of the special case here? Does a diagram like this make sense?
// niche_start niche_end
// | |
// v v
// 0u8----------+--------------------------------+----------255u8
// ^ | is niche |
// | +--------------------------------+
// | |
// tag_range.start tag_range.end
@bors r=dianqk |
🌲 The tree is currently closed for pull requests below priority 100. This pull request will be tested once the tree is reopened. |
Inspired by #139729, this attempts to be a much-simpler and more-localized change while still making a difference. (Specifically, this does not try to solve the problem with select-sinking, leaving that to be fixed by llvm/llvm-project#134024 -- once it gets released -- instead of in rustc's codegen.)
What this does improve is checking for the variant in a 3+ variant enum when that variant is the type providing the niche. Something like
if let Foo::WithBool(_) = ...
previously compiled tougt(add(x, -2), 2)
, which is non-trivial to think about because it's depending on the unsigned wrapping to shift the 0/1 up above 2. With this PR it compiles to justult(x, 2)
, which is probably what you'd have written yourself if you were doing it by hand to look for "is this byte a bool?".That's done by leaving most of the codegen alone, but adding a couple new special cases to the
is_niche
check. The default looks at the relative discriminant, but in the common cases where there's no wraparound involved, we can just check the original value, rather than the offsetted one.The first commit just adds some tests, so the best way to see the effect of this change is to look at the second commit and how it updates the test expectations.