-
Notifications
You must be signed in to change notification settings - Fork 82
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
non-power-of-2 Simd types have wrong size #319
Comments
see also #63 |
see some previous discussion: https://rust-lang.zulipchat.com/#narrow/stream/257879-project-portable-simd/topic/Bytemuckable.20Simd/near/311734698 |
imho we should define layout such that |
Note the changes to vector layout by @RalfJung in rust-lang/rust@891a4da are the exact opposite of what we probably want: that commit adds padding until size is divisible by alignment, what we probably want is to decrease alignment enough that we can enforce vectors are the exact same size as the corresponding array (usually means no padding, there could still be padding if the element type contains padding, portable-simd will presumably enforce that those element types aren't allowed but |
now that I think about some more, gcd of aligns is wrong, instead we probably want |
I wonder, what's the motivation for that commit? If it's absolutely necessary for some other reason, we could pretty easily add a new repr for portable SIMD. |
I would assume it's for enforcing rust's rule that every type must have its size be divisible by its alignment. llvm doesn't enforce that rule, so relying on llvm to calculate layout for vectors can violate that rule. |
My commit does not change layout at all, it just changes the layout consistency check, assuming that the existing layout code is right. If the existing layout code is buggy then yeah I also ported the bug to the layout checker now. Feel free to fix both at the same time. :) The important part is the the size and align of the type must be uniquely determined by the size and align of the vector elements and the number of elements.
|
The actual layout computation is here. And yes This behavior of rustc (to round up vector sizes to the next power of two) has existed at least since 2016. Cc @eddyb |
To be clear, this is not rustc-specific behavior but LLVM behavior - the reason we have to reuse the IIRC the logic is roughly:
|
Reading more of the discussion above, you really cannot talk about At the point where you start diverging in alignments from LLVM, you can no longer use primitive vector types and You would probably need to "just" not use non-pow2 LLVM vector types, i.e. do not have Frankly, after what I've seen from GLSL (which has e.g. size=12 align=16 types that "eat" padding when used as fields!), my humble suggestion might be to ban these types instead of giving them magical semantics, since you generally can't "take back" the magic, even if you manage to make it work initially. |
what i'm envisioning is using npot vectors by value (not in memory) just uses usual llvm semantics, whereas when loading/storing llvm allows specifying the alignment, which is where we would override it to use the rust abi alignment. note that npot vectors are natively supported on some ISAs (e.g. SVE, RVV, and SimpleV) |
for llvm npot vector loads/stores, afaict from reading the llvm language reference llvm guarantees that they will not load/store padding if the elements are an integer byte size (so not |
we shouldn't run into that particular problem since the proposed layouts will always have |
It is not actually my opinion that these values should be equal in all cases, actually? I believe
We are strongly inclined to think we do not want byte-level padding in SIMD types, I think only a few murmurs have even discussed that possibility and largely in a negative light. We collectively average out to feeling a little dubious even about niches (or other forms of bit-level padding). |
power-of-2 sized vectors always matched their corresponding array size and my proposal doesn't change that. if we use the I should point out that I am explicitly not changing
so then you also agree we should change rustc's current vector layouts to never introduce padding bytes. this requires potentially reducing alignment for non-power-of-2 vectors in order to not violate the rust |
note that my proposal means that |
...That's not really a footgun, honestly, unless you write code that never actually tests the function ever, since the result must be monomorphized. |
In our docs we already repeatedly describe vectors as "basically arrays" so I do think it's a footgun if they have unusual layouts, in this function and elsewhere. |
maybe not in the sense of unintentionally causing UB, but it is in the sense of writing a bunch of code generic over vector lengths and expecting it to work for any length...which could require re-architecting a bunch of code to fix. |
You were quoting a statement about the size but your reply talks about alignment. Looks to me like you are talking past each other? f32x4 on x86 can be 16-byte aligned and still have the same size as |
Usually alignment of such types is not even something we can decide. What is their alignment in C? We pretty much have to use the same to be ABI compatible. |
Only the types in |
That is assuming people won't declare their own SIMD types and expect them to be compatible with the equivalent def.n in C. |
imho |
Fair. But make sure this is documented well and brace yourselves for bug reports caused by any difference in ABI. ;) Does C even have non-pot SIMD types, and if yes then how do their layouts look like? |
for x86_64, yes, but only in clang, not gcc (idk about icc or msvc): typedef unsigned short u16x3 __attribute__((vector_size(3 * sizeof(unsigned short)))); |
our 128-bit integers don't even match up with C!
"Ad hoc." As @eddyb mentioned/implied, |
And that is such a success that you want to repeat it? 😂 |
I'm out of my depth here, I don't understand the tradeoffs involved well enough to judge the pros and cons.
I guess instead of having the same logic in many places we could have a shared helper on Abi that distinguishes "register type" and "memory type", but no idea how practical that is.
|
imho it would be useful to also have a load/store type (value actually being passed to the load/store instruction):
|
The existing handling for handling bools being i1 in registers touches a lot of code (including seemingly unrelated code like determining signs for tags in the discriminant calculation code) and requires separate "immediate" and non-immediate versions of several methods. I am pretty sure the wrong one is used at several places. Also for Cranelift it did require extra special cases to handle "i1" being 8 bits big as Cranelift only has i8 and up. I believe GCC also requires special code as it uses a true bool type rather than a 1bit integer. Honestly I did prefer to just convert i1 to i8 as soon as possible and never pass it around as immediate. I realize this may not be possible for performance reasons though. |
note that the alignment specification I'm proposing will allow arbitrary vector type punning without having alignment issues as long as the type pun is otherwise valid and llvm_align doesn't do crazy stuff (e.g. if llvm decides alignof(i8x4) is less than alignof(i32x1) for some strange reason then that prevents type punning i32x1 to i8x4): see riscv-non-isa/riscv-elf-psabi-doc#347 (comment) for full explanation |
Considering this practically rather than idealistically for a moment, it's questionable to me whether it's really worth fixing the layout vs considering other options. That said, not supporting non-PoT vectors could excessively complicate our API and perhaps delay stabilization while we try to sort out a simpler alternative to
Personally, I like the first or second alternative best. LLVM seems to be able to generate pretty good code for non-PoT vectors, and I think messing with the alignment could cause problems. The second option would allow the user to choose which is more important--having a flexible memory layout or reliable codegen that doesn't juggle layouts. |
…rkingjubilee Implement repr(packed) for repr(simd) This allows creating vectors with non-power-of-2 lengths that do not have padding. See rust-lang/portable-simd#319
…workingjubilee Implement repr(packed) for repr(simd) This allows creating vectors with non-power-of-2 lengths that do not have padding. See rust-lang/portable-simd#319
…rkingjubilee Implement repr(packed) for repr(simd) This allows creating vectors with non-power-of-2 lengths that do not have padding. See rust-lang/portable-simd#319
…rkingjubilee Implement repr(packed) for repr(simd) This allows creating vectors with non-power-of-2 lengths that do not have padding. See rust-lang/portable-simd#319
Implement repr(packed) for repr(simd) This allows creating vectors with non-power-of-2 lengths that do not have padding. See rust-lang/portable-simd#319
Implement repr(packed) for repr(simd) This allows creating vectors with non-power-of-2 lengths that do not have padding. See rust-lang/portable-simd#319
Implement repr(packed) for repr(simd) This allows creating vectors with non-power-of-2 lengths that do not have padding. See rust-lang/portable-simd#319
…nsics, r=workingjubilee Make repr(packed) vectors work with SIMD intrinsics In rust-lang#117116 I fixed `#[repr(packed, simd)]` by doing the expected thing and removing padding from the layout. This should be the last step in providing a solution to rust-lang/portable-simd#319
…rinsics, r=workingjubilee Make repr(packed) vectors work with SIMD intrinsics In rust-lang#117116 I fixed `#[repr(packed, simd)]` by doing the expected thing and removing padding from the layout. This should be the last step in providing a solution to rust-lang/portable-simd#319
Rollup merge of rust-lang#125311 - calebzulawski:repr-packed-simd-intrinsics, r=workingjubilee Make repr(packed) vectors work with SIMD intrinsics In rust-lang#117116 I fixed `#[repr(packed, simd)]` by doing the expected thing and removing padding from the layout. This should be the last step in providing a solution to rust-lang/portable-simd#319
…r=workingjubilee Make repr(packed) vectors work with SIMD intrinsics In #117116 I fixed `#[repr(packed, simd)]` by doing the expected thing and removing padding from the layout. This should be the last step in providing a solution to rust-lang/portable-simd#319
I tried this code:
https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=f4ee5c373508bcb37be6cda3bb627b87
I expected to see this happen: run with no errors because
Simd<T, N>
types should be the same size as the corresponding array type[T; N]
(something we unofficially agreed on iirc, but is not formally decided)Instead, this happened:
Meta
rustc --version --verbose
:crate version in Cargo.toml
:N/A
The text was updated successfully, but these errors were encountered: