-
Notifications
You must be signed in to change notification settings - Fork 13.3k
use stores of the correct size to set discriminants #131698
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
Conversation
036b79a
to
e7b2ca9
Compare
CC @adwinwhite |
If this changes what codegen does, it should come with ui tests and/or codegen tests ensuring we don't regress this in the future. |
☔ The latest upstream changes (presumably #132581) made this pull request unmergeable. Please resolve the merge conflicts. |
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.
r=me after rebase + test
e7b2ca9
to
1b80892
Compare
}; | ||
let max = niche.layout.size.unsigned_int_max(); | ||
let wrapped = niche_value & max; |
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.
let wrapped = niche_value & max; | |
// We used u128 arithmetic above, so we have to get this back in-bounds. | |
let wrapped = niche_value & max; |
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.
Added a more detailed comment.
r=me with a comment added (assuming the comment is correct) |
1b80892
to
aec5b53
Compare
I was waffling between making the test a build-pass (just checking codegen no longer ices) or run-pass. I moved to the latter and added some more asserts. @bors r=RalfJung,estebank rollup |
This comment was marked as duplicate.
This comment was marked as duplicate.
aec5b53
to
cca2e96
Compare
@bors r=RalfJung,estebank rollup |
cca2e96
to
b8d4b75
Compare
And then I forgot to commit the changes 😔 @bors r=RalfJung,estebank |
}; | ||
let max = niche.layout.size.unsigned_int_max(); | ||
// Niche ranges that wrap around may be represented as out-of-range values | ||
// e.g. niche at 0u8 may end up being u8::MAX + 1. |
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.
I don't think that's true? AFAIK our niche_start
must always be inbounds of the scalar type they refer to. However, above you are doing u128
arithmetic so even if the niche range endpoints are inbounds, your niche_value
is not.
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.
niche_start is inbounds, but niche_start + niche_value might not. And the result was passed as such to the backend, i.e. I have seen 256 passed to llvm for a repr(i8) enum via const_uint_big
.
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.
niche_start + niche_value
ought to be computed wrapping on the type of the niche field. But the code here takes a shortcut, by doing u128
arithmetic instead. That is why it can go out-of-bounds.
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.
niche_start + niche_value ought to be computed wrapping on the type of the niche field
If that were the case then it would have been buggy for regular enums. Note that I did not change the calculation and the out of range value was passed to the backend before. This worked for integers. What I'm fixing is not that case but that llvm didn't like them for pointers.
fn const_uint_big(&self, t: &'ll Type, u: u128) -> &'ll Value {
debug_assert!(
self.type_kind(t) == TypeKind::Integer,
"only allows integer types in const_uint_big"
);
unsafe {
let words = [u as u64, (u >> 64) as u64];
llvm::LLVMConstIntOfArbitraryPrecision(t, 2, words.as_ptr())
}
}
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.
And the result was passed as such to the backend, i.e. I have seen 256 passed to llvm for a repr(i8) enum via const_uint_big.
If that worked before, that means LLVM has been doing the truncation for integers. It just didn't like doing that for pointers, I guess.
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.
What I don't understand is why you think my comment is incorrect.
We do calculate out of bound values. The backend accepts out of bound values in the common case. So we could just pass them through, as we did before. Ranges that wrap around resulting in out of bounds values is exactly what happens.
The only reason to do the wrapping ourselves is the special case that's currently only reachable via unstable attributes.
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.
This calculates the niche value we tell the backend to set. Not the value we use internally to represent the niche.
The value we tell the backend can go out of bounds due to truncation in the backend.
I could have special-cased this to just do the wrapping outselves for pointers. But feels silly. Since they're equivalent I do it for integers too. But that's not a necessary property of the code.
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.
Would this be better?
The calculated niche_value may end up being out of bounds. This would be fine for integer types since such integer constants do get truncated by the backend to fit the type. But to also cover pointer types we always do it ourselves.
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.
I think your comment is misleading. The reason the value can be out-of-bounds is that it wasn't computed the right way. Or rather, it wasn't yet fully computed. The comment occurs half-way through the computation.
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.
I don't see why we would talk about the backend truncation behavior... it's a bit unclean to rely on that anyway (reasonably a backend could complain if we build an i8
literal of value 256), and we are not relying on it any more with this PR.
@bors r- That is a substantially different comment than what I suggested, so we have to figure out which comment is correct here. |
@@ -387,13 +388,21 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { | |||
let niche_llty = bx.cx().immediate_backend_type(niche.layout); | |||
let niche_value = variant_index.as_u32() - niche_variants.start().as_u32(); | |||
let niche_value = (niche_value as u128).wrapping_add(niche_start); |
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.
let niche_value = (niche_value as u128).wrapping_add(niche_start); | |
// We are supposed to compute `niche_value.wrapping_add(niche_start)` wrapping | |
// around the `niche`'s type. | |
// The easiest way to do that is to do wrapping arithmetic on `u128` and then | |
// masking off any extra bits that occur because we did the arithmetic with too many bits. | |
let niche_value = (niche_value as u128).wrapping_add(niche_start); | |
let niche_value = niche_value & niche.layout.size.unsigned_int_max(); |
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.
Turns out it can be signed, but the logic should be right even for that case.
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.
M'kay, applied.
b8d4b75
to
26d7b5d
Compare
Thanks! @bors r+ |
…ck, r=RalfJung use stores of the correct size to set discriminants Resolves an old HACK /FIXME. Note that I haven't worked much with codegen so I'm not sure if I'm using the functions correctly and I was surprised seeing out-of-range values being fed into `const_uint_big` but apparently they're wrapped implicitly? By making it explicit we can pass in-range values instead.
Rollup of 6 pull requests Successful merges: - rust-lang#131698 (use stores of the correct size to set discriminants) - rust-lang#133571 (Mark visionOS as supporting `std`) - rust-lang#133655 (Eliminate print_expr_maybe_paren function from pretty printers) - rust-lang#133667 (Remove unused code) - rust-lang#133670 (bump hashbrown version) - rust-lang#133673 (replace hard coded error id with `ErrorKind::DirectoryNotEmpty`) r? `@ghost` `@rustbot` modify labels: rollup
Rollup merge of rust-lang#131698 - the8472:remove-set-discriminant-hack, r=RalfJung use stores of the correct size to set discriminants Resolves an old HACK /FIXME. Note that I haven't worked much with codegen so I'm not sure if I'm using the functions correctly and I was surprised seeing out-of-range values being fed into `const_uint_big` but apparently they're wrapped implicitly? By making it explicit we can pass in-range values instead.
Rollup of 6 pull requests Successful merges: - rust-lang#131698 (use stores of the correct size to set discriminants) - rust-lang#133571 (Mark visionOS as supporting `std`) - rust-lang#133655 (Eliminate print_expr_maybe_paren function from pretty printers) - rust-lang#133667 (Remove unused code) - rust-lang#133670 (bump hashbrown version) - rust-lang#133673 (replace hard coded error id with `ErrorKind::DirectoryNotEmpty`) r? `@ghost` `@rustbot` modify labels: rollup
Resolves an old HACK /FIXME.
Note that I haven't worked much with codegen so I'm not sure if I'm using the functions correctly and I was surprised seeing out-of-range values being fed into
const_uint_big
but apparently they're wrapped implicitly? By making it explicit we can pass in-range values instead.