-
Notifications
You must be signed in to change notification settings - Fork 13.3k
Adjust the alignment when passing a niche as a pointer #131739
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
cdf9a48
to
d910764
Compare
Interesting. Perhaps another option would be keeping the align and teaching the niche logic about bit masks. Or emit an error when And what about the |
I've been trying to get my head around this. The zero niche is special, because if we do use the forbidden value for another enum variant, that enum variant's bit pattern will still be aligned. Zero is still aligned. But there are other values that are still aligned. I think handling the general case would actually make it easier to understand this code. So what I'd like to see is instead of special-casing zero, check if:
Can you implement that? |
I’m not sure, it might be worth a try. Introducing additional instructions could make things worse.
Maybe not. This seems more like the address space restrictions we manually annotate.
It's ok with me. According to the semantic of dereferenceable(), this is only valid for load instructions.
|
r? saethlin |
My understanding is that this allows LLVM to insert spurious loads. Which would then violate the "risk of trapping" clause if we used those for niches instead of real allocations. |
Ah, I have checked again. We should drop |
d910764
to
759f333
Compare
I have expanded it to more general. |
I have created an issue #131834 for that. |
759f333
to
6238a57
Compare
6238a57
to
7bc5a39
Compare
compiler/rustc_abi/src/lib.rs
Outdated
@@ -1489,6 +1489,29 @@ pub enum Variants<FieldIdx: Idx, VariantIdx: Idx> { | |||
}, | |||
} | |||
|
|||
impl<FieldIdx: Idx, VariantIdx: Idx> Variants<FieldIdx, VariantIdx> { | |||
// Returns all used niche values. |
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 is a used niche value? I think a niche by definition is a value that must not be used, so that combination of words is confusing. Is this an iterator over the discriminants?
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, it iterates the discriminant and returns the corresponding niche.
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.
But this is returning a single value per variant, and niches are at least a range. And this is based on the discriminant start, so I'm pretty sure this just returns discriminants.
Then we fold these using restrict_for_offset
? The values we're passing to that function aren't offsets. Does that function just so happen to implement the arithmetic that we need?
I think I'm going to try to work through what this does with pencil and paper, because I feel like the math works out in your implementation, but I still don't think I can see how.
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.
IIUC, a variant corresponds to a niche. I convert to a discriminant(variant_idx
) to a niche by (d - niche_variants.start).wrapping_add(niche_start)
, so this returns an iterator for all niches.
Then we pass a niche as a pointer, the max alignment of a niche is max_for_offset(niche)
. For example:
- the max alignment of
8
is8
- the max alignment of
24
(0b11000
) is8
- the max alignment of
26
(0b11010
) is2
In order for the alignment to be legal, we must choose the min alignment and restrict_for_offset
is I want.
7bc5a39
to
fef7d19
Compare
Maybe ping? |
Is this PR related to #131834 ? There is no link in either direction so I have to assume they are completely unrelated, but they look very related. Please always add links to related issues / PRs, that's a crucial part of being able to follow what happens in rustc development, and making sure the right people notice the discussions relevant to them. EDIT: Ah, it got linked in the middle of this thread. That's very easy to miss. |
align.restrict_for_offset(Size::from_bytes(niche)) | ||
}) | ||
}); | ||
(Some(this.for_variant(cx, untagged_variant)), niche_align) |
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 logic is still not right, we need something like #132745 or else there will be wrong dereferenceable
flags.
The point of this function is to compute the pointee info, but with a type like MultipleAlign8
in your example, there is no pointee. More precisely, we are computing "pointee or null" info; null is the one and only special case that is allowed here.
fn call_multiple_niches_align_8() { | ||
// CHECK: call void @multiple_niches_align_8(ptr {{.*}}align 8 {{.*}}(i64 32768 to ptr) | ||
multiple_niches_align_8(MultipleAlign8::Niche_32768); | ||
// CHECK: call void @multiple_niches_align_8(ptr {{.*}}align 8 {{.*}}(i64 32776 to 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.
Specifically, among the attributes hidden by the {{.*}}
is dereferenceable
, and that is unsound.
We currently don't have a way to represent a pointer that is aligned but maybe non-dereferenceable. However, I am not convinced that is something worth having -- it will be extremely rare; IMO we should have evidence of real-world benefit for such a construction before we spend the effort of implementing and maintaining that in the compiler.
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.
Correction -- we do have a way to represent a non-dereferenceable pointer, and it is by setting size
to 0. This is what we already do for Box
.
But the rest of my point still stands.
let niche = ((variant_idx.index() - niche_variants.start().index()) 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.
This logic is wrong; it needs to take into account the size of the field that holds the niche, and wrap around accordingly.
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.
Since I only want to calculate alignment, I think the actual value of niche is not necessary. I will add some comment.
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 function is called niches
and offers itself as a general-purpose function. If it's only correct for alignment, then it should be a private helper function inside the alignment logic.
This is a different issue. I will create a separate one. |
This frames the PR as a bugfix. But it doesn't fully fix the bug, we are still computing a wrong The PR description does not motivate why we should keep the |
I think with my change |
Why is I've seen some revisions of your change, but I don't know which one you are referring to here. |
Valid on platforms where userspace addresses always have the top bit zeroed. That's one of the things I am experimenting with. |
Ah, that one. Yeah that's at least somewhat fishy. Once we are reasonably sure we'll have types that could benefit from |
☔ The latest upstream changes (presumably #132800) made this pull request unmergeable. Please resolve the merge conflicts. |
I have updated the PR's description. |
I'm closing this because the |
Context: Segfault at optlevel >= 1.
When passing a niche as a pointer, we have to consider drop
align
anddereferenceable
. The issue aboutdereferenceable
is #131834.Take https://rust.godbolt.org/z/rbxqKedG6 as an example: we pass
E::B
with a value of32769
as a parameter, and it's clear that the alignment of this as an address is not 8.Instead of dropping the
align
we could probably also shorten it, but we don't have a clear example to show it makes sense for optimization.r? @the8472 or @saethlin