Both of the following functions produce shufflevector <4 x i32> %0, <4 x i32> undef, <4 x i32> <i32 1, i32 3, i32 0, i32 2> in release mode today, FWIW:
#[no_mangle]
pub fn rearrange_via_tuplestruct(a: Simd4<i32>) -> Simd4<i32> {
Simd4(a.1,a.3,a.0,a.2)
}
#[no_mangle]
pub fn rearrange_via_array(a: Simd4<i32>) -> Simd4<i32> {
[ a[1], a[3], a[0], a[2] ].into()
}
(Helpers, including horrible transmutes as a simd struct can't have an array in today's nightly)
#[repr(simd)]
pub struct Simd4<T>(T,T,T,T);
impl<T> std::ops::Deref for Simd4<T> {
type Target = [T; 4];
fn deref(&self) -> &Self::Target {
unsafe { std::mem::transmute(self) }
}
}
impl<T> From<[T;4]> for Simd4<T> where T : Copy {
fn from(a: [T;4]) -> Self {
unsafe { std::mem::transmute_copy(&a) }
}
}
a.1 and a[1] are the same LLVM GEP, so struct vs tuple vs array doesn’t really matter to it.
Of course, as Aurora said, this is the simplest case in release mode, not a proof of bet-your-business-on-it-ility. But I’m not convinced that either is “very hard to read”; they seem to quite explicitly and directly show what’s happening.