]> git.proxmox.com Git - rustc.git/blobdiff - vendor/packed_simd/src/api/slice/from_slice.rs
Update upstream source from tag 'upstream/1.52.1+dfsg1'
[rustc.git] / vendor / packed_simd / src / api / slice / from_slice.rs
diff --git a/vendor/packed_simd/src/api/slice/from_slice.rs b/vendor/packed_simd/src/api/slice/from_slice.rs
new file mode 100644 (file)
index 0000000..ca83c7d
--- /dev/null
@@ -0,0 +1,219 @@
+//! Implements methods to read a vector type from a slice.
+
+macro_rules! impl_slice_from_slice {
+    ([$elem_ty:ident; $elem_count:expr]: $id:ident | $test_tt:tt) => {
+        impl $id {
+            /// Instantiates a new vector with the values of the `slice`.
+            ///
+            /// # Panics
+            ///
+            /// If `slice.len() < Self::lanes()` or `&slice[0]` is not aligned
+            /// to an `align_of::<Self>()` boundary.
+            #[inline]
+            pub fn from_slice_aligned(slice: &[$elem_ty]) -> Self {
+                unsafe {
+                    assert!(slice.len() >= $elem_count);
+                    let target_ptr = slice.get_unchecked(0) as *const $elem_ty;
+                    assert_eq!(
+                        target_ptr
+                            .align_offset(crate::mem::align_of::<Self>()),
+                        0
+                    );
+                    Self::from_slice_aligned_unchecked(slice)
+                }
+            }
+
+            /// Instantiates a new vector with the values of the `slice`.
+            ///
+            /// # Panics
+            ///
+            /// If `slice.len() < Self::lanes()`.
+            #[inline]
+            pub fn from_slice_unaligned(slice: &[$elem_ty]) -> Self {
+                unsafe {
+                    assert!(slice.len() >= $elem_count);
+                    Self::from_slice_unaligned_unchecked(slice)
+                }
+            }
+
+            /// Instantiates a new vector with the values of the `slice`.
+            ///
+            /// # Precondition
+            ///
+            /// 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 from_slice_aligned_unchecked(
+                slice: &[$elem_ty],
+            ) -> Self {
+                debug_assert!(slice.len() >= $elem_count);
+                let target_ptr = slice.get_unchecked(0) as *const $elem_ty;
+                debug_assert_eq!(
+                    target_ptr.align_offset(crate::mem::align_of::<Self>()),
+                    0
+                );
+
+                #[cfg_attr(
+                    feature = "cargo-clippy",
+                    allow(clippy::cast_ptr_alignment)
+                )]
+                *(target_ptr as *const Self)
+            }
+
+            /// Instantiates a new vector with the values of the `slice`.
+            ///
+            /// # Precondition
+            ///
+            /// If `slice.len() < Self::lanes()` the behavior is undefined.
+            #[inline]
+            pub unsafe fn from_slice_unaligned_unchecked(
+                slice: &[$elem_ty],
+            ) -> Self {
+                use crate::mem::size_of;
+                debug_assert!(slice.len() >= $elem_count);
+                let target_ptr =
+                    slice.get_unchecked(0) as *const $elem_ty as *const u8;
+                let mut x = Self::splat(0 as $elem_ty);
+                let self_ptr = &mut x as *mut Self as *mut u8;
+                crate::ptr::copy_nonoverlapping(
+                    target_ptr,
+                    self_ptr,
+                    size_of::<Self>(),
+                );
+                x
+            }
+        }
+
+        test_if! {
+            $test_tt:
+            paste::item! {
+                pub mod [<$id _slice_from_slice>] {
+                    use super::*;
+                    use crate::iter::Iterator;
+
+                    #[cfg_attr(not(target_arch = "wasm32"), test)]
+                    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
+                    fn from_slice_unaligned() {
+                        let mut unaligned = [42 as $elem_ty; $id::lanes() + 1];
+                        unaligned[0] = 0 as $elem_ty;
+                        let vec = $id::from_slice_unaligned(&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 from_slice_unaligned_fail() {
+                        let mut unaligned = [42 as $elem_ty; $id::lanes() + 1];
+                        unaligned[0] = 0 as $elem_ty;
+                        // the slice is not large enough => panic
+                        let _vec = $id::from_slice_unaligned(&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 from_slice_aligned() {
+                        let mut aligned = A {
+                            data: [0 as $elem_ty; 2 * $id::lanes()],
+                        };
+                        for i in $id::lanes()..(2 * $id::lanes()) {
+                            unsafe {
+                                aligned.data[i] = 42 as $elem_ty;
+                            }
+                        }
+
+                        let vec = unsafe {
+                            $id::from_slice_aligned(
+                                &aligned.data[$id::lanes()..]
+                            )
+                        };
+                        for (index, &b) in
+                            unsafe { aligned.data.iter().enumerate() } {
+                            if index < $id::lanes() {
+                                assert_eq!(b, 0 as $elem_ty);
+                            } else {
+                                assert_eq!(b, 42 as $elem_ty);
+                                assert_eq!(
+                                    b, vec.extract(index - $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 from_slice_aligned_fail_lanes() {
+                        let aligned = A {
+                            data: [0 as $elem_ty; 2 * $id::lanes()],
+                        };
+                        let _vec = unsafe {
+                            $id::from_slice_aligned(
+                                &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 from_slice_aligned_fail_align() {
+                        unsafe {
+                            let aligned = A {
+                                data: [0 as $elem_ty; 2 * $id::lanes()],
+                            };
+
+                            // get a pointer to the front of data
+                            let ptr: *const $elem_ty = aligned.data.as_ptr()
+                                as *const $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
+                                // from_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: &[$elem_ty] = slice::from_raw_parts(
+                                ptr, $id::lanes()
+                            );
+                            // this should always panic because the slice
+                            // alignment does not match the alignment
+                            // requirements for the vector type:
+                            let _vec = $id::from_slice_aligned(s);
+                        }
+                    }
+                }
+            }
+        }
+    };
+}