diff options
Diffstat (limited to 'third_party/rust/packed_simd/src/api/slice/write_to_slice.rs')
-rw-r--r-- | third_party/rust/packed_simd/src/api/slice/write_to_slice.rs | 196 |
1 files changed, 196 insertions, 0 deletions
diff --git a/third_party/rust/packed_simd/src/api/slice/write_to_slice.rs b/third_party/rust/packed_simd/src/api/slice/write_to_slice.rs new file mode 100644 index 0000000000..5abd4916e0 --- /dev/null +++ b/third_party/rust/packed_simd/src/api/slice/write_to_slice.rs @@ -0,0 +1,196 @@ +//! Implements methods to write a vector type to a slice. + +macro_rules! impl_slice_write_to_slice { + ([$elem_ty:ident; $elem_count:expr]: $id:ident | $test_tt:tt) => { + impl $id { + /// Writes the values of the vector to the `slice`. + /// + /// # Panics + /// + /// If `slice.len() < Self::lanes()` or `&slice[0]` is not + /// aligned to an `align_of::<Self>()` boundary. + #[inline] + pub fn write_to_slice_aligned(self, slice: &mut [$elem_ty]) { + unsafe { + assert!(slice.len() >= $elem_count); + let target_ptr = slice.as_mut_ptr(); + assert_eq!(target_ptr.align_offset(crate::mem::align_of::<Self>()), 0); + self.write_to_slice_aligned_unchecked(slice); + } + } + + /// Writes the values of the vector to the `slice`. + /// + /// # Panics + /// + /// If `slice.len() < Self::lanes()`. + #[inline] + pub fn write_to_slice_unaligned(self, slice: &mut [$elem_ty]) { + unsafe { + assert!(slice.len() >= $elem_count); + self.write_to_slice_unaligned_unchecked(slice); + } + } + + /// Writes the values of the vector to the `slice`. + /// + /// # Safety + /// + /// If `slice.len() < Self::lanes()` or `&slice[0]` is not + /// aligned to an `align_of::<Self>()` boundary, the behavior is + /// undefined. + #[inline] + pub unsafe fn write_to_slice_aligned_unchecked(self, slice: &mut [$elem_ty]) { + debug_assert!(slice.len() >= $elem_count); + let target_ptr = slice.as_mut_ptr(); + debug_assert_eq!(target_ptr.align_offset(crate::mem::align_of::<Self>()), 0); + + #[allow(clippy::cast_ptr_alignment)] + #[allow(clippy::cast_ptr_alignment)] + #[allow(clippy::cast_ptr_alignment)] + #[allow(clippy::cast_ptr_alignment)] + *(target_ptr as *mut Self) = self; + } + + /// Writes the values of the vector to the `slice`. + /// + /// # Safety + /// + /// If `slice.len() < Self::lanes()` the behavior is undefined. + #[inline] + pub unsafe fn write_to_slice_unaligned_unchecked(self, slice: &mut [$elem_ty]) { + debug_assert!(slice.len() >= $elem_count); + let target_ptr = slice.as_mut_ptr().cast(); + let self_ptr = &self as *const Self as *const u8; + crate::ptr::copy_nonoverlapping(self_ptr, target_ptr, crate::mem::size_of::<Self>()); + } + } + + test_if! { + $test_tt: + paste::item! { + // Comparisons use integer casts within mantissa^1 range. + #[allow(clippy::float_cmp)] + pub mod [<$id _slice_write_to_slice>] { + use super::*; + use crate::iter::Iterator; + + #[cfg_attr(not(target_arch = "wasm32"), test)] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] + fn write_to_slice_unaligned() { + let mut unaligned = [0 as $elem_ty; $id::lanes() + 1]; + let vec = $id::splat(42 as $elem_ty); + vec.write_to_slice_unaligned(&mut unaligned[1..]); + for (index, &b) in unaligned.iter().enumerate() { + if index == 0 { + assert_eq!(b, 0 as $elem_ty); + } else { + assert_eq!(b, 42 as $elem_ty); + assert_eq!(b, vec.extract(index - 1)); + } + } + } + + // FIXME: wasm-bindgen-test does not support #[should_panic] + // #[cfg_attr(not(target_arch = "wasm32"), test)] + // #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] + #[cfg(not(target_arch = "wasm32"))] + #[test] + #[should_panic] + fn write_to_slice_unaligned_fail() { + let mut unaligned = [0 as $elem_ty; $id::lanes() + 1]; + let vec = $id::splat(42 as $elem_ty); + vec.write_to_slice_unaligned(&mut unaligned[2..]); + } + + union A { + data: [$elem_ty; 2 * $id::lanes()], + _vec: $id, + } + + #[cfg_attr(not(target_arch = "wasm32"), test)] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] + fn write_to_slice_aligned() { + let mut aligned = A { + data: [0 as $elem_ty; 2 * $id::lanes()], + }; + let vec = $id::splat(42 as $elem_ty); + unsafe { + vec.write_to_slice_aligned( + &mut aligned.data[$id::lanes()..] + ); + for (idx, &b) in aligned.data.iter().enumerate() { + if idx < $id::lanes() { + assert_eq!(b, 0 as $elem_ty); + } else { + assert_eq!(b, 42 as $elem_ty); + assert_eq!( + b, vec.extract(idx - $id::lanes()) + ); + } + } + } + } + + // FIXME: wasm-bindgen-test does not support #[should_panic] + // #[cfg_attr(not(target_arch = "wasm32"), test)] + // #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] + #[cfg(not(target_arch = "wasm32"))] + #[test] + #[should_panic] + fn write_to_slice_aligned_fail_lanes() { + let mut aligned = A { + data: [0 as $elem_ty; 2 * $id::lanes()], + }; + let vec = $id::splat(42 as $elem_ty); + unsafe { + vec.write_to_slice_aligned( + &mut aligned.data[2 * $id::lanes()..] + ) + }; + } + + // FIXME: wasm-bindgen-test does not support #[should_panic] + // #[cfg_attr(not(target_arch = "wasm32"), test)] + // #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] + #[cfg(not(target_arch = "wasm32"))] + #[test] + #[should_panic] + fn write_to_slice_aligned_fail_align() { + unsafe { + let mut aligned = A { + data: [0 as $elem_ty; 2 * $id::lanes()], + }; + + // get a pointer to the front of data + let ptr: *mut $elem_ty + = aligned.data.as_mut_ptr() as *mut $elem_ty; + // offset pointer by one element + let ptr = ptr.wrapping_add(1); + + if ptr.align_offset(crate::mem::align_of::<$id>()) + == 0 { + // the pointer is properly aligned, so + // write_to_slice_aligned won't fail here (e.g. + // this can happen for i128x1). So we panic to + // make the "should_fail" test pass: + panic!("ok"); + } + + // create a slice - this is safe, because the + // elements of the slice exist, are properly + // initialized, and properly aligned: + let s: &mut [$elem_ty] + = slice::from_raw_parts_mut(ptr, $id::lanes()); + // this should always panic because the slice + // alignment does not match the alignment + // requirements for the vector type: + let vec = $id::splat(42 as $elem_ty); + vec.write_to_slice_aligned(s); + } + } + } + } + } + }; +} |