From 86158f581d20948507bef65e6162e3bbf5f4fa91 Mon Sep 17 00:00:00 2001 From: Caleb Zulawski Date: Mon, 20 May 2024 01:09:29 -0400 Subject: Make repr(packed) vectors work with SIMD intrinsics --- compiler/rustc_codegen_llvm/src/intrinsic.rs | 49 +++++++++++++++++++++++++++- tests/ui/simd/repr_packed.rs | 18 +++------- 2 files changed, 52 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index c0a1208a8c7..83a71752ffd 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -480,8 +480,55 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> { } _ if name.as_str().starts_with("simd_") => { + // Unpack non-power-of-2 #[repr(packed)] + let mut loaded_args = Vec::new(); + for (ty, arg) in arg_tys.iter().zip(args) { + loaded_args.push( + if ty.is_simd() + && let OperandValue::Ref(place) = arg.val + { + let (size, elem_ty) = ty.simd_size_and_type(self.tcx()); + let elem_ll_ty = match elem_ty.kind() { + ty::Float(f) => self.type_float_from_ty(*f), + ty::Int(i) => self.type_int_from_ty(*i), + ty::Uint(u) => self.type_uint_from_ty(*u), + ty::RawPtr(_, _) => self.type_ptr(), + _ => unreachable!(), + }; + let loaded = + self.load_from_place(self.type_vector(elem_ll_ty, size), place); + OperandRef::from_immediate_or_packed_pair(self, loaded, arg.layout) + } else { + *arg + }, + ); + } + + let llret_ty = if ret_ty.is_simd() + && let abi::Abi::Aggregate { .. } = self.layout_of(ret_ty).layout.abi + { + let (size, elem_ty) = ret_ty.simd_size_and_type(self.tcx()); + let elem_ll_ty = match elem_ty.kind() { + ty::Float(f) => self.type_float_from_ty(*f), + ty::Int(i) => self.type_int_from_ty(*i), + ty::Uint(u) => self.type_uint_from_ty(*u), + ty::RawPtr(_, _) => self.type_ptr(), + _ => unreachable!(), + }; + self.type_vector(elem_ll_ty, size) + } else { + llret_ty + }; + match generic_simd_intrinsic( - self, name, callee_ty, fn_args, args, ret_ty, llret_ty, span, + self, + name, + callee_ty, + fn_args, + &loaded_args, + ret_ty, + llret_ty, + span, ) { Ok(llval) => llval, Err(()) => return Ok(()), diff --git a/tests/ui/simd/repr_packed.rs b/tests/ui/simd/repr_packed.rs index 411bba3454e..52c794563de 100644 --- a/tests/ui/simd/repr_packed.rs +++ b/tests/ui/simd/repr_packed.rs @@ -6,9 +6,6 @@ #[repr(simd, packed)] struct Simd([T; N]); -#[repr(simd)] -struct FullSimd([T; N]); - fn check_size_align() { use std::mem; assert_eq!(mem::size_of::>(), mem::size_of::<[T; N]>()); @@ -44,16 +41,9 @@ fn main() { simd_add(Simd::([0., 1., 2., 3.]), Simd::([2., 2., 2., 2.])); assert_eq!(std::mem::transmute::<_, [f64; 4]>(x), [2., 3., 4., 5.]); - // non-powers-of-two have padding and need to be expanded to full vectors - fn load(v: Simd) -> FullSimd { - unsafe { - let mut tmp = core::mem::MaybeUninit::>::uninit(); - std::ptr::copy_nonoverlapping(&v as *const _, tmp.as_mut_ptr().cast(), 1); - tmp.assume_init() - } - } - let x: FullSimd = - simd_add(load(Simd::([0., 1., 2.])), load(Simd::([2., 2., 2.]))); - assert_eq!(x.0, [2., 3., 4.]); + // non-powers-of-two have padding and lesser alignment, but the intrinsic handles it + let x: Simd = simd_add(Simd::([0., 1., 2.]), Simd::([2., 2., 2.])); + let arr: [f64; 3] = x.0; + assert_eq!(arr, [2., 3., 4.]); } } -- cgit 1.4.1-3-g733a5