diff options
Diffstat (limited to 'third_party/rust/packed_simd/src/api/from')
-rw-r--r-- | third_party/rust/packed_simd/src/api/from/from_array.rs | 124 | ||||
-rw-r--r-- | third_party/rust/packed_simd/src/api/from/from_vector.rs | 67 |
2 files changed, 191 insertions, 0 deletions
diff --git a/third_party/rust/packed_simd/src/api/from/from_array.rs b/third_party/rust/packed_simd/src/api/from/from_array.rs new file mode 100644 index 0000000000..5c7801ddaf --- /dev/null +++ b/third_party/rust/packed_simd/src/api/from/from_array.rs @@ -0,0 +1,124 @@ +//! Implements `From<[T; N]>` and `Into<[T; N]>` for vector types. + +macro_rules! impl_from_array { + ([$elem_ty:ident; $elem_count:expr]: $id:ident | $test_tt:tt + | ($non_default_array:expr, $non_default_vec:expr)) => { + impl From<[$elem_ty; $elem_count]> for $id { + #[inline] + fn from(array: [$elem_ty; $elem_count]) -> Self { + union U { + array: [$elem_ty; $elem_count], + vec: $id, + } + unsafe { U { array }.vec } + } + } + + impl From<$id> for [$elem_ty; $elem_count] { + #[inline] + fn from(vec: $id) -> Self { + union U { + array: [$elem_ty; $elem_count], + vec: $id, + } + unsafe { U { vec }.array } + } + } + + // FIXME: `Into::into` is not inline, but due to + // the blanket impl in `std`, which is not + // marked `default`, we cannot override it here with + // specialization. + /* + impl Into<[$elem_ty; $elem_count]> for $id { + #[inline] + fn into(self) -> [$elem_ty; $elem_count] { + union U { + array: [$elem_ty; $elem_count], + vec: $id, + } + unsafe { U { vec: self }.array } + } + } + + impl Into<$id> for [$elem_ty; $elem_count] { + #[inline] + fn into(self) -> $id { + union U { + array: [$elem_ty; $elem_count], + vec: $id, + } + unsafe { U { array: self }.vec } + } + } + */ + + test_if! { + $test_tt: + paste::item! { + // Comparisons use integer casts within mantissa^1 range. + #[allow(clippy::float_cmp)] + mod [<$id _from>] { + use super::*; + #[test] + #[cfg_attr(miri, ignore)] + fn array() { + let vec: $id = Default::default(); + + // FIXME: Workaround for arrays with more than 32 + // elements. + // + // Safe because we never take a reference to any + // uninitialized element. + union W { + array: [$elem_ty; $elem_count], + other: () + } + let mut array = W { other: () }; + for i in 0..$elem_count { + let default: $elem_ty = Default::default(); + // note: array.other is the active member and + // initialized so we can take a reference to it: + let p = unsafe { + &mut array.other as *mut () as *mut $elem_ty + }; + // note: default is a valid bit-pattern for + // $elem_ty: + unsafe { + crate::ptr::write(p.wrapping_add(i), default) + }; + } + // note: the array variant of the union is properly + // initialized: + let mut array = unsafe { + array.array + }; + + array[0] = $non_default_array; + let vec = vec.replace(0, $non_default_vec); + + let vec_from_array = $id::from(array); + assert_eq!(vec_from_array, vec); + let array_from_vec + = <[$elem_ty; $elem_count]>::from(vec); + // FIXME: Workaround for arrays with more than 32 + // elements. + for i in 0..$elem_count { + assert_eq!(array_from_vec[i], array[i]); + } + + let vec_from_into_array: $id = array.into(); + assert_eq!(vec_from_into_array, vec); + let array_from_into_vec: [$elem_ty; $elem_count] + = vec.into(); + // FIXME: Workaround for arrays with more than 32 + // elements. + for i in 0..$elem_count { + assert_eq!(array_from_into_vec[i], array[i]); + } + } + } + } + } + }; +} diff --git a/third_party/rust/packed_simd/src/api/from/from_vector.rs b/third_party/rust/packed_simd/src/api/from/from_vector.rs new file mode 100644 index 0000000000..55f70016d5 --- /dev/null +++ b/third_party/rust/packed_simd/src/api/from/from_vector.rs @@ -0,0 +1,67 @@ +//! Implements `From` and `Into` for vector types. + +macro_rules! impl_from_vector { + ([$elem_ty:ident; $elem_count:expr]: $id:ident | $test_tt:tt + | $source:ident) => { + impl From<$source> for $id { + #[inline] + fn from(source: $source) -> Self { + fn static_assert_same_number_of_lanes<T, U>() + where + T: crate::sealed::Simd, + U: crate::sealed::Simd<LanesType = T::LanesType>, + { + } + use crate::llvm::simd_cast; + static_assert_same_number_of_lanes::<$id, $source>(); + Simd(unsafe { simd_cast(source.0) }) + } + } + + // FIXME: `Into::into` is not inline, but due to the blanket impl in + // `std`, which is not marked `default`, we cannot override it here + // with specialization. + + /* + impl Into<$id> for $source { + #[inline] + fn into(self) -> $id { + unsafe { simd_cast(self) } + } + } + */ + + test_if! { + $test_tt: + paste::item! { + pub mod [<$id _from_ $source>] { + use super::*; + #[cfg_attr(not(target_arch = "wasm32"), test)] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] + fn from() { + assert_eq!($id::lanes(), $source::lanes()); + let source: $source = Default::default(); + let vec: $id = Default::default(); + + let e = $id::from(source); + assert_eq!(e, vec); + + let e: $id = source.into(); + assert_eq!(e, vec); + } + } + } + } + }; +} + +macro_rules! impl_from_vectors { + ([$elem_ty:ident; $elem_count:expr]: $id:ident | $test_tt:tt + | $($source:ident),*) => { + $( + impl_from_vector!( + [$elem_ty; $elem_count]: $id | $test_tt | $source + ); + )* + } +} |