Layout of packed SIMD vectors
Disclaimer: This chapter represents the consensus from issue #38. The statements in here are not (yet) "guaranteed" not to change until an RFC ratifies them.
Rust currently exposes packed1 SIMD vector types like __m128
to users, but it
does not expose a way for users to construct their own vector types.
The set of currently-exposed packed SIMD vector types is implementation-defined and it is currently different for each architecture.
packed denotes that these SIMD vectors have a compile-time fixed size, distinguishing these from SIMD vector types whose size is only known at run-time. Rust currently only supports packed SIMD vector types. This is elaborated further in RFC2366.
Packed SIMD vector types
Packed SIMD vector types are repr(simd)
homogeneous tuple-structs containing
N
elements of type T
where N
is a power-of-two and the size and alignment
requirements of T
are equal:
#[repr(simd)]
struct Vector<T, N>(T_0, ..., T_(N - 1));
The set of supported values of T
and N
is implementation-defined.
The size of Vector
is N * size_of::<T>()
and its alignment is an
implementation-defined function of T
and N
greater than or equal to
align_of::<T>()
. That is:
assert_eq!(size_of::<Vector<T, N>>(), size_of::<T>() * N);
assert!(align_of::<Vector<T, N>>() >= align_of::<T>());
That is, two distinct repr(simd)
vector types that have the same T
and the
same N
have the same size and alignment.
Vector elements are laid out in source field order, enabling random access to vector elements by reinterpreting the vector as an array:
union U {
vec: Vector<T, N>,
arr: [T; N]
}
assert_eq!(size_of::<Vector<T, N>>(), size_of::<[T; N]>());
assert!(align_of::<Vector<T, N>>() >= align_of::<[T; N]>());
unsafe {
let u = U { vec: Vector<T, N>(t_0, ..., t_(N - 1)) };
assert_eq!(u.vec.0, u.arr[0]);
// ...
assert_eq!(u.vec.(N - 1), u.arr[N - 1]);
}
Unresolved questions
-
Blocked: Should the layout of packed SIMD vectors be the same as that of homogeneous tuples ? Such that:
union U { vec: Vector<T, N>, tup: (T_0, ..., T_(N-1)), } assert_eq!(size_of::<Vector<T, N>>(), size_of::<(T_0, ..., T_(N-1))>()); assert!(align_of::<Vector<T, N>>() >= align_of::<(T_0, ..., T_(N-1))>()); unsafe { let u = U { vec: Vector(t_0, ..., t_(N - 1)) }; assert_eq!(u.vec.0, u.tup.0); // ... assert_eq!(u.vec.(N - 1), u.tup.(N - 1)); }
This is blocked on the resolution of issue #36 about the layout of homogeneous structs and tuples.
-
MaybeUninit<T>
does not have the samerepr
asT
, soMaybeUninit<Vector<T, N>>
are notrepr(simd)
, which has performance consequences and means thatMaybeUninit<Vector<T, N>>
is not C-FFI safe.