Code change:
I think I found a bug with non-power-of-2 SIMD vectors. They're randomly turned into zero values when I store them on Expected result: What we get: Tested with:
As you can see, this is a fault of assuming (while for this is 12 and 16 respectively). More accurately, for , every growth allocates bytes while it actually needs bytes; any element after will overflow the memory, and they will be omitted at the next reallocation.
Ack!
CC
I've got through and I guess there's something wrong with for and other non-power-of-2 SIMD types.<!-- (Don't trust me!) --I think now we've got 2 available options. Make always true even for non-power-of-2 SIMD types like . Make function properly even for situation. I'm pretty new with Rust. Someone pleaes make me an advise!
I'm not sure what the exact behaviour should be. Part of the problem is that non-power-of-two SIMD types don't exist on most platforms, so it gets widened to whatever it needs to be. However, an f32x3 is still only 12 bytes of actual data. I think that Vec should handle the case anyway. Whether the case should come up... I don't really know.
Given that sizeof (f32x3, u32) == 32, it seems like rust already adds padding for SIMD types, so it's simply sizeof that's broken, and should include the padding. At the same time, Vec<Tshould probably assert that sizeof T = minalignof T to catch any errors if in the future there are any types where their size is less than their alignment.
Nominating because the required change may be a back-compat change to some primitive semantics.
Actually, thinking about it some more. I believe that the current behaviour is correct. doesn't account for padding, because padding is situation-dependent: has 7 bytes of padding after the , but that doesn't stop from being 1 byte in size. Just because the type gets padding, doesn't mean it needs to change size. The whole point of having a different alignment to size is to cover these kinds of cases, where the number of usable bytes is not a nice integer multiple of the alignment.
In that situation, the extra padding is to meet the alignment requirements of "u64", not the "i8". In the SIMD example, the extra padding is part of the SIMD type. ie. for (f32x3, u32) there are 4 bytes of padding between the fields, even though u32 only requires alignment to 4 bytes. Either the compiler should not add any padding and sizeof (f32x3, u32) == 16, and any accesses take care to preserve the u32 or as is more usual, the SIMD type should include it's padding. edit: To clarify, types do include their padding in sizeof, which is why sizeof (u64, i8) == 16 as opposed to 9
Amusingly, has a size of 16, whereas f32x3 on it's own has a size of 12, which really shouldn't happen. The issue is caused by sizeof being implemented as a call to this function: The comment above the function is wrong: LLVM does include padding when calculating the size of types, but only for structs (not for vectorised types), which makes that function fairly useless and definitely not the preferred option as the comment suggests. should be preferred instead which always includes padding, so is at least consistent.
NB. and are experimental and are highly unlikely to be stable at 1.0.
Current works like below: and I found that current LLVM doesn't have any guarantee between and . Instead, for SIMD vector types, is guaranteed to be greater or equal than . For example, and of 80-bit floating point format is and . I know that Rust doesn't have but if it does, will be and will be . Which means would have same problem. Now I see 2 options here call , not (as said) function properly even for situation. → → → → → → → alignof → → → → →
I meant more-so the size_of semantics, but simd semantics might also be affected.
I think this is a compiler bug. There are many low-level APIs assuming that size is a multiple of the alignment...
For example, C11's function requires that is a multiple of the parameter. It's expected that the compiler will always output sane values for both (unlike :P) so it is a sensible limitation.
Unfortunately, forcing to return a multiple of would make impossible, which seems like a big missed opportunity. Perhaps there should be a function that just rounds to the next multiple of ?
You could have both sizeof and paddedsizeof, but for the moment, they'd both have to include padding because for struct types LLVM provides no way to get the size without padding, and for vectorised types, even sizeof should include padding as can't be applied to vectorised types without masking every load/store to avoid overwriting the u32 in (f32x3, u32).
Currently I'm testing , and it seems to cause no trouble. Please make me an advise if I'm doing something wrong.
OK Let's do this →

Related discussion:
text: <ins> // Copyright 2015 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your // option. This file may not be copied, modified, or distributed // except according to those terms. #![feature(simd)] #![allow(non_camel_case_types)] use std::mem; /// `T` should satisfy `size_of T (mod min_align_of T) === 0` to be stored at `Vec<T>` properly /// Please consult the issue #20460 fn check<T>() { assert_eq!(mem::size_of::<T>() % mem::min_align_of::<T>(), 0) } fn main() { check::<u8x2>(); check::<u8x3>(); check::<u8x4>(); check::<u8x5>(); check::<u8x6>(); check::<u8x7>(); check::<u8x8>(); check::<i16x2>(); check::<i16x3>(); check::<i16x4>(); check::<i16x5>(); check::<i16x6>(); check::<i16x7>(); check::<i16x8>(); check::<f32x2>(); check::<f32x3>(); check::<f32x4>(); check::<f32x5>(); check::<f32x6>(); check::<f32x7>(); check::<f32x8>(); } #[simd] struct u8x2(u8, u8); #[simd] struct u8x3(u8, u8, u8); #[simd] struct u8x4(u8, u8, u8, u8); #[simd] struct u8x5(u8, u8, u8, u8, u8); #[simd] struct u8x6(u8, u8, u8, u8, u8, u8); #[simd] struct u8x7(u8, u8, u8, u8, u8, u8, u8); #[simd] struct u8x8(u8, u8, u8, u8, u8, u8, u8, u8); #[simd] struct i16x2(i16, i16); #[simd] struct i16x3(i16, i16, i16); #[simd] struct i16x4(i16, i16, i16, i16); #[simd] struct i16x5(i16, i16, i16, i16, i16); #[simd] struct i16x6(i16, i16, i16, i16, i16, i16); #[simd] struct i16x7(i16, i16, i16, i16, i16, i16, i16); #[simd] struct i16x8(i16, i16, i16, i16, i16, i16, i16, i16); #[simd] struct f32x2(f32, f32); #[simd] struct f32x3(f32, f32, f32); #[simd] struct f32x4(f32, f32, f32, f32); #[simd] struct f32x5(f32, f32, f32, f32, f32); #[simd] struct f32x6(f32, f32, f32, f32, f32, f32); #[simd] struct f32x7(f32, f32, f32, f32, f32, f32, f32); #[simd] struct f32x8(f32, f32, f32, f32, f32, f32, f32, f32); </ins>