diff --git a/crates/core_simd/src/comparisons.rs b/crates/core_simd/src/comparisons.rs index c5e9be9015fe..601576e094fa 100644 --- a/crates/core_simd/src/comparisons.rs +++ b/crates/core_simd/src/comparisons.rs @@ -1,77 +1,49 @@ -use crate::{LaneCount, SupportedLaneCount}; +use crate::{LaneCount, Mask, Simd, SimdElement, SupportedLaneCount}; -macro_rules! implement_mask_ops { - { $($vector:ident => $mask:ident ($inner_ty:ident),)* } => { - $( - impl crate::$vector - where - LaneCount: SupportedLaneCount, - { - /// Test if each lane is equal to the corresponding lane in `other`. - #[inline] - pub fn lanes_eq(self, other: Self) -> crate::$mask { - unsafe { - crate::$mask::from_int_unchecked(crate::intrinsics::simd_eq(self, other)) - } - } +impl Simd +where + T: SimdElement + PartialEq, + LaneCount: SupportedLaneCount, +{ + /// Test if each lane is equal to the corresponding lane in `other`. + #[inline] + pub fn lanes_eq(self, other: Self) -> Mask { + unsafe { Mask::from_int_unchecked(crate::intrinsics::simd_eq(self, other)) } + } - /// Test if each lane is not equal to the corresponding lane in `other`. - #[inline] - pub fn lanes_ne(self, other: Self) -> crate::$mask { - unsafe { - crate::$mask::from_int_unchecked(crate::intrinsics::simd_ne(self, other)) - } - } - - /// Test if each lane is less than the corresponding lane in `other`. - #[inline] - pub fn lanes_lt(self, other: Self) -> crate::$mask { - unsafe { - crate::$mask::from_int_unchecked(crate::intrinsics::simd_lt(self, other)) - } - } - - /// Test if each lane is greater than the corresponding lane in `other`. - #[inline] - pub fn lanes_gt(self, other: Self) -> crate::$mask { - unsafe { - crate::$mask::from_int_unchecked(crate::intrinsics::simd_gt(self, other)) - } - } - - /// Test if each lane is less than or equal to the corresponding lane in `other`. - #[inline] - pub fn lanes_le(self, other: Self) -> crate::$mask { - unsafe { - crate::$mask::from_int_unchecked(crate::intrinsics::simd_le(self, other)) - } - } - - /// Test if each lane is greater than or equal to the corresponding lane in `other`. - #[inline] - pub fn lanes_ge(self, other: Self) -> crate::$mask { - unsafe { - crate::$mask::from_int_unchecked(crate::intrinsics::simd_ge(self, other)) - } - } - } - )* + /// Test if each lane is not equal to the corresponding lane in `other`. + #[inline] + pub fn lanes_ne(self, other: Self) -> Mask { + unsafe { Mask::from_int_unchecked(crate::intrinsics::simd_ne(self, other)) } } } -implement_mask_ops! { - SimdI8 => Mask8 (SimdI8), - SimdI16 => Mask16 (SimdI16), - SimdI32 => Mask32 (SimdI32), - SimdI64 => Mask64 (SimdI64), - SimdIsize => MaskSize (SimdIsize), +impl Simd +where + T: SimdElement + PartialOrd, + LaneCount: SupportedLaneCount, +{ + /// Test if each lane is less than the corresponding lane in `other`. + #[inline] + pub fn lanes_lt(self, other: Self) -> Mask { + unsafe { Mask::from_int_unchecked(crate::intrinsics::simd_lt(self, other)) } + } - SimdU8 => Mask8 (SimdI8), - SimdU16 => Mask16 (SimdI16), - SimdU32 => Mask32 (SimdI32), - SimdU64 => Mask64 (SimdI64), - SimdUsize => MaskSize (SimdIsize), + /// Test if each lane is greater than the corresponding lane in `other`. + #[inline] + pub fn lanes_gt(self, other: Self) -> Mask { + unsafe { Mask::from_int_unchecked(crate::intrinsics::simd_gt(self, other)) } + } - SimdF32 => Mask32 (SimdI32), - SimdF64 => Mask64 (SimdI64), + /// Test if each lane is less than or equal to the corresponding lane in `other`. + #[inline] + pub fn lanes_le(self, other: Self) -> Mask { + unsafe { Mask::from_int_unchecked(crate::intrinsics::simd_le(self, other)) } + } + + /// Test if each lane is greater than or equal to the corresponding lane in `other`. + #[inline] + pub fn lanes_ge(self, other: Self) -> Mask { + unsafe { Mask::from_int_unchecked(crate::intrinsics::simd_ge(self, other)) } + } } diff --git a/crates/core_simd/src/fmt.rs b/crates/core_simd/src/fmt.rs index 78ae5ce3fcea..c3947c92f2a9 100644 --- a/crates/core_simd/src/fmt.rs +++ b/crates/core_simd/src/fmt.rs @@ -1,88 +1,36 @@ -macro_rules! debug_wrapper { - { $($trait:ident => $name:ident,)* } => { +macro_rules! impl_fmt_trait { + { $($trait:ident,)* } => { $( - pub(crate) fn $name(slice: &[T], f: &mut core::fmt::Formatter) -> core::fmt::Result { - #[repr(transparent)] - struct Wrapper<'a, T: core::fmt::$trait>(&'a T); + impl core::fmt::$trait for crate::Simd + where + crate::LaneCount: crate::SupportedLaneCount, + T: crate::SimdElement + core::fmt::$trait, + { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + #[repr(transparent)] + struct Wrapper<'a, T: core::fmt::$trait>(&'a T); - impl core::fmt::Debug for Wrapper<'_, T> { - fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { - self.0.fmt(f) + impl core::fmt::Debug for Wrapper<'_, T> { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + self.0.fmt(f) + } } - } - f.debug_list() - .entries(slice.iter().map(|x| Wrapper(x))) - .finish() + f.debug_list() + .entries(self.as_array().iter().map(|x| Wrapper(x))) + .finish() + } } )* } } -debug_wrapper! { - Debug => format, - Binary => format_binary, - LowerExp => format_lower_exp, - UpperExp => format_upper_exp, - Octal => format_octal, - LowerHex => format_lower_hex, - UpperHex => format_upper_hex, -} - -macro_rules! impl_fmt_trait { - { $($type:ident => $(($trait:ident, $format:ident)),*;)* } => { - $( // repeat type - $( // repeat trait - impl core::fmt::$trait for crate::$type - where - crate::LaneCount: crate::SupportedLaneCount, - { - fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { - $format(self.as_ref(), f) - } - } - )* - )* - }; - { integers: $($type:ident,)* } => { - impl_fmt_trait! { - $($type => - (Debug, format), - (Binary, format_binary), - (LowerExp, format_lower_exp), - (UpperExp, format_upper_exp), - (Octal, format_octal), - (LowerHex, format_lower_hex), - (UpperHex, format_upper_hex); - )* - } - }; - { floats: $($type:ident,)* } => { - impl_fmt_trait! { - $($type => - (Debug, format), - (LowerExp, format_lower_exp), - (UpperExp, format_upper_exp); - )* - } - }; - { masks: $($type:ident,)* } => { - impl_fmt_trait! { - $($type => - (Debug, format); - )* - } - } -} - impl_fmt_trait! { - integers: - SimdU8, SimdU16, SimdU32, SimdU64, - SimdI8, SimdI16, SimdI32, SimdI64, - SimdUsize, SimdIsize, -} - -impl_fmt_trait! { - floats: - SimdF32, SimdF64, + Debug, + Binary, + LowerExp, + UpperExp, + Octal, + LowerHex, + UpperHex, } diff --git a/crates/core_simd/src/iter.rs b/crates/core_simd/src/iter.rs index 0020ea5f2016..f403f4d90473 100644 --- a/crates/core_simd/src/iter.rs +++ b/crates/core_simd/src/iter.rs @@ -1,54 +1,58 @@ -use crate::{LaneCount, SupportedLaneCount}; +use crate::{LaneCount, Simd, SupportedLaneCount}; +use core::{ + iter::{Product, Sum}, + ops::{Add, Mul}, +}; macro_rules! impl_traits { - { $type:ident } => { - impl core::iter::Sum for crate::$type + { $type:ty } => { + impl Sum for Simd<$type, LANES> where LaneCount: SupportedLaneCount, { - fn sum>(iter: I) -> Self { - iter.fold(Default::default(), core::ops::Add::add) + fn sum>(iter: I) -> Self { + iter.fold(Simd::splat(0 as $type), Add::add) } } - impl core::iter::Product for crate::$type + impl core::iter::Product for Simd<$type, LANES> where LaneCount: SupportedLaneCount, { - fn product>(iter: I) -> Self { - iter.fold(Default::default(), core::ops::Mul::mul) + fn product>(iter: I) -> Self { + iter.fold(Simd::splat(1 as $type), Mul::mul) } } - impl<'a, const LANES: usize> core::iter::Sum<&'a Self> for crate::$type + impl<'a, const LANES: usize> Sum<&'a Self> for Simd<$type, LANES> where LaneCount: SupportedLaneCount, { - fn sum>(iter: I) -> Self { - iter.fold(Default::default(), core::ops::Add::add) + fn sum>(iter: I) -> Self { + iter.fold(Simd::splat(0 as $type), Add::add) } } - impl<'a, const LANES: usize> core::iter::Product<&'a Self> for crate::$type + impl<'a, const LANES: usize> Product<&'a Self> for Simd<$type, LANES> where LaneCount: SupportedLaneCount, { - fn product>(iter: I) -> Self { - iter.fold(Default::default(), core::ops::Mul::mul) + fn product>(iter: I) -> Self { + iter.fold(Simd::splat(1 as $type), Mul::mul) } } } } -impl_traits! { SimdF32 } -impl_traits! { SimdF64 } -impl_traits! { SimdU8 } -impl_traits! { SimdU16 } -impl_traits! { SimdU32 } -impl_traits! { SimdU64 } -impl_traits! { SimdUsize } -impl_traits! { SimdI8 } -impl_traits! { SimdI16 } -impl_traits! { SimdI32 } -impl_traits! { SimdI64 } -impl_traits! { SimdIsize } +impl_traits! { f32 } +impl_traits! { f64 } +impl_traits! { u8 } +impl_traits! { u16 } +impl_traits! { u32 } +impl_traits! { u64 } +impl_traits! { usize } +impl_traits! { i8 } +impl_traits! { i16 } +impl_traits! { i32 } +impl_traits! { i64 } +impl_traits! { isize } diff --git a/crates/core_simd/src/lib.rs b/crates/core_simd/src/lib.rs index 5f88e3c63b5b..fc0df1813b94 100644 --- a/crates/core_simd/src/lib.rs +++ b/crates/core_simd/src/lib.rs @@ -2,6 +2,7 @@ #![allow(incomplete_features)] #![feature( const_evaluatable_checked, + const_fn_trait_bound, const_generics, platform_intrinsics, repr_simd, diff --git a/crates/core_simd/src/masks.rs b/crates/core_simd/src/masks.rs index ba7da704f61d..14b1fe08ffbd 100644 --- a/crates/core_simd/src/masks.rs +++ b/crates/core_simd/src/masks.rs @@ -12,521 +12,516 @@ )] mod mask_impl; -use crate::{SimdI16, SimdI32, SimdI64, SimdI8, SimdIsize}; +use crate::{LaneCount, Simd, SimdElement, SupportedLaneCount}; -mod sealed { - pub trait Sealed {} +/// Marker trait for types that may be used as SIMD mask elements. +pub unsafe trait MaskElement: SimdElement { + #[doc(hidden)] + fn valid(values: Simd) -> bool + where + LaneCount: SupportedLaneCount; + + #[doc(hidden)] + fn eq(self, other: Self) -> bool; + + #[doc(hidden)] + const TRUE: Self; + + #[doc(hidden)] + const FALSE: Self; } -/// Helper trait for mask types. -pub trait Mask: sealed::Sealed { - /// The number of lanes for this mask. - const LANES: usize; +macro_rules! impl_element { + { $ty:ty } => { + unsafe impl MaskElement for $ty { + fn valid(value: Simd) -> bool + where + LaneCount: SupportedLaneCount, + { + (value.lanes_eq(Simd::splat(0)) | value.lanes_eq(Simd::splat(-1))).all() + } - /// Generates a mask with the same value in every lane. - #[must_use] - fn splat(val: bool) -> Self; + fn eq(self, other: Self) -> bool { self == other } + + const TRUE: Self = -1; + const FALSE: Self = 0; + } + } } -macro_rules! define_opaque_mask { - { - $(#[$attr:meta])* - struct $name:ident($inner_ty:ty); - @bits $bits_ty:ident - } => { - $(#[$attr])* - #[allow(non_camel_case_types)] - pub struct $name($inner_ty) - where - crate::LaneCount: crate::SupportedLaneCount; +impl_element! { i8 } +impl_element! { i16 } +impl_element! { i32 } +impl_element! { i64 } +impl_element! { isize } - impl sealed::Sealed for $name - where - crate::LaneCount: crate::SupportedLaneCount, - {} +/// A SIMD vector mask for `LANES` elements of width specified by `Element`. +/// +/// The layout of this type is unspecified. +#[repr(transparent)] +pub struct Mask(mask_impl::Mask) +where + T: MaskElement, + LaneCount: SupportedLaneCount; - impl Mask for $name - where - crate::LaneCount: crate::SupportedLaneCount, - { - const LANES: usize = LANES; - - #[inline] - fn splat(value: bool) -> Self { - Self::splat(value) - } - } - - impl_opaque_mask_reductions! { $name, $bits_ty } - - impl $name - where - crate::LaneCount: crate::SupportedLaneCount, - { - /// Construct a mask by setting all lanes to the given value. - pub fn splat(value: bool) -> Self { - Self(<$inner_ty>::splat(value)) - } - - /// Converts an array to a SIMD vector. - pub fn from_array(array: [bool; LANES]) -> Self { - let mut vector = Self::splat(false); - let mut i = 0; - while i < $lanes { - vector.set(i, array[i]); - i += 1; - } - vector - } - - /// Converts a SIMD vector to an array. - pub fn to_array(self) -> [bool; LANES] { - let mut array = [false; LANES]; - let mut i = 0; - while i < $lanes { - array[i] = self.test(i); - i += 1; - } - array - } - - /// Converts a vector of integers to a mask, where 0 represents `false` and -1 - /// represents `true`. - /// - /// # Safety - /// All lanes must be either 0 or -1. - #[inline] - pub unsafe fn from_int_unchecked(value: $bits_ty) -> Self { - Self(<$inner_ty>::from_int_unchecked(value)) - } - - /// Converts a vector of integers to a mask, where 0 represents `false` and -1 - /// represents `true`. - /// - /// # Panics - /// Panics if any lane is not 0 or -1. - #[inline] - pub fn from_int(value: $bits_ty) -> Self { - assert!( - (value.lanes_eq($bits_ty::splat(0)) | value.lanes_eq($bits_ty::splat(-1))).all(), - "all values must be either 0 or -1", - ); - unsafe { Self::from_int_unchecked(value) } - } - - /// Converts the mask to a vector of integers, where 0 represents `false` and -1 - /// represents `true`. - #[inline] - pub fn to_int(self) -> $bits_ty { - self.0.to_int() - } - - /// Tests the value of the specified lane. - /// - /// # Safety - /// `lane` must be less than `LANES`. - #[inline] - pub unsafe fn test_unchecked(&self, lane: usize) -> bool { - self.0.test_unchecked(lane) - } - - /// Tests the value of the specified lane. - /// - /// # Panics - /// Panics if `lane` is greater than or equal to the number of lanes in the vector. - #[inline] - pub fn test(&self, lane: usize) -> bool { - assert!(lane < LANES, "lane index out of range"); - unsafe { self.test_unchecked(lane) } - } - - /// Sets the value of the specified lane. - /// - /// # Safety - /// `lane` must be less than `LANES`. - #[inline] - pub unsafe fn set_unchecked(&mut self, lane: usize, value: bool) { - self.0.set_unchecked(lane, value); - } - - /// Sets the value of the specified lane. - /// - /// # Panics - /// Panics if `lane` is greater than or equal to the number of lanes in the vector. - #[inline] - pub fn set(&mut self, lane: usize, value: bool) { - assert!(lane < LANES, "lane index out of range"); - unsafe { self.set_unchecked(lane, value); } - } - - /// Convert this mask to a bitmask, with one bit set per lane. - pub fn to_bitmask(self) -> [u8; crate::LaneCount::::BITMASK_LEN] { - self.0.to_bitmask() - } - - /// Convert a bitmask to a mask. - pub fn from_bitmask(bitmask: [u8; crate::LaneCount::::BITMASK_LEN]) -> Self { - Self(<$inner_ty>::from_bitmask(bitmask)) - } - } - - // vector/array conversion - impl From<[bool; LANES]> for $name - where - crate::LaneCount: crate::SupportedLaneCount, - { - fn from(array: [bool; LANES]) -> Self { - Self::from_array(array) - } - } - - impl From<$name> for [bool; LANES] - where - crate::LaneCount: crate::SupportedLaneCount, - { - fn from(vector: $name) -> Self { - vector.to_array() - } - } - - impl Copy for $name - where - crate::LaneCount: crate::SupportedLaneCount, - {} - - impl Clone for $name - where - crate::LaneCount: crate::SupportedLaneCount, - { - #[inline] - fn clone(&self) -> Self { - *self - } - } - - impl Default for $name - where - crate::LaneCount: crate::SupportedLaneCount, - { - #[inline] - fn default() -> Self { - Self::splat(false) - } - } - - impl PartialEq for $name - where - crate::LaneCount: crate::SupportedLaneCount, - { - #[inline] - fn eq(&self, other: &Self) -> bool { - self.0 == other.0 - } - } - - impl PartialOrd for $name - where - crate::LaneCount: crate::SupportedLaneCount, - { - #[inline] - fn partial_cmp(&self, other: &Self) -> Option { - self.0.partial_cmp(&other.0) - } - } - - impl core::fmt::Debug for $name - where - crate::LaneCount: crate::SupportedLaneCount, - { - fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { - f.debug_list() - .entries((0..LANES).map(|lane| self.test(lane))) - .finish() - } - } - - impl core::ops::BitAnd for $name - where - crate::LaneCount: crate::SupportedLaneCount, - { - type Output = Self; - #[inline] - fn bitand(self, rhs: Self) -> Self { - Self(self.0 & rhs.0) - } - } - - impl core::ops::BitAnd for $name - where - crate::LaneCount: crate::SupportedLaneCount, - { - type Output = Self; - #[inline] - fn bitand(self, rhs: bool) -> Self { - self & Self::splat(rhs) - } - } - - impl core::ops::BitAnd<$name> for bool - where - crate::LaneCount: crate::SupportedLaneCount, - { - type Output = $name; - #[inline] - fn bitand(self, rhs: $name) -> $name { - $name::::splat(self) & rhs - } - } - - impl core::ops::BitOr for $name - where - crate::LaneCount: crate::SupportedLaneCount, - { - type Output = Self; - #[inline] - fn bitor(self, rhs: Self) -> Self { - Self(self.0 | rhs.0) - } - } - - impl core::ops::BitOr for $name - where - crate::LaneCount: crate::SupportedLaneCount, - { - type Output = Self; - #[inline] - fn bitor(self, rhs: bool) -> Self { - self | Self::splat(rhs) - } - } - - impl core::ops::BitOr<$name> for bool - where - crate::LaneCount: crate::SupportedLaneCount, - { - type Output = $name; - #[inline] - fn bitor(self, rhs: $name) -> $name { - $name::::splat(self) | rhs - } - } - - impl core::ops::BitXor for $name - where - crate::LaneCount: crate::SupportedLaneCount, - { - type Output = Self; - #[inline] - fn bitxor(self, rhs: Self) -> Self::Output { - Self(self.0 ^ rhs.0) - } - } - - impl core::ops::BitXor for $name - where - crate::LaneCount: crate::SupportedLaneCount, - { - type Output = Self; - #[inline] - fn bitxor(self, rhs: bool) -> Self::Output { - self ^ Self::splat(rhs) - } - } - - impl core::ops::BitXor<$name> for bool - where - crate::LaneCount: crate::SupportedLaneCount, - { - type Output = $name; - #[inline] - fn bitxor(self, rhs: $name) -> Self::Output { - $name::::splat(self) ^ rhs - } - } - - impl core::ops::Not for $name - where - crate::LaneCount: crate::SupportedLaneCount, - { - type Output = $name; - #[inline] - fn not(self) -> Self::Output { - Self(!self.0) - } - } - - impl core::ops::BitAndAssign for $name - where - crate::LaneCount: crate::SupportedLaneCount, - { - #[inline] - fn bitand_assign(&mut self, rhs: Self) { - self.0 = self.0 & rhs.0; - } - } - - impl core::ops::BitAndAssign for $name - where - crate::LaneCount: crate::SupportedLaneCount, - { - #[inline] - fn bitand_assign(&mut self, rhs: bool) { - *self &= Self::splat(rhs); - } - } - - impl core::ops::BitOrAssign for $name - where - crate::LaneCount: crate::SupportedLaneCount, - { - #[inline] - fn bitor_assign(&mut self, rhs: Self) { - self.0 = self.0 | rhs.0; - } - } - - impl core::ops::BitOrAssign for $name - where - crate::LaneCount: crate::SupportedLaneCount, - { - #[inline] - fn bitor_assign(&mut self, rhs: bool) { - *self |= Self::splat(rhs); - } - } - - impl core::ops::BitXorAssign for $name - where - crate::LaneCount: crate::SupportedLaneCount, - { - #[inline] - fn bitxor_assign(&mut self, rhs: Self) { - self.0 = self.0 ^ rhs.0; - } - } - - impl core::ops::BitXorAssign for $name - where - crate::LaneCount: crate::SupportedLaneCount, - { - #[inline] - fn bitxor_assign(&mut self, rhs: bool) { - *self ^= Self::splat(rhs); - } - } - }; +impl Copy for Mask +where + T: MaskElement, + LaneCount: SupportedLaneCount, +{ } -define_opaque_mask! { - /// Mask for vectors with `LANES` 8-bit elements. +impl Clone for Mask +where + T: MaskElement, + LaneCount: SupportedLaneCount, +{ + fn clone(&self) -> Self { + *self + } +} + +impl Mask +where + T: MaskElement, + LaneCount: SupportedLaneCount, +{ + /// Construct a mask by setting all lanes to the given value. + pub fn splat(value: bool) -> Self { + Self(mask_impl::Mask::splat(value)) + } + + /// Converts an array to a SIMD vector. + pub fn from_array(array: [bool; LANES]) -> Self { + let mut vector = Self::splat(false); + for (i, v) in array.iter().enumerate() { + vector.set(i, *v); + } + vector + } + + /// Converts a SIMD vector to an array. + pub fn to_array(self) -> [bool; LANES] { + let mut array = [false; LANES]; + for (i, v) in array.iter_mut().enumerate() { + *v = self.test(i); + } + array + } + + /// Converts a vector of integers to a mask, where 0 represents `false` and -1 + /// represents `true`. /// - /// The layout of this type is unspecified. - struct Mask8(mask_impl::Mask8); - @bits SimdI8 + /// # Safety + /// All lanes must be either 0 or -1. + #[inline] + pub unsafe fn from_int_unchecked(value: Simd) -> Self { + Self(mask_impl::Mask::from_int_unchecked(value)) + } + + /// Converts a vector of integers to a mask, where 0 represents `false` and -1 + /// represents `true`. + /// + /// # Panics + /// Panics if any lane is not 0 or -1. + #[inline] + pub fn from_int(value: Simd) -> Self { + assert!(T::valid(value), "all values must be either 0 or -1",); + unsafe { Self::from_int_unchecked(value) } + } + + /// Converts the mask to a vector of integers, where 0 represents `false` and -1 + /// represents `true`. + #[inline] + pub fn to_int(self) -> Simd { + self.0.to_int() + } + + /// Tests the value of the specified lane. + /// + /// # Safety + /// `lane` must be less than `LANES`. + #[inline] + pub unsafe fn test_unchecked(&self, lane: usize) -> bool { + self.0.test_unchecked(lane) + } + + /// Tests the value of the specified lane. + /// + /// # Panics + /// Panics if `lane` is greater than or equal to the number of lanes in the vector. + #[inline] + pub fn test(&self, lane: usize) -> bool { + assert!(lane < LANES, "lane index out of range"); + unsafe { self.test_unchecked(lane) } + } + + /// Sets the value of the specified lane. + /// + /// # Safety + /// `lane` must be less than `LANES`. + #[inline] + pub unsafe fn set_unchecked(&mut self, lane: usize, value: bool) { + self.0.set_unchecked(lane, value); + } + + /// Sets the value of the specified lane. + /// + /// # Panics + /// Panics if `lane` is greater than or equal to the number of lanes in the vector. + #[inline] + pub fn set(&mut self, lane: usize, value: bool) { + assert!(lane < LANES, "lane index out of range"); + unsafe { + self.set_unchecked(lane, value); + } + } + + /// Convert this mask to a bitmask, with one bit set per lane. + pub fn to_bitmask(self) -> [u8; LaneCount::::BITMASK_LEN] { + self.0.to_bitmask() + } + + /// Convert a bitmask to a mask. + pub fn from_bitmask(bitmask: [u8; LaneCount::::BITMASK_LEN]) -> Self { + Self(mask_impl::Mask::from_bitmask(bitmask)) + } + + /// Returns true if any lane is set, or false otherwise. + #[inline] + pub fn any(self) -> bool { + self.0.any() + } + + /// Returns true if all lanes are set, or false otherwise. + #[inline] + pub fn all(self) -> bool { + self.0.all() + } } -define_opaque_mask! { - /// Mask for vectors with `LANES` 16-bit elements. - /// - /// The layout of this type is unspecified. - struct Mask16(mask_impl::Mask16); - @bits SimdI16 +// vector/array conversion +impl From<[bool; LANES]> for Mask +where + T: MaskElement, + LaneCount: SupportedLaneCount, +{ + fn from(array: [bool; LANES]) -> Self { + Self::from_array(array) + } } -define_opaque_mask! { - /// Mask for vectors with `LANES` 32-bit elements. - /// - /// The layout of this type is unspecified. - struct Mask32(mask_impl::Mask32); - @bits SimdI32 +impl From> for [bool; LANES] +where + T: MaskElement, + LaneCount: SupportedLaneCount, +{ + fn from(vector: Mask) -> Self { + vector.to_array() + } } -define_opaque_mask! { - /// Mask for vectors with `LANES` 64-bit elements. - /// - /// The layout of this type is unspecified. - struct Mask64(mask_impl::Mask64); - @bits SimdI64 +impl Default for Mask +where + T: MaskElement, + LaneCount: SupportedLaneCount, +{ + #[inline] + fn default() -> Self { + Self::splat(false) + } } -define_opaque_mask! { - /// Mask for vectors with `LANES` pointer-width elements. - /// - /// The layout of this type is unspecified. - struct MaskSize(mask_impl::MaskSize); - @bits SimdIsize +impl PartialEq for Mask +where + T: MaskElement + PartialEq, + LaneCount: SupportedLaneCount, +{ + #[inline] + fn eq(&self, other: &Self) -> bool { + self.0 == other.0 + } +} + +impl PartialOrd for Mask +where + T: MaskElement + PartialOrd, + LaneCount: SupportedLaneCount, +{ + #[inline] + fn partial_cmp(&self, other: &Self) -> Option { + self.0.partial_cmp(&other.0) + } +} + +impl core::fmt::Debug for Mask +where + T: MaskElement + core::fmt::Debug, + LaneCount: SupportedLaneCount, +{ + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + f.debug_list() + .entries((0..LANES).map(|lane| self.test(lane))) + .finish() + } +} + +impl core::ops::BitAnd for Mask +where + T: MaskElement, + LaneCount: SupportedLaneCount, +{ + type Output = Self; + #[inline] + fn bitand(self, rhs: Self) -> Self { + Self(self.0 & rhs.0) + } +} + +impl core::ops::BitAnd for Mask +where + T: MaskElement, + LaneCount: SupportedLaneCount, +{ + type Output = Self; + #[inline] + fn bitand(self, rhs: bool) -> Self { + self & Self::splat(rhs) + } +} + +impl core::ops::BitAnd> for bool +where + T: MaskElement, + LaneCount: SupportedLaneCount, +{ + type Output = Mask; + #[inline] + fn bitand(self, rhs: Mask) -> Mask { + Mask::splat(self) & rhs + } +} + +impl core::ops::BitOr for Mask +where + T: MaskElement, + LaneCount: SupportedLaneCount, +{ + type Output = Self; + #[inline] + fn bitor(self, rhs: Self) -> Self { + Self(self.0 | rhs.0) + } +} + +impl core::ops::BitOr for Mask +where + T: MaskElement, + LaneCount: SupportedLaneCount, +{ + type Output = Self; + #[inline] + fn bitor(self, rhs: bool) -> Self { + self | Self::splat(rhs) + } +} + +impl core::ops::BitOr> for bool +where + T: MaskElement, + LaneCount: SupportedLaneCount, +{ + type Output = Mask; + #[inline] + fn bitor(self, rhs: Mask) -> Mask { + Mask::splat(self) | rhs + } +} + +impl core::ops::BitXor for Mask +where + T: MaskElement, + LaneCount: SupportedLaneCount, +{ + type Output = Self; + #[inline] + fn bitxor(self, rhs: Self) -> Self::Output { + Self(self.0 ^ rhs.0) + } +} + +impl core::ops::BitXor for Mask +where + T: MaskElement, + LaneCount: SupportedLaneCount, +{ + type Output = Self; + #[inline] + fn bitxor(self, rhs: bool) -> Self::Output { + self ^ Self::splat(rhs) + } +} + +impl core::ops::BitXor> for bool +where + T: MaskElement, + LaneCount: SupportedLaneCount, +{ + type Output = Mask; + #[inline] + fn bitxor(self, rhs: Mask) -> Self::Output { + Mask::splat(self) ^ rhs + } +} + +impl core::ops::Not for Mask +where + T: MaskElement, + LaneCount: SupportedLaneCount, +{ + type Output = Mask; + #[inline] + fn not(self) -> Self::Output { + Self(!self.0) + } +} + +impl core::ops::BitAndAssign for Mask +where + T: MaskElement, + LaneCount: SupportedLaneCount, +{ + #[inline] + fn bitand_assign(&mut self, rhs: Self) { + self.0 = self.0 & rhs.0; + } +} + +impl core::ops::BitAndAssign for Mask +where + T: MaskElement, + LaneCount: SupportedLaneCount, +{ + #[inline] + fn bitand_assign(&mut self, rhs: bool) { + *self &= Self::splat(rhs); + } +} + +impl core::ops::BitOrAssign for Mask +where + T: MaskElement, + LaneCount: SupportedLaneCount, +{ + #[inline] + fn bitor_assign(&mut self, rhs: Self) { + self.0 = self.0 | rhs.0; + } +} + +impl core::ops::BitOrAssign for Mask +where + T: MaskElement, + LaneCount: SupportedLaneCount, +{ + #[inline] + fn bitor_assign(&mut self, rhs: bool) { + *self |= Self::splat(rhs); + } +} + +impl core::ops::BitXorAssign for Mask +where + T: MaskElement, + LaneCount: SupportedLaneCount, +{ + #[inline] + fn bitxor_assign(&mut self, rhs: Self) { + self.0 = self.0 ^ rhs.0; + } +} + +impl core::ops::BitXorAssign for Mask +where + T: MaskElement, + LaneCount: SupportedLaneCount, +{ + #[inline] + fn bitxor_assign(&mut self, rhs: bool) { + *self ^= Self::splat(rhs); + } } /// Vector of eight 8-bit masks -pub type mask8x8 = Mask8<8>; +pub type mask8x8 = Mask; /// Vector of 16 8-bit masks -pub type mask8x16 = Mask8<16>; +pub type mask8x16 = Mask; /// Vector of 32 8-bit masks -pub type mask8x32 = Mask8<32>; +pub type mask8x32 = Mask; /// Vector of 16 8-bit masks -pub type mask8x64 = Mask8<64>; +pub type mask8x64 = Mask; /// Vector of four 16-bit masks -pub type mask16x4 = Mask16<4>; +pub type mask16x4 = Mask; /// Vector of eight 16-bit masks -pub type mask16x8 = Mask16<8>; +pub type mask16x8 = Mask; /// Vector of 16 16-bit masks -pub type mask16x16 = Mask16<16>; +pub type mask16x16 = Mask; /// Vector of 32 16-bit masks -pub type mask16x32 = Mask32<32>; +pub type mask16x32 = Mask; /// Vector of two 32-bit masks -pub type mask32x2 = Mask32<2>; +pub type mask32x2 = Mask; /// Vector of four 32-bit masks -pub type mask32x4 = Mask32<4>; +pub type mask32x4 = Mask; /// Vector of eight 32-bit masks -pub type mask32x8 = Mask32<8>; +pub type mask32x8 = Mask; /// Vector of 16 32-bit masks -pub type mask32x16 = Mask32<16>; +pub type mask32x16 = Mask; /// Vector of two 64-bit masks -pub type mask64x2 = Mask64<2>; +pub type mask64x2 = Mask; /// Vector of four 64-bit masks -pub type mask64x4 = Mask64<4>; +pub type mask64x4 = Mask; /// Vector of eight 64-bit masks -pub type mask64x8 = Mask64<8>; +pub type mask64x8 = Mask; /// Vector of two pointer-width masks -pub type masksizex2 = MaskSize<2>; +pub type masksizex2 = Mask; /// Vector of four pointer-width masks -pub type masksizex4 = MaskSize<4>; +pub type masksizex4 = Mask; /// Vector of eight pointer-width masks -pub type masksizex8 = MaskSize<8>; +pub type masksizex8 = Mask; macro_rules! impl_from { - { $from:ident ($from_inner:ident) => $($to:ident ($to_inner:ident)),* } => { + { $from:ty => $($to:ty),* } => { $( - impl From<$from> for $to + impl From> for Mask<$to, LANES> where - crate::LaneCount: crate::SupportedLaneCount, + LaneCount: SupportedLaneCount, { - fn from(value: $from) -> Self { - Self(value.0.into()) + fn from(value: Mask<$from, LANES>) -> Self { + Self(value.0.convert()) } } )* } } -impl_from! { Mask8 (SimdI8) => Mask16 (SimdI16), Mask32 (SimdI32), Mask64 (SimdI64), MaskSize (SimdIsize) } -impl_from! { Mask16 (SimdI16) => Mask32 (SimdI32), Mask64 (SimdI64), MaskSize (SimdIsize), Mask8 (SimdI8) } -impl_from! { Mask32 (SimdI32) => Mask64 (SimdI64), MaskSize (SimdIsize), Mask8 (SimdI8), Mask16 (SimdI16) } -impl_from! { Mask64 (SimdI64) => MaskSize (SimdIsize), Mask8 (SimdI8), Mask16 (SimdI16), Mask32 (SimdI32) } -impl_from! { MaskSize (SimdIsize) => Mask8 (SimdI8), Mask16 (SimdI16), Mask32 (SimdI32), Mask64 (SimdI64) } +impl_from! { i8 => i16, i32, i64, isize } +impl_from! { i16 => i32, i64, isize, i8 } +impl_from! { i32 => i64, isize, i8, i16 } +impl_from! { i64 => isize, i8, i16, i32 } +impl_from! { isize => i8, i16, i32, i64 } diff --git a/crates/core_simd/src/masks/bitmask.rs b/crates/core_simd/src/masks/bitmask.rs index 69edd5235872..0b5b3a5c595e 100644 --- a/crates/core_simd/src/masks/bitmask.rs +++ b/crates/core_simd/src/masks/bitmask.rs @@ -1,38 +1,26 @@ -use crate::{LaneCount, SupportedLaneCount}; - -/// Helper trait for limiting int conversion types -pub trait ConvertToInt {} -impl ConvertToInt for crate::SimdI8 where - LaneCount: SupportedLaneCount -{ -} -impl ConvertToInt for crate::SimdI16 where - LaneCount: SupportedLaneCount -{ -} -impl ConvertToInt for crate::SimdI32 where - LaneCount: SupportedLaneCount -{ -} -impl ConvertToInt for crate::SimdI64 where - LaneCount: SupportedLaneCount -{ -} -impl ConvertToInt for crate::SimdIsize where - LaneCount: SupportedLaneCount -{ -} +use crate::{LaneCount, MaskElement, Simd, SupportedLaneCount}; +use core::marker::PhantomData; /// A mask where each lane is represented by a single bit. #[repr(transparent)] -pub struct BitMask( as SupportedLaneCount>::BitMask) +pub struct Mask( + as SupportedLaneCount>::BitMask, + PhantomData, +) where + T: MaskElement, LaneCount: SupportedLaneCount; -impl Copy for BitMask where LaneCount: SupportedLaneCount {} - -impl Clone for BitMask +impl Copy for Mask where + T: MaskElement, + LaneCount: SupportedLaneCount, +{ +} + +impl Clone for Mask +where + T: MaskElement, LaneCount: SupportedLaneCount, { fn clone(&self) -> Self { @@ -40,8 +28,9 @@ where } } -impl PartialEq for BitMask +impl PartialEq for Mask where + T: MaskElement, LaneCount: SupportedLaneCount, { fn eq(&self, other: &Self) -> bool { @@ -49,8 +38,9 @@ where } } -impl PartialOrd for BitMask +impl PartialOrd for Mask where + T: MaskElement, LaneCount: SupportedLaneCount, { fn partial_cmp(&self, other: &Self) -> Option { @@ -58,10 +48,16 @@ where } } -impl Eq for BitMask where LaneCount: SupportedLaneCount {} - -impl Ord for BitMask +impl Eq for Mask where + T: MaskElement, + LaneCount: SupportedLaneCount, +{ +} + +impl Ord for Mask +where + T: MaskElement, LaneCount: SupportedLaneCount, { fn cmp(&self, other: &Self) -> core::cmp::Ordering { @@ -69,8 +65,9 @@ where } } -impl BitMask +impl Mask where + T: MaskElement, LaneCount: SupportedLaneCount, { #[inline] @@ -84,7 +81,7 @@ where if LANES % 8 > 0 { *mask.as_mut().last_mut().unwrap() &= u8::MAX >> (8 - LANES % 8); } - Self(mask) + Self(mask, PhantomData) } #[inline] @@ -98,33 +95,28 @@ where } #[inline] - pub fn to_int(self) -> V - where - V: ConvertToInt + Default + core::ops::Not, - { + pub fn to_int(self) -> Simd { unsafe { let mask: as SupportedLaneCount>::IntBitMask = core::mem::transmute_copy(&self); - crate::intrinsics::simd_select_bitmask(mask, !V::default(), V::default()) + crate::intrinsics::simd_select_bitmask( + mask, + Simd::splat(T::TRUE), + Simd::splat(T::FALSE), + ) } } #[inline] - pub unsafe fn from_int_unchecked(value: V) -> Self - where - V: crate::Vector, - { + pub unsafe fn from_int_unchecked(value: Simd) -> Self { // TODO remove the transmute when rustc is more flexible assert_eq!( - core::mem::size_of::< as crate::SupportedLaneCount>::BitMask>( - ), - core::mem::size_of::< - as crate::SupportedLaneCount>::IntBitMask, - >(), + core::mem::size_of::< as SupportedLaneCount>::BitMask>(), + core::mem::size_of::< as SupportedLaneCount>::IntBitMask>(), ); let mask: as SupportedLaneCount>::IntBitMask = crate::intrinsics::simd_bitmask(value); - Self(core::mem::transmute_copy(&mask)) + Self(core::mem::transmute_copy(&mask), PhantomData) } #[inline] @@ -136,7 +128,15 @@ where #[inline] pub fn from_bitmask(bitmask: [u8; LaneCount::::BITMASK_LEN]) -> Self { // Safety: these are the same type and we are laundering the generic - Self(unsafe { core::mem::transmute_copy(&bitmask) }) + Self(unsafe { core::mem::transmute_copy(&bitmask) }, PhantomData) + } + + #[inline] + pub fn convert(self) -> Mask + where + U: MaskElement, + { + unsafe { core::mem::transmute_copy(&self) } } #[inline] @@ -150,10 +150,11 @@ where } } -impl core::ops::BitAnd for BitMask +impl core::ops::BitAnd for Mask where + T: MaskElement, LaneCount: SupportedLaneCount, - as SupportedLaneCount>::BitMask: Default + AsRef<[u8]> + AsMut<[u8]>, + as SupportedLaneCount>::BitMask: AsRef<[u8]> + AsMut<[u8]>, { type Output = Self; #[inline] @@ -165,10 +166,11 @@ where } } -impl core::ops::BitOr for BitMask +impl core::ops::BitOr for Mask where + T: MaskElement, LaneCount: SupportedLaneCount, - as SupportedLaneCount>::BitMask: Default + AsRef<[u8]> + AsMut<[u8]>, + as SupportedLaneCount>::BitMask: AsRef<[u8]> + AsMut<[u8]>, { type Output = Self; #[inline] @@ -180,8 +182,9 @@ where } } -impl core::ops::BitXor for BitMask +impl core::ops::BitXor for Mask where + T: MaskElement, LaneCount: SupportedLaneCount, { type Output = Self; @@ -194,8 +197,9 @@ where } } -impl core::ops::Not for BitMask +impl core::ops::Not for Mask where + T: MaskElement, LaneCount: SupportedLaneCount, { type Output = Self; @@ -210,9 +214,3 @@ where self } } - -pub type Mask8 = BitMask; -pub type Mask16 = BitMask; -pub type Mask32 = BitMask; -pub type Mask64 = BitMask; -pub type MaskSize = BitMask; diff --git a/crates/core_simd/src/masks/full_masks.rs b/crates/core_simd/src/masks/full_masks.rs index 2923cf1964a0..9c1cc4623f9a 100644 --- a/crates/core_simd/src/masks/full_masks.rs +++ b/crates/core_simd/src/masks/full_masks.rs @@ -1,264 +1,225 @@ //! Masks that take up full SIMD vector registers. -macro_rules! define_mask { +use super::MaskElement; +use crate::{LaneCount, Simd, SupportedLaneCount}; + +#[repr(transparent)] +pub struct Mask(Simd) +where + T: MaskElement, + LaneCount: SupportedLaneCount; + +impl Copy for Mask +where + T: MaskElement, + LaneCount: SupportedLaneCount, +{ +} + +impl Clone for Mask +where + T: MaskElement, + LaneCount: SupportedLaneCount, +{ + #[inline] + fn clone(&self) -> Self { + *self + } +} + +impl PartialEq for Mask +where + T: MaskElement + PartialEq, + LaneCount: SupportedLaneCount, +{ + fn eq(&self, other: &Self) -> bool { + self.0.eq(&other.0) + } +} + +impl PartialOrd for Mask +where + T: MaskElement + PartialOrd, + LaneCount: SupportedLaneCount, +{ + fn partial_cmp(&self, other: &Self) -> Option { + self.0.partial_cmp(&other.0) + } +} + +impl Eq for Mask +where + T: MaskElement + Eq, + LaneCount: SupportedLaneCount, +{ +} + +impl Ord for Mask +where + T: MaskElement + Ord, + LaneCount: SupportedLaneCount, +{ + fn cmp(&self, other: &Self) -> core::cmp::Ordering { + self.0.cmp(&other.0) + } +} + +impl Mask +where + T: MaskElement, + LaneCount: SupportedLaneCount, +{ + pub fn splat(value: bool) -> Self { + Self(Simd::splat(if value { T::TRUE } else { T::FALSE })) + } + + #[inline] + pub unsafe fn test_unchecked(&self, lane: usize) -> bool { + T::eq(self.0[lane], T::TRUE) + } + + #[inline] + pub unsafe fn set_unchecked(&mut self, lane: usize, value: bool) { + self.0[lane] = if value { T::TRUE } else { T::FALSE } + } + + #[inline] + pub fn to_int(self) -> Simd { + self.0 + } + + #[inline] + pub unsafe fn from_int_unchecked(value: Simd) -> Self { + Self(value) + } + + #[inline] + pub fn convert(self) -> Mask + where + U: MaskElement, { - $(#[$attr:meta])* - struct $name:ident( - crate::$type:ident<$lanes2:ident> - ); - } => { - $(#[$attr])* - #[repr(transparent)] - pub struct $name(crate::$type<$lanes>) - where - crate::LaneCount<$lanes>: crate::SupportedLaneCount; + unsafe { Mask(crate::intrinsics::simd_cast(self.0)) } + } - impl_full_mask_reductions! { $name, $type } + #[inline] + pub fn to_bitmask(self) -> [u8; LaneCount::::BITMASK_LEN] { + unsafe { + // TODO remove the transmute when rustc can use arrays of u8 as bitmasks + assert_eq!( + core::mem::size_of::< as SupportedLaneCount>::IntBitMask>(), + LaneCount::::BITMASK_LEN, + ); + let bitmask: as SupportedLaneCount>::IntBitMask = + crate::intrinsics::simd_bitmask(self.0); + let mut bitmask: [u8; LaneCount::::BITMASK_LEN] = + core::mem::transmute_copy(&bitmask); - impl Copy for $name - where - crate::LaneCount: crate::SupportedLaneCount, - {} - - impl Clone for $name - where - crate::LaneCount: crate::SupportedLaneCount, - { - #[inline] - fn clone(&self) -> Self { - *self - } - } - - impl PartialEq for $name - where - crate::LaneCount: crate::SupportedLaneCount, - { - fn eq(&self, other: &Self) -> bool { - self.0 == other.0 - } - } - - impl PartialOrd for $name - where - crate::LaneCount: crate::SupportedLaneCount, - { - fn partial_cmp(&self, other: &Self) -> Option { - self.0.partial_cmp(&other.0) - } - } - - impl Eq for $name - where - crate::LaneCount: crate::SupportedLaneCount, - {} - - impl Ord for $name - where - crate::LaneCount: crate::SupportedLaneCount, - { - fn cmp(&self, other: &Self) -> core::cmp::Ordering { - self.0.cmp(&other.0) - } - } - - impl $name - where - crate::LaneCount: crate::SupportedLaneCount, - { - pub fn splat(value: bool) -> Self { - Self( - >::splat( - if value { - -1 - } else { - 0 - } - ), - ) - } - - #[inline] - pub unsafe fn test_unchecked(&self, lane: usize) -> bool { - self.0[lane] == -1 - } - - #[inline] - pub unsafe fn set_unchecked(&mut self, lane: usize, value: bool) { - self.0[lane] = if value { - -1 - } else { - 0 + // There is a bug where LLVM appears to implement this operation with the wrong + // bit order. + // TODO fix this in a better way + if cfg!(any(target_arch = "mips", target_arch = "mips64")) { + for x in bitmask.as_mut() { + *x = x.reverse_bits(); } } - #[inline] - pub fn to_int(self) -> crate::$type { - self.0 - } + bitmask + } + } - #[inline] - pub unsafe fn from_int_unchecked(value: crate::$type) -> Self { - Self(value) - } - - #[inline] - pub fn to_bitmask(self) -> [u8; crate::LaneCount::::BITMASK_LEN] { - unsafe { - // TODO remove the transmute when rustc can use arrays of u8 as bitmasks - assert_eq!( - core::mem::size_of::< as crate::SupportedLaneCount>::IntBitMask>(), - crate::LaneCount::::BITMASK_LEN, - ); - let bitmask: as crate::SupportedLaneCount>::IntBitMask = crate::intrinsics::simd_bitmask(self.0); - let mut bitmask: [u8; crate::LaneCount::::BITMASK_LEN] = core::mem::transmute_copy(&bitmask); - - // There is a bug where LLVM appears to implement this operation with the wrong - // bit order. - // TODO fix this in a better way - if cfg!(any(target_arch = "mips", target_arch = "mips64")) { - for x in bitmask.as_mut() { - *x = x.reverse_bits(); - } - } - - bitmask + #[inline] + pub fn from_bitmask(mut bitmask: [u8; LaneCount::::BITMASK_LEN]) -> Self { + unsafe { + // There is a bug where LLVM appears to implement this operation with the wrong + // bit order. + // TODO fix this in a better way + if cfg!(any(target_arch = "mips", target_arch = "mips64")) { + for x in bitmask.as_mut() { + *x = x.reverse_bits(); } } - #[inline] - pub fn from_bitmask(mut bitmask: [u8; crate::LaneCount::::BITMASK_LEN]) -> Self { - unsafe { - // There is a bug where LLVM appears to implement this operation with the wrong - // bit order. - // TODO fix this in a better way - if cfg!(any(target_arch = "mips", target_arch = "mips64")) { - for x in bitmask.as_mut() { - *x = x.reverse_bits(); - } - } + // TODO remove the transmute when rustc can use arrays of u8 as bitmasks + assert_eq!( + core::mem::size_of::< as SupportedLaneCount>::IntBitMask>(), + LaneCount::::BITMASK_LEN, + ); + let bitmask: as SupportedLaneCount>::IntBitMask = + core::mem::transmute_copy(&bitmask); - // TODO remove the transmute when rustc can use arrays of u8 as bitmasks - assert_eq!( - core::mem::size_of::< as crate::SupportedLaneCount>::IntBitMask>(), - crate::LaneCount::::BITMASK_LEN, - ); - let bitmask: as crate::SupportedLaneCount>::IntBitMask = core::mem::transmute_copy(&bitmask); - - Self::from_int_unchecked(crate::intrinsics::simd_select_bitmask( - bitmask, - Self::splat(true).to_int(), - Self::splat(false).to_int(), - )) - } - } + Self::from_int_unchecked(crate::intrinsics::simd_select_bitmask( + bitmask, + Self::splat(true).to_int(), + Self::splat(false).to_int(), + )) } + } - impl core::convert::From<$name> for crate::$type - where - crate::LaneCount: crate::SupportedLaneCount, - { - fn from(value: $name) -> Self { - value.0 - } - } + #[inline] + pub fn any(self) -> bool { + unsafe { crate::intrinsics::simd_reduce_any(self.to_int()) } + } - impl core::ops::BitAnd for $name - where - crate::LaneCount: crate::SupportedLaneCount, - { - type Output = Self; - #[inline] - fn bitand(self, rhs: Self) -> Self { - Self(self.0 & rhs.0) - } - } - - impl core::ops::BitOr for $name - where - crate::LaneCount: crate::SupportedLaneCount, - { - type Output = Self; - #[inline] - fn bitor(self, rhs: Self) -> Self { - Self(self.0 | rhs.0) - } - } - - impl core::ops::BitXor for $name - where - crate::LaneCount: crate::SupportedLaneCount, - { - type Output = Self; - #[inline] - fn bitxor(self, rhs: Self) -> Self::Output { - Self(self.0 ^ rhs.0) - } - } - - impl core::ops::Not for $name - where - crate::LaneCount: crate::SupportedLaneCount, - { - type Output = Self; - #[inline] - fn not(self) -> Self::Output { - Self(!self.0) - } - } + #[inline] + pub fn all(self) -> bool { + unsafe { crate::intrinsics::simd_reduce_all(self.to_int()) } } } -define_mask! { - /// A mask equivalent to [SimdI8](crate::SimdI8), where all bits in the lane must be either set - /// or unset. - struct Mask8(crate::SimdI8); -} - -define_mask! { - /// A mask equivalent to [SimdI16](crate::SimdI16), where all bits in the lane must be either set - /// or unset. - struct Mask16(crate::SimdI16); -} - -define_mask! { - /// A mask equivalent to [SimdI32](crate::SimdI32), where all bits in the lane must be either set - /// or unset. - struct Mask32(crate::SimdI32); -} - -define_mask! { - /// A mask equivalent to [SimdI64](crate::SimdI64), where all bits in the lane must be either set - /// or unset. - struct Mask64(crate::SimdI64); -} - -define_mask! { - /// A mask equivalent to [SimdIsize](crate::SimdIsize), where all bits in the lane must be either set - /// or unset. - struct MaskSize(crate::SimdIsize); -} - -macro_rules! impl_from { - { $from:ident ($from_inner:ident) => $($to:ident ($to_inner:ident)),* } => { - $( - impl From<$from> for $to - where - crate::LaneCount: crate::SupportedLaneCount, - { - fn from(value: $from) -> Self { - let mut new = Self::splat(false); - for i in 0..LANES { - unsafe { new.set_unchecked(i, value.test_unchecked(i)) } - } - new - } - } - )* +impl core::convert::From> for Simd +where + T: MaskElement, + LaneCount: SupportedLaneCount, +{ + fn from(value: Mask) -> Self { + value.0 + } +} + +impl core::ops::BitAnd for Mask +where + T: MaskElement, + LaneCount: SupportedLaneCount, +{ + type Output = Self; + #[inline] + fn bitand(self, rhs: Self) -> Self { + unsafe { Self(crate::intrinsics::simd_and(self.0, rhs.0)) } + } +} + +impl core::ops::BitOr for Mask +where + T: MaskElement, + LaneCount: SupportedLaneCount, +{ + type Output = Self; + #[inline] + fn bitor(self, rhs: Self) -> Self { + unsafe { Self(crate::intrinsics::simd_or(self.0, rhs.0)) } + } +} + +impl core::ops::BitXor for Mask +where + T: MaskElement, + LaneCount: SupportedLaneCount, +{ + type Output = Self; + #[inline] + fn bitxor(self, rhs: Self) -> Self { + unsafe { Self(crate::intrinsics::simd_xor(self.0, rhs.0)) } + } +} + +impl core::ops::Not for Mask +where + T: MaskElement, + LaneCount: SupportedLaneCount, +{ + type Output = Self; + #[inline] + fn not(self) -> Self::Output { + Self::splat(true) ^ self } } -impl_from! { Mask8 (SimdI8) => Mask16 (SimdI16), Mask32 (SimdI32), Mask64 (SimdI64), MaskSize (SimdIsize) } -impl_from! { Mask16 (SimdI16) => Mask32 (SimdI32), Mask64 (SimdI64), MaskSize (SimdIsize), Mask8 (SimdI8) } -impl_from! { Mask32 (SimdI32) => Mask64 (SimdI64), MaskSize (SimdIsize), Mask8 (SimdI8), Mask16 (SimdI16) } -impl_from! { Mask64 (SimdI64) => MaskSize (SimdIsize), Mask8 (SimdI8), Mask16 (SimdI16), Mask32 (SimdI32) } -impl_from! { MaskSize (SimdIsize) => Mask8 (SimdI8), Mask16 (SimdI16), Mask32 (SimdI32), Mask64 (SimdI64) } diff --git a/crates/core_simd/src/math.rs b/crates/core_simd/src/math.rs index 28720eb13e3c..7affecbafd68 100644 --- a/crates/core_simd/src/math.rs +++ b/crates/core_simd/src/math.rs @@ -1,6 +1,8 @@ +use crate::{LaneCount, Simd, SupportedLaneCount}; + macro_rules! impl_uint_arith { - ($(($name:ident, $n:ident)),+) => { - $( impl $name where crate::LaneCount: crate::SupportedLaneCount { + ($($ty:ty),+) => { + $( impl Simd<$ty, LANES> where LaneCount: SupportedLaneCount { /// Lanewise saturating add. /// @@ -8,9 +10,9 @@ macro_rules! impl_uint_arith { /// ``` /// # #![feature(portable_simd)] /// # use core_simd::*; - #[doc = concat!("# use core::", stringify!($n), "::MAX;")] - #[doc = concat!("let x = ", stringify!($name), "::from_array([2, 1, 0, MAX]);")] - #[doc = concat!("let max = ", stringify!($name), "::splat(MAX);")] + #[doc = concat!("# use core::", stringify!($ty), "::MAX;")] + /// let x = Simd::from_array([2, 1, 0, MAX]); + /// let max = Simd::splat(MAX); /// let unsat = x + max; /// let sat = x.saturating_add(max); /// assert_eq!(x - 1, unsat); @@ -27,13 +29,13 @@ macro_rules! impl_uint_arith { /// ``` /// # #![feature(portable_simd)] /// # use core_simd::*; - #[doc = concat!("# use core::", stringify!($n), "::MAX;")] - #[doc = concat!("let x = ", stringify!($name), "::from_array([2, 1, 0, MAX]);")] - #[doc = concat!("let max = ", stringify!($name), "::splat(MAX);")] + #[doc = concat!("# use core::", stringify!($ty), "::MAX;")] + /// let x = Simd::from_array([2, 1, 0, MAX]); + /// let max = Simd::splat(MAX); /// let unsat = x - max; /// let sat = x.saturating_sub(max); /// assert_eq!(unsat, x + 1); - #[doc = concat!("assert_eq!(sat, ", stringify!($name), "::splat(0));")] + /// assert_eq!(sat, Simd::splat(0)); #[inline] pub fn saturating_sub(self, second: Self) -> Self { unsafe { crate::intrinsics::simd_saturating_sub(self, second) } @@ -43,8 +45,8 @@ macro_rules! impl_uint_arith { } macro_rules! impl_int_arith { - ($(($name:ident, $n:ident)),+) => { - $( impl $name where crate::LaneCount: crate::SupportedLaneCount { + ($($ty:ty),+) => { + $( impl Simd<$ty, LANES> where LaneCount: SupportedLaneCount { /// Lanewise saturating add. /// @@ -52,13 +54,13 @@ macro_rules! impl_int_arith { /// ``` /// # #![feature(portable_simd)] /// # use core_simd::*; - #[doc = concat!("# use core::", stringify!($n), "::{MIN, MAX};")] - #[doc = concat!("let x = ", stringify!($name), "::from_array([MIN, 0, 1, MAX]);")] - #[doc = concat!("let max = ", stringify!($name), "::splat(MAX);")] + #[doc = concat!("# use core::", stringify!($ty), "::{MIN, MAX};")] + /// let x = Simd::from_array([MIN, 0, 1, MAX]); + /// let max = Simd::splat(MAX); /// let unsat = x + max; /// let sat = x.saturating_add(max); - #[doc = concat!("assert_eq!(unsat, ", stringify!($name), "::from_array([-1, MAX, MIN, -2]));")] - #[doc = concat!("assert_eq!(sat, ", stringify!($name), "::from_array([-1, MAX, MAX, MAX]));")] + /// assert_eq!(unsat, Simd::from_array([-1, MAX, MIN, -2])); + /// assert_eq!(sat, Simd::from_array([-1, MAX, MAX, MAX])); /// ``` #[inline] pub fn saturating_add(self, second: Self) -> Self { @@ -71,13 +73,13 @@ macro_rules! impl_int_arith { /// ``` /// # #![feature(portable_simd)] /// # use core_simd::*; - #[doc = concat!("# use core::", stringify!($n), "::{MIN, MAX};")] - #[doc = concat!("let x = ", stringify!($name), "::from_array([MIN, -2, -1, MAX]);")] - #[doc = concat!("let max = ", stringify!($name), "::splat(MAX);")] + #[doc = concat!("# use core::", stringify!($ty), "::{MIN, MAX};")] + /// let x = Simd::from_array([MIN, -2, -1, MAX]); + /// let max = Simd::splat(MAX); /// let unsat = x - max; /// let sat = x.saturating_sub(max); - #[doc = concat!("assert_eq!(unsat, ", stringify!($name), "::from_array([1, MAX, MIN, 0]));")] - #[doc = concat!("assert_eq!(sat, ", stringify!($name), "::from_array([MIN, MIN, MIN, 0]));")] + /// assert_eq!(unsat, Simd::from_array([1, MAX, MIN, 0])); + /// assert_eq!(sat, Simd::from_array([MIN, MIN, MIN, 0])); #[inline] pub fn saturating_sub(self, second: Self) -> Self { unsafe { crate::intrinsics::simd_saturating_sub(self, second) } @@ -90,13 +92,13 @@ macro_rules! impl_int_arith { /// ``` /// # #![feature(portable_simd)] /// # use core_simd::*; - #[doc = concat!("# use core::", stringify!($n), "::{MIN, MAX};")] - #[doc = concat!("let xs = ", stringify!($name), "::from_array([MIN, MIN +1, -5, 0]);")] - #[doc = concat!("assert_eq!(xs.abs(), ", stringify!($name), "::from_array([MIN, MAX, 5, 0]));")] + #[doc = concat!("# use core::", stringify!($ty), "::{MIN, MAX};")] + /// let xs = Simd::from_array([MIN, MIN +1, -5, 0]); + /// assert_eq!(xs.abs(), Simd::from_array([MIN, MAX, 5, 0])); /// ``` #[inline] pub fn abs(self) -> Self { - const SHR: $n = <$n>::BITS as $n - 1; + const SHR: $ty = <$ty>::BITS as $ty - 1; let m = self >> SHR; (self^m) - m } @@ -108,17 +110,17 @@ macro_rules! impl_int_arith { /// ``` /// # #![feature(portable_simd)] /// # use core_simd::*; - #[doc = concat!("# use core::", stringify!($n), "::{MIN, MAX};")] - #[doc = concat!("let xs = ", stringify!($name), "::from_array([MIN, -2, 0, 3]);")] + #[doc = concat!("# use core::", stringify!($ty), "::{MIN, MAX};")] + /// let xs = Simd::from_array([MIN, -2, 0, 3]); /// let unsat = xs.abs(); /// let sat = xs.saturating_abs(); - #[doc = concat!("assert_eq!(unsat, ", stringify!($name), "::from_array([MIN, 2, 0, 3]));")] - #[doc = concat!("assert_eq!(sat, ", stringify!($name), "::from_array([MAX, 2, 0, 3]));")] + /// assert_eq!(unsat, Simd::from_array([MIN, 2, 0, 3])); + /// assert_eq!(sat, Simd::from_array([MAX, 2, 0, 3])); /// ``` #[inline] pub fn saturating_abs(self) -> Self { // arith shift for -1 or 0 mask based on sign bit, giving 2s complement - const SHR: $n = <$n>::BITS as $n - 1; + const SHR: $ty = <$ty>::BITS as $ty - 1; let m = self >> SHR; (self^m).saturating_sub(m) } @@ -130,12 +132,12 @@ macro_rules! impl_int_arith { /// ``` /// # #![feature(portable_simd)] /// # use core_simd::*; - #[doc = concat!("# use core::", stringify!($n), "::{MIN, MAX};")] - #[doc = concat!("let x = ", stringify!($name), "::from_array([MIN, -2, 3, MAX]);")] + #[doc = concat!("# use core::", stringify!($ty), "::{MIN, MAX};")] + /// let x = Simd::from_array([MIN, -2, 3, MAX]); /// let unsat = -x; /// let sat = x.saturating_neg(); - #[doc = concat!("assert_eq!(unsat, ", stringify!($name), "::from_array([MIN, 2, -3, MIN + 1]));")] - #[doc = concat!("assert_eq!(sat, ", stringify!($name), "::from_array([MAX, 2, -3, MIN + 1]));")] + /// assert_eq!(unsat, Simd::from_array([MIN, 2, -3, MIN + 1])); + /// assert_eq!(sat, Simd::from_array([MAX, 2, -3, MIN + 1])); /// ``` #[inline] pub fn saturating_neg(self) -> Self { @@ -145,7 +147,5 @@ macro_rules! impl_int_arith { } } -use crate::vector::*; - -impl_uint_arith! { (SimdU8, u8), (SimdU16, u16), (SimdU32, u32), (SimdU64, u64), (SimdUsize, usize) } -impl_int_arith! { (SimdI8, i8), (SimdI16, i16), (SimdI32, i32), (SimdI64, i64), (SimdIsize, isize) } +impl_uint_arith! { u8, u16, u32, u64, usize } +impl_int_arith! { i8, i16, i32, i64, isize } diff --git a/crates/core_simd/src/ops.rs b/crates/core_simd/src/ops.rs index c75090aab9c5..900315660005 100644 --- a/crates/core_simd/src/ops.rs +++ b/crates/core_simd/src/ops.rs @@ -1,4 +1,27 @@ -use crate::{LaneCount, SupportedLaneCount}; +use crate::{LaneCount, Simd, SimdElement, SupportedLaneCount}; + +impl core::ops::Index for Simd +where + T: SimdElement, + LaneCount: SupportedLaneCount, + I: core::slice::SliceIndex<[T]>, +{ + type Output = I::Output; + fn index(&self, index: I) -> &Self::Output { + &self.as_array()[index] + } +} + +impl core::ops::IndexMut for Simd +where + T: SimdElement, + LaneCount: SupportedLaneCount, + I: core::slice::SliceIndex<[T]>, +{ + fn index_mut(&mut self, index: I) -> &mut Self::Output { + &mut self.as_mut_array()[index] + } +} /// Checks if the right-hand side argument of a left- or right-shift would cause overflow. fn invalid_shift_rhs(rhs: T) -> bool @@ -132,40 +155,40 @@ macro_rules! impl_ref_ops { /// Automatically implements operators over vectors and scalars for a particular vector. macro_rules! impl_op { - { impl Add for $type:ident, $scalar:ty } => { - impl_op! { @binary $type, $scalar, Add::add, AddAssign::add_assign, simd_add } + { impl Add for $scalar:ty } => { + impl_op! { @binary $scalar, Add::add, AddAssign::add_assign, simd_add } }; - { impl Sub for $type:ident, $scalar:ty } => { - impl_op! { @binary $type, $scalar, Sub::sub, SubAssign::sub_assign, simd_sub } + { impl Sub for $scalar:ty } => { + impl_op! { @binary $scalar, Sub::sub, SubAssign::sub_assign, simd_sub } }; - { impl Mul for $type:ident, $scalar:ty } => { - impl_op! { @binary $type, $scalar, Mul::mul, MulAssign::mul_assign, simd_mul } + { impl Mul for $scalar:ty } => { + impl_op! { @binary $scalar, Mul::mul, MulAssign::mul_assign, simd_mul } }; - { impl Div for $type:ident, $scalar:ty } => { - impl_op! { @binary $type, $scalar, Div::div, DivAssign::div_assign, simd_div } + { impl Div for $scalar:ty } => { + impl_op! { @binary $scalar, Div::div, DivAssign::div_assign, simd_div } }; - { impl Rem for $type:ident, $scalar:ty } => { - impl_op! { @binary $type, $scalar, Rem::rem, RemAssign::rem_assign, simd_rem } + { impl Rem for $scalar:ty } => { + impl_op! { @binary $scalar, Rem::rem, RemAssign::rem_assign, simd_rem } }; - { impl Shl for $type:ident, $scalar:ty } => { - impl_op! { @binary $type, $scalar, Shl::shl, ShlAssign::shl_assign, simd_shl } + { impl Shl for $scalar:ty } => { + impl_op! { @binary $scalar, Shl::shl, ShlAssign::shl_assign, simd_shl } }; - { impl Shr for $type:ident, $scalar:ty } => { - impl_op! { @binary $type, $scalar, Shr::shr, ShrAssign::shr_assign, simd_shr } + { impl Shr for $scalar:ty } => { + impl_op! { @binary $scalar, Shr::shr, ShrAssign::shr_assign, simd_shr } }; - { impl BitAnd for $type:ident, $scalar:ty } => { - impl_op! { @binary $type, $scalar, BitAnd::bitand, BitAndAssign::bitand_assign, simd_and } + { impl BitAnd for $scalar:ty } => { + impl_op! { @binary $scalar, BitAnd::bitand, BitAndAssign::bitand_assign, simd_and } }; - { impl BitOr for $type:ident, $scalar:ty } => { - impl_op! { @binary $type, $scalar, BitOr::bitor, BitOrAssign::bitor_assign, simd_or } + { impl BitOr for $scalar:ty } => { + impl_op! { @binary $scalar, BitOr::bitor, BitOrAssign::bitor_assign, simd_or } }; - { impl BitXor for $type:ident, $scalar:ty } => { - impl_op! { @binary $type, $scalar, BitXor::bitxor, BitXorAssign::bitxor_assign, simd_xor } + { impl BitXor for $scalar:ty } => { + impl_op! { @binary $scalar, BitXor::bitxor, BitXorAssign::bitxor_assign, simd_xor } }; - { impl Not for $type:ident, $scalar:ty } => { + { impl Not for $scalar:ty } => { impl_ref_ops! { - impl core::ops::Not for crate::$type + impl core::ops::Not for Simd<$scalar, LANES> where LaneCount: SupportedLaneCount, { @@ -177,9 +200,9 @@ macro_rules! impl_op { } }; - { impl Neg for $type:ident, $scalar:ty } => { + { impl Neg for $scalar:ty } => { impl_ref_ops! { - impl core::ops::Neg for crate::$type + impl core::ops::Neg for Simd<$scalar, LANES> where LaneCount: SupportedLaneCount, { @@ -191,35 +214,10 @@ macro_rules! impl_op { } }; - { impl Index for $type:ident, $scalar:ty } => { - impl core::ops::Index for crate::$type - where - LaneCount: SupportedLaneCount, - I: core::slice::SliceIndex<[$scalar]>, - { - type Output = I::Output; - fn index(&self, index: I) -> &Self::Output { - let slice: &[_] = self.as_ref(); - &slice[index] - } - } - - impl core::ops::IndexMut for crate::$type - where - LaneCount: SupportedLaneCount, - I: core::slice::SliceIndex<[$scalar]>, - { - fn index_mut(&mut self, index: I) -> &mut Self::Output { - let slice: &mut [_] = self.as_mut(); - &mut slice[index] - } - } - }; - // generic binary op with assignment when output is `Self` - { @binary $type:ident, $scalar:ty, $trait:ident :: $trait_fn:ident, $assign_trait:ident :: $assign_trait_fn:ident, $intrinsic:ident } => { + { @binary $scalar:ty, $trait:ident :: $trait_fn:ident, $assign_trait:ident :: $assign_trait_fn:ident, $intrinsic:ident } => { impl_ref_ops! { - impl core::ops::$trait for crate::$type + impl core::ops::$trait for Simd<$scalar, LANES> where LaneCount: SupportedLaneCount, { @@ -235,7 +233,7 @@ macro_rules! impl_op { } impl_ref_ops! { - impl core::ops::$trait<$scalar> for crate::$type + impl core::ops::$trait<$scalar> for Simd<$scalar, LANES> where LaneCount: SupportedLaneCount, { @@ -249,21 +247,21 @@ macro_rules! impl_op { } impl_ref_ops! { - impl core::ops::$trait> for $scalar + impl core::ops::$trait> for $scalar where LaneCount: SupportedLaneCount, { - type Output = crate::$type; + type Output = Simd<$scalar, LANES>; #[inline] - fn $trait_fn(self, rhs: crate::$type) -> Self::Output { - core::ops::$trait::$trait_fn(crate::$type::splat(self), rhs) + fn $trait_fn(self, rhs: Simd<$scalar, LANES>) -> Self::Output { + core::ops::$trait::$trait_fn(Simd::splat(self), rhs) } } } impl_ref_ops! { - impl core::ops::$assign_trait for crate::$type + impl core::ops::$assign_trait for Simd<$scalar, LANES> where LaneCount: SupportedLaneCount, { @@ -277,7 +275,7 @@ macro_rules! impl_op { } impl_ref_ops! { - impl core::ops::$assign_trait<$scalar> for crate::$type + impl core::ops::$assign_trait<$scalar> for Simd<$scalar, LANES> where LaneCount: SupportedLaneCount, { @@ -292,379 +290,354 @@ macro_rules! impl_op { /// Implements floating-point operators for the provided types. macro_rules! impl_float_ops { - { $($scalar:ty => $($vector:ident),*;)* } => { - $( // scalar - $( // vector - impl_op! { impl Add for $vector, $scalar } - impl_op! { impl Sub for $vector, $scalar } - impl_op! { impl Mul for $vector, $scalar } - impl_op! { impl Div for $vector, $scalar } - impl_op! { impl Rem for $vector, $scalar } - impl_op! { impl Neg for $vector, $scalar } - impl_op! { impl Index for $vector, $scalar } - )* + { $($scalar:ty),* } => { + $( + impl_op! { impl Add for $scalar } + impl_op! { impl Sub for $scalar } + impl_op! { impl Mul for $scalar } + impl_op! { impl Div for $scalar } + impl_op! { impl Rem for $scalar } + impl_op! { impl Neg for $scalar } )* }; } /// Implements unsigned integer operators for the provided types. macro_rules! impl_unsigned_int_ops { - { $($scalar:ty => $($vector:ident),*;)* } => { - $( // scalar - $( // vector - impl_op! { impl Add for $vector, $scalar } - impl_op! { impl Sub for $vector, $scalar } - impl_op! { impl Mul for $vector, $scalar } - impl_op! { impl BitAnd for $vector, $scalar } - impl_op! { impl BitOr for $vector, $scalar } - impl_op! { impl BitXor for $vector, $scalar } - impl_op! { impl Not for $vector, $scalar } - impl_op! { impl Index for $vector, $scalar } + { $($scalar:ty),* } => { + $( + impl_op! { impl Add for $scalar } + impl_op! { impl Sub for $scalar } + impl_op! { impl Mul for $scalar } + impl_op! { impl BitAnd for $scalar } + impl_op! { impl BitOr for $scalar } + impl_op! { impl BitXor for $scalar } + impl_op! { impl Not for $scalar } - // Integers panic on divide by 0 - impl_ref_ops! { - impl core::ops::Div for crate::$vector - where - LaneCount: SupportedLaneCount, - { - type Output = Self; + // Integers panic on divide by 0 + impl_ref_ops! { + impl core::ops::Div for Simd<$scalar, LANES> + where + LaneCount: SupportedLaneCount, + { + type Output = Self; - #[inline] - fn div(self, rhs: Self) -> Self::Output { - if rhs.as_array() - .iter() - .any(|x| *x == 0) - { - panic!("attempt to divide by zero"); - } + #[inline] + fn div(self, rhs: Self) -> Self::Output { + if rhs.as_array() + .iter() + .any(|x| *x == 0) + { + panic!("attempt to divide by zero"); + } - // Guards for div(MIN, -1), - // this check only applies to signed ints - if <$scalar>::MIN != 0 && self.as_array().iter() - .zip(rhs.as_array().iter()) - .any(|(x,y)| *x == <$scalar>::MIN && *y == -1 as _) { + // Guards for div(MIN, -1), + // this check only applies to signed ints + if <$scalar>::MIN != 0 && self.as_array().iter() + .zip(rhs.as_array().iter()) + .any(|(x,y)| *x == <$scalar>::MIN && *y == -1 as _) { + panic!("attempt to divide with overflow"); + } + unsafe { crate::intrinsics::simd_div(self, rhs) } + } + } + } + + impl_ref_ops! { + impl core::ops::Div<$scalar> for Simd<$scalar, LANES> + where + LaneCount: SupportedLaneCount, + { + type Output = Self; + + #[inline] + fn div(self, rhs: $scalar) -> Self::Output { + if rhs == 0 { + panic!("attempt to divide by zero"); + } + if <$scalar>::MIN != 0 && + self.as_array().iter().any(|x| *x == <$scalar>::MIN) && + rhs == -1 as _ { panic!("attempt to divide with overflow"); - } - unsafe { crate::intrinsics::simd_div(self, rhs) } } + let rhs = Self::splat(rhs); + unsafe { crate::intrinsics::simd_div(self, rhs) } } } + } - impl_ref_ops! { - impl core::ops::Div<$scalar> for crate::$vector - where - LaneCount: SupportedLaneCount, - { - type Output = Self; + impl_ref_ops! { + impl core::ops::Div> for $scalar + where + LaneCount: SupportedLaneCount, + { + type Output = Simd<$scalar, LANES>; - #[inline] - fn div(self, rhs: $scalar) -> Self::Output { - if rhs == 0 { - panic!("attempt to divide by zero"); - } - if <$scalar>::MIN != 0 && - self.as_array().iter().any(|x| *x == <$scalar>::MIN) && - rhs == -1 as _ { - panic!("attempt to divide with overflow"); - } - let rhs = Self::splat(rhs); - unsafe { crate::intrinsics::simd_div(self, rhs) } - } + #[inline] + fn div(self, rhs: Simd<$scalar, LANES>) -> Self::Output { + Simd::splat(self) / rhs } } + } - impl_ref_ops! { - impl core::ops::Div> for $scalar - where - LaneCount: SupportedLaneCount, - { - type Output = crate::$vector; - - #[inline] - fn div(self, rhs: crate::$vector) -> Self::Output { - crate::$vector::splat(self) / rhs - } + impl_ref_ops! { + impl core::ops::DivAssign for Simd<$scalar, LANES> + where + LaneCount: SupportedLaneCount, + { + #[inline] + fn div_assign(&mut self, rhs: Self) { + *self = *self / rhs; } } + } - impl_ref_ops! { - impl core::ops::DivAssign for crate::$vector - where - LaneCount: SupportedLaneCount, - { - #[inline] - fn div_assign(&mut self, rhs: Self) { - *self = *self / rhs; - } + impl_ref_ops! { + impl core::ops::DivAssign<$scalar> for Simd<$scalar, LANES> + where + LaneCount: SupportedLaneCount, + { + #[inline] + fn div_assign(&mut self, rhs: $scalar) { + *self = *self / rhs; } } + } - impl_ref_ops! { - impl core::ops::DivAssign<$scalar> for crate::$vector - where - LaneCount: SupportedLaneCount, - { - #[inline] - fn div_assign(&mut self, rhs: $scalar) { - *self = *self / rhs; + // remainder panics on zero divisor + impl_ref_ops! { + impl core::ops::Rem for Simd<$scalar, LANES> + where + LaneCount: SupportedLaneCount, + { + type Output = Self; + + #[inline] + fn rem(self, rhs: Self) -> Self::Output { + if rhs.as_array() + .iter() + .any(|x| *x == 0) + { + panic!("attempt to calculate the remainder with a divisor of zero"); } + + // Guards for rem(MIN, -1) + // this branch applies the check only to signed ints + if <$scalar>::MIN != 0 && self.as_array().iter() + .zip(rhs.as_array().iter()) + .any(|(x,y)| *x == <$scalar>::MIN && *y == -1 as _) { + panic!("attempt to calculate the remainder with overflow"); + } + unsafe { crate::intrinsics::simd_rem(self, rhs) } } } + } - // remainder panics on zero divisor - impl_ref_ops! { - impl core::ops::Rem for crate::$vector - where - LaneCount: SupportedLaneCount, - { - type Output = Self; + impl_ref_ops! { + impl core::ops::Rem<$scalar> for Simd<$scalar, LANES> + where + LaneCount: SupportedLaneCount, + { + type Output = Self; - #[inline] - fn rem(self, rhs: Self) -> Self::Output { - if rhs.as_array() - .iter() - .any(|x| *x == 0) - { - panic!("attempt to calculate the remainder with a divisor of zero"); - } - - // Guards for rem(MIN, -1) - // this branch applies the check only to signed ints - if <$scalar>::MIN != 0 && self.as_array().iter() - .zip(rhs.as_array().iter()) - .any(|(x,y)| *x == <$scalar>::MIN && *y == -1 as _) { + #[inline] + fn rem(self, rhs: $scalar) -> Self::Output { + if rhs == 0 { + panic!("attempt to calculate the remainder with a divisor of zero"); + } + if <$scalar>::MIN != 0 && + self.as_array().iter().any(|x| *x == <$scalar>::MIN) && + rhs == -1 as _ { panic!("attempt to calculate the remainder with overflow"); - } - unsafe { crate::intrinsics::simd_rem(self, rhs) } } + let rhs = Self::splat(rhs); + unsafe { crate::intrinsics::simd_rem(self, rhs) } } } + } - impl_ref_ops! { - impl core::ops::Rem<$scalar> for crate::$vector - where - LaneCount: SupportedLaneCount, - { - type Output = Self; + impl_ref_ops! { + impl core::ops::Rem> for $scalar + where + LaneCount: SupportedLaneCount, + { + type Output = Simd<$scalar, LANES>; - #[inline] - fn rem(self, rhs: $scalar) -> Self::Output { - if rhs == 0 { - panic!("attempt to calculate the remainder with a divisor of zero"); - } - if <$scalar>::MIN != 0 && - self.as_array().iter().any(|x| *x == <$scalar>::MIN) && - rhs == -1 as _ { - panic!("attempt to calculate the remainder with overflow"); - } - let rhs = Self::splat(rhs); - unsafe { crate::intrinsics::simd_rem(self, rhs) } - } + #[inline] + fn rem(self, rhs: Simd<$scalar, LANES>) -> Self::Output { + Simd::splat(self) % rhs } } + } - impl_ref_ops! { - impl core::ops::Rem> for $scalar - where - LaneCount: SupportedLaneCount, - { - type Output = crate::$vector; - - #[inline] - fn rem(self, rhs: crate::$vector) -> Self::Output { - crate::$vector::splat(self) % rhs - } + impl_ref_ops! { + impl core::ops::RemAssign for Simd<$scalar, LANES> + where + LaneCount: SupportedLaneCount, + { + #[inline] + fn rem_assign(&mut self, rhs: Self) { + *self = *self % rhs; } } + } - impl_ref_ops! { - impl core::ops::RemAssign for crate::$vector - where - LaneCount: SupportedLaneCount, - { - #[inline] - fn rem_assign(&mut self, rhs: Self) { - *self = *self % rhs; - } + impl_ref_ops! { + impl core::ops::RemAssign<$scalar> for Simd<$scalar, LANES> + where + LaneCount: SupportedLaneCount, + { + #[inline] + fn rem_assign(&mut self, rhs: $scalar) { + *self = *self % rhs; } } + } - impl_ref_ops! { - impl core::ops::RemAssign<$scalar> for crate::$vector - where - LaneCount: SupportedLaneCount, - { - #[inline] - fn rem_assign(&mut self, rhs: $scalar) { - *self = *self % rhs; + // shifts panic on overflow + impl_ref_ops! { + impl core::ops::Shl for Simd<$scalar, LANES> + where + LaneCount: SupportedLaneCount, + { + type Output = Self; + + #[inline] + fn shl(self, rhs: Self) -> Self::Output { + // TODO there is probably a better way of doing this + if rhs.as_array() + .iter() + .copied() + .any(invalid_shift_rhs) + { + panic!("attempt to shift left with overflow"); } + unsafe { crate::intrinsics::simd_shl(self, rhs) } } } + } - // shifts panic on overflow - impl_ref_ops! { - impl core::ops::Shl for crate::$vector - where - LaneCount: SupportedLaneCount, - { - type Output = Self; + impl_ref_ops! { + impl core::ops::Shl<$scalar> for Simd<$scalar, LANES> + where + LaneCount: SupportedLaneCount, + { + type Output = Self; - #[inline] - fn shl(self, rhs: Self) -> Self::Output { - // TODO there is probably a better way of doing this - if rhs.as_array() - .iter() - .copied() - .any(invalid_shift_rhs) - { - panic!("attempt to shift left with overflow"); - } - unsafe { crate::intrinsics::simd_shl(self, rhs) } + #[inline] + fn shl(self, rhs: $scalar) -> Self::Output { + if invalid_shift_rhs(rhs) { + panic!("attempt to shift left with overflow"); } + let rhs = Self::splat(rhs); + unsafe { crate::intrinsics::simd_shl(self, rhs) } } } + } - impl_ref_ops! { - impl core::ops::Shl<$scalar> for crate::$vector - where - LaneCount: SupportedLaneCount, - { - type Output = Self; - #[inline] - fn shl(self, rhs: $scalar) -> Self::Output { - if invalid_shift_rhs(rhs) { - panic!("attempt to shift left with overflow"); - } - let rhs = Self::splat(rhs); - unsafe { crate::intrinsics::simd_shl(self, rhs) } - } + impl_ref_ops! { + impl core::ops::ShlAssign for Simd<$scalar, LANES> + where + LaneCount: SupportedLaneCount, + { + #[inline] + fn shl_assign(&mut self, rhs: Self) { + *self = *self << rhs; } } + } - - impl_ref_ops! { - impl core::ops::ShlAssign for crate::$vector - where - LaneCount: SupportedLaneCount, - { - #[inline] - fn shl_assign(&mut self, rhs: Self) { - *self = *self << rhs; - } + impl_ref_ops! { + impl core::ops::ShlAssign<$scalar> for Simd<$scalar, LANES> + where + LaneCount: SupportedLaneCount, + { + #[inline] + fn shl_assign(&mut self, rhs: $scalar) { + *self = *self << rhs; } } + } - impl_ref_ops! { - impl core::ops::ShlAssign<$scalar> for crate::$vector - where - LaneCount: SupportedLaneCount, - { - #[inline] - fn shl_assign(&mut self, rhs: $scalar) { - *self = *self << rhs; + impl_ref_ops! { + impl core::ops::Shr for Simd<$scalar, LANES> + where + LaneCount: SupportedLaneCount, + { + type Output = Self; + + #[inline] + fn shr(self, rhs: Self) -> Self::Output { + // TODO there is probably a better way of doing this + if rhs.as_array() + .iter() + .copied() + .any(invalid_shift_rhs) + { + panic!("attempt to shift with overflow"); } + unsafe { crate::intrinsics::simd_shr(self, rhs) } } } + } - impl_ref_ops! { - impl core::ops::Shr for crate::$vector - where - LaneCount: SupportedLaneCount, - { - type Output = Self; + impl_ref_ops! { + impl core::ops::Shr<$scalar> for Simd<$scalar, LANES> + where + LaneCount: SupportedLaneCount, + { + type Output = Self; - #[inline] - fn shr(self, rhs: Self) -> Self::Output { - // TODO there is probably a better way of doing this - if rhs.as_array() - .iter() - .copied() - .any(invalid_shift_rhs) - { - panic!("attempt to shift with overflow"); - } - unsafe { crate::intrinsics::simd_shr(self, rhs) } + #[inline] + fn shr(self, rhs: $scalar) -> Self::Output { + if invalid_shift_rhs(rhs) { + panic!("attempt to shift with overflow"); } + let rhs = Self::splat(rhs); + unsafe { crate::intrinsics::simd_shr(self, rhs) } } } + } - impl_ref_ops! { - impl core::ops::Shr<$scalar> for crate::$vector - where - LaneCount: SupportedLaneCount, - { - type Output = Self; - #[inline] - fn shr(self, rhs: $scalar) -> Self::Output { - if invalid_shift_rhs(rhs) { - panic!("attempt to shift with overflow"); - } - let rhs = Self::splat(rhs); - unsafe { crate::intrinsics::simd_shr(self, rhs) } - } + impl_ref_ops! { + impl core::ops::ShrAssign for Simd<$scalar, LANES> + where + LaneCount: SupportedLaneCount, + { + #[inline] + fn shr_assign(&mut self, rhs: Self) { + *self = *self >> rhs; } } + } - - impl_ref_ops! { - impl core::ops::ShrAssign for crate::$vector - where - LaneCount: SupportedLaneCount, - { - #[inline] - fn shr_assign(&mut self, rhs: Self) { - *self = *self >> rhs; - } + impl_ref_ops! { + impl core::ops::ShrAssign<$scalar> for Simd<$scalar, LANES> + where + LaneCount: SupportedLaneCount, + { + #[inline] + fn shr_assign(&mut self, rhs: $scalar) { + *self = *self >> rhs; } } - - impl_ref_ops! { - impl core::ops::ShrAssign<$scalar> for crate::$vector - where - LaneCount: SupportedLaneCount, - { - #[inline] - fn shr_assign(&mut self, rhs: $scalar) { - *self = *self >> rhs; - } - } - } - )* + } )* }; } /// Implements unsigned integer operators for the provided types. macro_rules! impl_signed_int_ops { - { $($scalar:ty => $($vector:ident),*;)* } => { - impl_unsigned_int_ops! { $($scalar => $($vector),*;)* } + { $($scalar:ty),* } => { + impl_unsigned_int_ops! { $($scalar),* } $( // scalar - $( // vector - impl_op! { impl Neg for $vector, $scalar } - )* + impl_op! { impl Neg for $scalar } )* }; } -impl_unsigned_int_ops! { - u8 => SimdU8; - u16 => SimdU16; - u32 => SimdU32; - u64 => SimdU64; - usize => SimdUsize; -} - -impl_signed_int_ops! { - i8 => SimdI8; - i16 => SimdI16; - i32 => SimdI32; - i64 => SimdI64; - isize => SimdIsize; -} - -impl_float_ops! { - f32 => SimdF32; - f64 => SimdF64; -} +impl_unsigned_int_ops! { u8, u16, u32, u64, usize } +impl_signed_int_ops! { i8, i16, i32, i64, isize } +impl_float_ops! { f32, f64 } diff --git a/crates/core_simd/src/permute.rs b/crates/core_simd/src/permute.rs index 01148a26bad4..cc58778b6b4b 100644 --- a/crates/core_simd/src/permute.rs +++ b/crates/core_simd/src/permute.rs @@ -1,6 +1,9 @@ macro_rules! impl_shuffle_lane { - { $name:ident, $fn:ident, $n:literal } => { - impl $name<$n> { + { $fn:ident, $n:literal } => { + impl crate::Simd + where + T: crate::SimdElement, + { /// A const SIMD shuffle that takes 2 SIMD vectors and produces another vector, using /// the indices in the const parameter. The first or "self" vector will have its lanes /// indexed from 0, and the second vector will have its first lane indexed at $n. @@ -12,12 +15,12 @@ macro_rules! impl_shuffle_lane { /// /// ``` /// #![feature(portable_simd)] - /// # use core_simd::*; - /// let a = f32x4::from_array([1.0, 2.0, 3.0, 4.0]); - /// let b = f32x4::from_array([5.0, 6.0, 7.0, 8.0]); + /// # use core_simd::Simd; + /// let a = Simd::from_array([1.0, 2.0, 3.0, 4.0]); + /// let b = Simd::from_array([5.0, 6.0, 7.0, 8.0]); /// const IDXS: [u32; 4] = [4,0,3,7]; - /// let c = f32x4::shuffle::(a,b); - /// assert_eq!(f32x4::from_array([5.0, 1.0, 4.0, 8.0]), c); + /// let c = Simd::<_, 4>::shuffle::(a,b); + /// assert_eq!(Simd::from_array([5.0, 1.0, 4.0, 8.0]), c); /// ``` #[inline] pub fn shuffle(self, second: Self) -> Self { @@ -53,9 +56,9 @@ macro_rules! impl_shuffle_lane { /// /// ``` /// #![feature(portable_simd)] - /// # use core_simd::SimdU32; - /// let a = SimdU32::from_array([0, 1, 2, 3]); - /// let b = SimdU32::from_array([4, 5, 6, 7]); + /// # use core_simd::Simd; + /// let a = Simd::from_array([0, 1, 2, 3]); + /// let b = Simd::from_array([4, 5, 6, 7]); /// let (x, y) = a.interleave(b); /// assert_eq!(x.to_array(), [0, 4, 1, 5]); /// assert_eq!(y.to_array(), [2, 6, 3, 7]); @@ -105,9 +108,9 @@ macro_rules! impl_shuffle_lane { /// /// ``` /// #![feature(portable_simd)] - /// # use core_simd::SimdU32; - /// let a = SimdU32::from_array([0, 4, 1, 5]); - /// let b = SimdU32::from_array([2, 6, 3, 7]); + /// # use core_simd::Simd; + /// let a = Simd::from_array([0, 4, 1, 5]); + /// let b = Simd::from_array([2, 6, 3, 7]); /// let (x, y) = a.deinterleave(b); /// assert_eq!(x.to_array(), [0, 1, 2, 3]); /// assert_eq!(y.to_array(), [4, 5, 6, 7]); @@ -138,12 +141,8 @@ macro_rules! impl_shuffle_lane { } } -macro_rules! impl_shuffle_2pow_lanes { - { $name:ident } => { - impl_shuffle_lane!{ $name, simd_shuffle2, 2 } - impl_shuffle_lane!{ $name, simd_shuffle4, 4 } - impl_shuffle_lane!{ $name, simd_shuffle8, 8 } - impl_shuffle_lane!{ $name, simd_shuffle16, 16 } - impl_shuffle_lane!{ $name, simd_shuffle32, 32 } - } -} +impl_shuffle_lane! { simd_shuffle2, 2 } +impl_shuffle_lane! { simd_shuffle4, 4 } +impl_shuffle_lane! { simd_shuffle8, 8 } +impl_shuffle_lane! { simd_shuffle16, 16 } +impl_shuffle_lane! { simd_shuffle32, 32 } diff --git a/crates/core_simd/src/reduction.rs b/crates/core_simd/src/reduction.rs index df227d09e342..943d2856e359 100644 --- a/crates/core_simd/src/reduction.rs +++ b/crates/core_simd/src/reduction.rs @@ -1,8 +1,10 @@ +use crate::{LaneCount, Simd, SupportedLaneCount}; + macro_rules! impl_integer_reductions { - { $name:ident, $scalar:ty } => { - impl crate::$name + { $scalar:ty } => { + impl Simd<$scalar, LANES> where - crate::LaneCount: crate::SupportedLaneCount, + LaneCount: SupportedLaneCount, { /// Horizontal wrapping add. Returns the sum of the lanes of the vector, with wrapping addition. #[inline] @@ -52,11 +54,22 @@ macro_rules! impl_integer_reductions { } } +impl_integer_reductions! { i8 } +impl_integer_reductions! { i16 } +impl_integer_reductions! { i32 } +impl_integer_reductions! { i64 } +impl_integer_reductions! { isize } +impl_integer_reductions! { u8 } +impl_integer_reductions! { u16 } +impl_integer_reductions! { u32 } +impl_integer_reductions! { u64 } +impl_integer_reductions! { usize } + macro_rules! impl_float_reductions { - { $name:ident, $scalar:ty } => { - impl crate::$name + { $scalar:ty } => { + impl Simd<$scalar, LANES> where - crate::LaneCount: crate::SupportedLaneCount, + LaneCount: SupportedLaneCount, { /// Horizontal add. Returns the sum of the lanes of the vector. @@ -102,42 +115,5 @@ macro_rules! impl_float_reductions { } } -macro_rules! impl_full_mask_reductions { - { $name:ident, $bits_ty:ident } => { - impl $name - where - crate::LaneCount: crate::SupportedLaneCount, - { - #[inline] - pub fn any(self) -> bool { - unsafe { crate::intrinsics::simd_reduce_any(self.to_int()) } - } - - #[inline] - pub fn all(self) -> bool { - unsafe { crate::intrinsics::simd_reduce_all(self.to_int()) } - } - } - } -} - -macro_rules! impl_opaque_mask_reductions { - { $name:ident, $bits_ty:ident } => { - impl $name - where - crate::LaneCount: crate::SupportedLaneCount, - { - /// Returns true if any lane is set, or false otherwise. - #[inline] - pub fn any(self) -> bool { - self.0.any() - } - - /// Returns true if all lanes are set, or false otherwise. - #[inline] - pub fn all(self) -> bool { - self.0.all() - } - } - } -} +impl_float_reductions! { f32 } +impl_float_reductions! { f64 } diff --git a/crates/core_simd/src/round.rs b/crates/core_simd/src/round.rs index c284ade463fc..96d46b9a1232 100644 --- a/crates/core_simd/src/round.rs +++ b/crates/core_simd/src/round.rs @@ -1,11 +1,13 @@ +use crate::{LaneCount, Simd, SupportedLaneCount}; + macro_rules! implement { { - $type:ident, $int_type:ident + $type:ty, $int_type:ty } => { #[cfg(feature = "std")] - impl crate::$type + impl Simd<$type, LANES> where - crate::LaneCount: crate::SupportedLaneCount, + LaneCount: SupportedLaneCount, { /// Returns the smallest integer greater than or equal to each lane. #[must_use = "method returns a new vector and does not mutate the original value"] @@ -43,9 +45,9 @@ macro_rules! implement { } } - impl crate::$type + impl Simd<$type, LANES> where - crate::LaneCount: crate::SupportedLaneCount, + LaneCount: SupportedLaneCount, { /// Rounds toward zero and converts to the same-width integer type, assuming that /// the value is finite and fits in that type. @@ -57,19 +59,19 @@ macro_rules! implement { /// * Not be infinite /// * Be representable in the return type, after truncating off its fractional part #[inline] - pub unsafe fn to_int_unchecked(self) -> crate::$int_type { + pub unsafe fn to_int_unchecked(self) -> Simd<$int_type, LANES> { crate::intrinsics::simd_cast(self) } /// Creates a floating-point vector from an integer vector. Rounds values that are /// not exactly representable. #[inline] - pub fn round_from_int(value: crate::$int_type) -> Self { + pub fn round_from_int(value: Simd<$int_type, LANES>) -> Self { unsafe { crate::intrinsics::simd_cast(value) } } } } } -implement! { SimdF32, SimdI32 } -implement! { SimdF64, SimdI64 } +implement! { f32, i32 } +implement! { f64, i64 } diff --git a/crates/core_simd/src/select.rs b/crates/core_simd/src/select.rs index d70e8a66b95f..0951639c9426 100644 --- a/crates/core_simd/src/select.rs +++ b/crates/core_simd/src/select.rs @@ -1,3 +1,5 @@ +use crate::{LaneCount, Mask, MaskElement, Simd, SimdElement, SupportedLaneCount}; + mod sealed { pub trait Sealed {} } @@ -9,79 +11,75 @@ pub trait Select: Sealed { fn select(mask: Mask, true_values: Self, false_values: Self) -> Self; } -macro_rules! impl_select { - { - $mask:ident ($bits_ty:ident): $($type:ident),* - } => { - $( - impl Sealed for crate::$type where crate::LaneCount: crate::SupportedLaneCount {} - impl Select> for crate::$type - where - crate::LaneCount: crate::SupportedLaneCount, - { - #[doc(hidden)] - #[inline] - fn select(mask: crate::$mask, true_values: Self, false_values: Self) -> Self { - unsafe { crate::intrinsics::simd_select(mask.to_int(), true_values, false_values) } - } - } - )* +impl Sealed for Simd +where + T: SimdElement, + LaneCount: SupportedLaneCount, +{ +} - impl Sealed for crate::$mask - where - crate::LaneCount: crate::SupportedLaneCount, - {} - - impl Select for crate::$mask - where - crate::LaneCount: crate::SupportedLaneCount, - { - #[doc(hidden)] - #[inline] - fn select(mask: Self, true_values: Self, false_values: Self) -> Self { - mask & true_values | !mask & false_values - } - } - - impl crate::$mask - where - crate::LaneCount: crate::SupportedLaneCount, - { - /// Choose lanes from two vectors. - /// - /// For each lane in the mask, choose the corresponding lane from `true_values` if - /// that lane mask is true, and `false_values` if that lane mask is false. - /// - /// ``` - /// # #![feature(portable_simd)] - /// # use core_simd::{Mask32, SimdI32}; - /// let a = SimdI32::from_array([0, 1, 2, 3]); - /// let b = SimdI32::from_array([4, 5, 6, 7]); - /// let mask = Mask32::from_array([true, false, false, true]); - /// let c = mask.select(a, b); - /// assert_eq!(c.to_array(), [0, 5, 6, 3]); - /// ``` - /// - /// `select` can also be used on masks: - /// ``` - /// # #![feature(portable_simd)] - /// # use core_simd::Mask32; - /// let a = Mask32::from_array([true, true, false, false]); - /// let b = Mask32::from_array([false, false, true, true]); - /// let mask = Mask32::from_array([true, false, false, true]); - /// let c = mask.select(a, b); - /// assert_eq!(c.to_array(), [true, false, true, false]); - /// ``` - #[inline] - pub fn select>(self, true_values: S, false_values: S) -> S { - S::select(self, true_values, false_values) - } - } +impl Select> for Simd +where + T: SimdElement, + LaneCount: SupportedLaneCount, +{ + #[inline] + fn select(mask: Mask, true_values: Self, false_values: Self) -> Self { + unsafe { crate::intrinsics::simd_select(mask.to_int(), true_values, false_values) } } } -impl_select! { Mask8 (SimdI8): SimdU8, SimdI8 } -impl_select! { Mask16 (SimdI16): SimdU16, SimdI16 } -impl_select! { Mask32 (SimdI32): SimdU32, SimdI32, SimdF32} -impl_select! { Mask64 (SimdI64): SimdU64, SimdI64, SimdF64} -impl_select! { MaskSize (SimdIsize): SimdUsize, SimdIsize } +impl Sealed for Mask +where + T: MaskElement, + LaneCount: SupportedLaneCount, +{ +} + +impl Select for Mask +where + T: MaskElement, + LaneCount: SupportedLaneCount, +{ + #[doc(hidden)] + #[inline] + fn select(mask: Self, true_values: Self, false_values: Self) -> Self { + mask & true_values | !mask & false_values + } +} + +impl Mask +where + T: MaskElement, + LaneCount: SupportedLaneCount, +{ + /// Choose lanes from two vectors. + /// + /// For each lane in the mask, choose the corresponding lane from `true_values` if + /// that lane mask is true, and `false_values` if that lane mask is false. + /// + /// ``` + /// # #![feature(portable_simd)] + /// # use core_simd::{Mask, Simd}; + /// let a = Simd::from_array([0, 1, 2, 3]); + /// let b = Simd::from_array([4, 5, 6, 7]); + /// let mask = Mask::from_array([true, false, false, true]); + /// let c = mask.select(a, b); + /// assert_eq!(c.to_array(), [0, 5, 6, 3]); + /// ``` + /// + /// `select` can also be used on masks: + /// ``` + /// # #![feature(portable_simd)] + /// # use core_simd::Mask; + /// let a = Mask::::from_array([true, true, false, false]); + /// let b = Mask::::from_array([false, false, true, true]); + /// let mask = Mask::::from_array([true, false, false, true]); + /// let c = mask.select(a, b); + /// assert_eq!(c.to_array(), [true, false, true, false]); + /// ``` + #[inline] + pub fn select>(self, true_values: S, false_values: S) -> S { + S::select(self, true_values, false_values) + } +} diff --git a/crates/core_simd/src/to_bytes.rs b/crates/core_simd/src/to_bytes.rs index 31d7dfebe1a7..bd818f532118 100644 --- a/crates/core_simd/src/to_bytes.rs +++ b/crates/core_simd/src/to_bytes.rs @@ -1,39 +1,39 @@ macro_rules! impl_to_bytes { - { $name:ident, $size:literal } => { - impl crate::$name + { $ty:ty, $size:literal } => { + impl crate::Simd<$ty, LANES> where crate::LaneCount: crate::SupportedLaneCount, crate::LaneCount<{{ $size * LANES }}>: crate::SupportedLaneCount, { /// Return the memory representation of this integer as a byte array in native byte /// order. - pub fn to_ne_bytes(self) -> crate::SimdU8<{{ $size * LANES }}> { + pub fn to_ne_bytes(self) -> crate::Simd { unsafe { core::mem::transmute_copy(&self) } } /// Create a native endian integer value from its memory representation as a byte array /// in native endianness. - pub fn from_ne_bytes(bytes: crate::SimdU8<{{ $size * LANES }}>) -> Self { + pub fn from_ne_bytes(bytes: crate::Simd) -> Self { unsafe { core::mem::transmute_copy(&bytes) } } } } } -impl_to_bytes! { SimdU8, 1 } -impl_to_bytes! { SimdU16, 2 } -impl_to_bytes! { SimdU32, 4 } -impl_to_bytes! { SimdU64, 8 } +impl_to_bytes! { u8, 1 } +impl_to_bytes! { u16, 2 } +impl_to_bytes! { u32, 4 } +impl_to_bytes! { u64, 8 } #[cfg(target_pointer_width = "32")] -impl_to_bytes! { SimdUsize, 4 } +impl_to_bytes! { usize, 4 } #[cfg(target_pointer_width = "64")] -impl_to_bytes! { SimdUsize, 8 } +impl_to_bytes! { usize, 8 } -impl_to_bytes! { SimdI8, 1 } -impl_to_bytes! { SimdI16, 2 } -impl_to_bytes! { SimdI32, 4 } -impl_to_bytes! { SimdI64, 8 } +impl_to_bytes! { i8, 1 } +impl_to_bytes! { i16, 2 } +impl_to_bytes! { i32, 4 } +impl_to_bytes! { i64, 8 } #[cfg(target_pointer_width = "32")] -impl_to_bytes! { SimdIsize, 4 } +impl_to_bytes! { isize, 4 } #[cfg(target_pointer_width = "64")] -impl_to_bytes! { SimdIsize, 8 } +impl_to_bytes! { isize, 8 } diff --git a/crates/core_simd/src/transmute.rs b/crates/core_simd/src/transmute.rs deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/crates/core_simd/src/vector.rs b/crates/core_simd/src/vector.rs index 1f6df533767e..07e8a6c5926c 100644 --- a/crates/core_simd/src/vector.rs +++ b/crates/core_simd/src/vector.rs @@ -1,6 +1,3 @@ -#[macro_use] -mod vector_impl; - mod float; mod int; mod uint; @@ -12,21 +9,399 @@ pub use uint::*; // Vectors of pointers are not for public use at the current time. pub(crate) mod ptr; +use crate::{LaneCount, Mask, MaskElement, SupportedLaneCount}; + +/// A SIMD vector of `LANES` elements of type `T`. +#[repr(simd)] +pub struct Simd([T; LANES]) +where + T: SimdElement, + LaneCount: SupportedLaneCount; + +impl Simd +where + LaneCount: SupportedLaneCount, + T: SimdElement, +{ + /// Construct a SIMD vector by setting all lanes to the given value. + pub const fn splat(value: T) -> Self { + Self([value; LANES]) + } + + /// Returns an array reference containing the entire SIMD vector. + pub const fn as_array(&self) -> &[T; LANES] { + &self.0 + } + + /// Returns a mutable array reference containing the entire SIMD vector. + pub fn as_mut_array(&mut self) -> &mut [T; LANES] { + &mut self.0 + } + + /// Converts an array to a SIMD vector. + pub const fn from_array(array: [T; LANES]) -> Self { + Self(array) + } + + /// Converts a SIMD vector to an array. + pub const fn to_array(self) -> [T; LANES] { + self.0 + } + + /// SIMD gather: construct a SIMD vector by reading from a slice, using potentially discontiguous indices. + /// If an index is out of bounds, that lane instead selects the value from the "or" vector. + /// ``` + /// # #![feature(portable_simd)] + /// # use core_simd::*; + /// let vec: Vec = vec![10, 11, 12, 13, 14, 15, 16, 17, 18]; + /// let idxs = Simd::from_array([9, 3, 0, 5]); + /// let alt = Simd::from_array([-5, -4, -3, -2]); + /// + /// let result = Simd::gather_or(&vec, idxs, alt); // Note the lane that is out-of-bounds. + /// assert_eq!(result, Simd::from_array([-5, 13, 10, 15])); + /// ``` + #[must_use] + #[inline] + pub fn gather_or(slice: &[T], idxs: Simd, or: Self) -> Self { + Self::gather_select(slice, Mask::splat(true), idxs, or) + } + + /// SIMD gather: construct a SIMD vector by reading from a slice, using potentially discontiguous indices. + /// Out-of-bounds indices instead use the default value for that lane (0). + /// ``` + /// # #![feature(portable_simd)] + /// # use core_simd::*; + /// let vec: Vec = vec![10, 11, 12, 13, 14, 15, 16, 17, 18]; + /// let idxs = Simd::from_array([9, 3, 0, 5]); + /// + /// let result = Simd::gather_or_default(&vec, idxs); // Note the lane that is out-of-bounds. + /// assert_eq!(result, Simd::from_array([0, 13, 10, 15])); + /// ``` + #[must_use] + #[inline] + pub fn gather_or_default(slice: &[T], idxs: Simd) -> Self + where + T: Default, + { + Self::gather_or(slice, idxs, Self::splat(T::default())) + } + + /// SIMD gather: construct a SIMD vector by reading from a slice, using potentially discontiguous indices. + /// Out-of-bounds or masked indices instead select the value from the "or" vector. + /// ``` + /// # #![feature(portable_simd)] + /// # use core_simd::*; + /// let vec: Vec = vec![10, 11, 12, 13, 14, 15, 16, 17, 18]; + /// let idxs = Simd::from_array([9, 3, 0, 5]); + /// let alt = Simd::from_array([-5, -4, -3, -2]); + /// let mask = Mask::from_array([true, true, true, false]); // Note the mask of the last lane. + /// + /// let result = Simd::gather_select(&vec, mask, idxs, alt); // Note the lane that is out-of-bounds. + /// assert_eq!(result, Simd::from_array([-5, 13, 10, -2])); + /// ``` + #[must_use] + #[inline] + pub fn gather_select( + slice: &[T], + mask: Mask, + idxs: Simd, + or: Self, + ) -> Self { + let mask = (mask & idxs.lanes_lt(Simd::splat(slice.len()))).to_int(); + let base_ptr = crate::vector::ptr::SimdConstPtr::splat(slice.as_ptr()); + // Ferris forgive me, I have done pointer arithmetic here. + let ptrs = base_ptr.wrapping_add(idxs); + // SAFETY: The ptrs have been bounds-masked to prevent memory-unsafe reads insha'allah + unsafe { crate::intrinsics::simd_gather(or, ptrs, mask) } + } + + /// SIMD scatter: write a SIMD vector's values into a slice, using potentially discontiguous indices. + /// Out-of-bounds indices are not written. + /// `scatter` writes "in order", so if an index receives two writes, only the last is guaranteed. + /// ``` + /// # #![feature(portable_simd)] + /// # use core_simd::*; + /// let mut vec: Vec = vec![10, 11, 12, 13, 14, 15, 16, 17, 18]; + /// let idxs = Simd::from_array([9, 3, 0, 0]); + /// let vals = Simd::from_array([-27, 82, -41, 124]); + /// + /// vals.scatter(&mut vec, idxs); // index 0 receives two writes. + /// assert_eq!(vec, vec![124, 11, 12, 82, 14, 15, 16, 17, 18]); + /// ``` + #[inline] + pub fn scatter(self, slice: &mut [T], idxs: Simd) { + self.scatter_select(slice, Mask::splat(true), idxs) + } + + /// SIMD scatter: write a SIMD vector's values into a slice, using potentially discontiguous indices. + /// Out-of-bounds or masked indices are not written. + /// `scatter_select` writes "in order", so if an index receives two writes, only the last is guaranteed. + /// ``` + /// # #![feature(portable_simd)] + /// # use core_simd::*; + /// let mut vec: Vec = vec![10, 11, 12, 13, 14, 15, 16, 17, 18]; + /// let idxs = Simd::from_array([9, 3, 0, 0]); + /// let vals = Simd::from_array([-27, 82, -41, 124]); + /// let mask = Mask::from_array([true, true, true, false]); // Note the mask of the last lane. + /// + /// vals.scatter_select(&mut vec, mask, idxs); // index 0's second write is masked, thus omitted. + /// assert_eq!(vec, vec![-41, 11, 12, 82, 14, 15, 16, 17, 18]); + /// ``` + #[inline] + pub fn scatter_select( + self, + slice: &mut [T], + mask: Mask, + idxs: Simd, + ) { + // We must construct our scatter mask before we derive a pointer! + let mask = (mask & idxs.lanes_lt(Simd::splat(slice.len()))).to_int(); + // SAFETY: This block works with *mut T derived from &mut 'a [T], + // which means it is delicate in Rust's borrowing model, circa 2021: + // &mut 'a [T] asserts uniqueness, so deriving &'a [T] invalidates live *mut Ts! + // Even though this block is largely safe methods, it must be almost exactly this way + // to prevent invalidating the raw ptrs while they're live. + // Thus, entering this block requires all values to use being already ready: + // 0. idxs we want to write to, which are used to construct the mask. + // 1. mask, which depends on an initial &'a [T] and the idxs. + // 2. actual values to scatter (self). + // 3. &mut [T] which will become our base ptr. + unsafe { + // Now Entering ☢️ *mut T Zone + let base_ptr = crate::vector::ptr::SimdMutPtr::splat(slice.as_mut_ptr()); + // Ferris forgive me, I have done pointer arithmetic here. + let ptrs = base_ptr.wrapping_add(idxs); + // The ptrs have been bounds-masked to prevent memory-unsafe writes insha'allah + crate::intrinsics::simd_scatter(self, ptrs, mask) + // Cleared ☢️ *mut T Zone + } + } +} + +impl Copy for Simd +where + T: SimdElement, + LaneCount: SupportedLaneCount, +{ +} + +impl Clone for Simd +where + T: SimdElement, + LaneCount: SupportedLaneCount, +{ + fn clone(&self) -> Self { + *self + } +} + +impl Default for Simd +where + LaneCount: SupportedLaneCount, + T: SimdElement + Default, +{ + #[inline] + fn default() -> Self { + Self::splat(T::default()) + } +} + +impl PartialEq for Simd +where + LaneCount: SupportedLaneCount, + T: SimdElement + PartialEq, +{ + #[inline] + fn eq(&self, other: &Self) -> bool { + // TODO use SIMD equality + self.to_array() == other.to_array() + } +} + +impl PartialOrd for Simd +where + LaneCount: SupportedLaneCount, + T: SimdElement + PartialOrd, +{ + #[inline] + fn partial_cmp(&self, other: &Self) -> Option { + // TODO use SIMD equality + self.to_array().partial_cmp(other.as_ref()) + } +} + +impl Eq for Simd +where + LaneCount: SupportedLaneCount, + T: SimdElement + Eq, +{ +} + +impl Ord for Simd +where + LaneCount: SupportedLaneCount, + T: SimdElement + Ord, +{ + #[inline] + fn cmp(&self, other: &Self) -> core::cmp::Ordering { + // TODO use SIMD equality + self.to_array().cmp(other.as_ref()) + } +} + +impl core::hash::Hash for Simd +where + LaneCount: SupportedLaneCount, + T: SimdElement + core::hash::Hash, +{ + #[inline] + fn hash(&self, state: &mut H) + where + H: core::hash::Hasher, + { + self.as_array().hash(state) + } +} + +// array references +impl AsRef<[T; LANES]> for Simd +where + LaneCount: SupportedLaneCount, + T: SimdElement, +{ + #[inline] + fn as_ref(&self) -> &[T; LANES] { + &self.0 + } +} + +impl AsMut<[T; LANES]> for Simd +where + LaneCount: SupportedLaneCount, + T: SimdElement, +{ + #[inline] + fn as_mut(&mut self) -> &mut [T; LANES] { + &mut self.0 + } +} + +// slice references +impl AsRef<[T]> for Simd +where + LaneCount: SupportedLaneCount, + T: SimdElement, +{ + #[inline] + fn as_ref(&self) -> &[T] { + &self.0 + } +} + +impl AsMut<[T]> for Simd +where + LaneCount: SupportedLaneCount, + T: SimdElement, +{ + #[inline] + fn as_mut(&mut self) -> &mut [T] { + &mut self.0 + } +} + +// vector/array conversion +impl From<[T; LANES]> for Simd +where + LaneCount: SupportedLaneCount, + T: SimdElement, +{ + fn from(array: [T; LANES]) -> Self { + Self(array) + } +} + +impl From> for [T; LANES] +where + LaneCount: SupportedLaneCount, + T: SimdElement, +{ + fn from(vector: Simd) -> Self { + vector.to_array() + } +} + mod sealed { pub trait Sealed {} } +use sealed::Sealed; -/// A representation of a vector as an "array" with indices, implementing -/// operations applicable to any vector type based solely on "having lanes", -/// and describing relationships between vector and scalar types. -pub trait Vector: sealed::Sealed { - /// The scalar type in every lane of this vector type. - type Scalar: Copy + Sized; - - /// The number of lanes for this vector. - const LANES: usize; - - /// Generates a SIMD vector with the same value in every lane. - #[must_use] - fn splat(val: Self::Scalar) -> Self; +/// Marker trait for types that may be used as SIMD vector elements. +/// SAFETY: This trait, when implemented, asserts the compiler can monomorphize +/// `#[repr(simd)]` structs with the marked type as an element. +/// Strictly, it is valid to impl if the vector will not be miscompiled. +/// Practically, it is user-unfriendly to impl it if the vector won't compile, +/// even when no soundness guarantees are broken by allowing the user to try. +pub unsafe trait SimdElement: Sealed + Copy { + /// The mask element type corresponding to this element type. + type Mask: MaskElement; +} + +impl Sealed for u8 {} +unsafe impl SimdElement for u8 { + type Mask = i8; +} + +impl Sealed for u16 {} +unsafe impl SimdElement for u16 { + type Mask = i16; +} + +impl Sealed for u32 {} +unsafe impl SimdElement for u32 { + type Mask = i32; +} + +impl Sealed for u64 {} +unsafe impl SimdElement for u64 { + type Mask = i64; +} + +impl Sealed for usize {} +unsafe impl SimdElement for usize { + type Mask = isize; +} + +impl Sealed for i8 {} +unsafe impl SimdElement for i8 { + type Mask = i8; +} + +impl Sealed for i16 {} +unsafe impl SimdElement for i16 { + type Mask = i16; +} + +impl Sealed for i32 {} +unsafe impl SimdElement for i32 { + type Mask = i32; +} + +impl Sealed for i64 {} +unsafe impl SimdElement for i64 { + type Mask = i64; +} + +impl Sealed for isize {} +unsafe impl SimdElement for isize { + type Mask = isize; +} + +impl Sealed for f32 {} +unsafe impl SimdElement for f32 { + type Mask = i32; +} + +impl Sealed for f64 {} +unsafe impl SimdElement for f64 { + type Mask = i64; } diff --git a/crates/core_simd/src/vector/float.rs b/crates/core_simd/src/vector/float.rs index bdeccd037a80..6ef88ddebc68 100644 --- a/crates/core_simd/src/vector/float.rs +++ b/crates/core_simd/src/vector/float.rs @@ -1,32 +1,29 @@ #![allow(non_camel_case_types)] -use crate::{LaneCount, SupportedLaneCount}; +use crate::{LaneCount, Mask, Simd, SupportedLaneCount}; -/// Implements inherent methods for a float vector `$name` containing multiple +/// Implements inherent methods for a float vector containing multiple /// `$lanes` of float `$type`, which uses `$bits_ty` as its binary -/// representation. Called from `define_float_vector!`. +/// representation. macro_rules! impl_float_vector { - { $name:ident, $type:ident, $bits_ty:ident, $mask_ty:ident, $mask_impl_ty:ident } => { - impl_vector! { $name, $type } - impl_float_reductions! { $name, $type } - - impl $name + { $type:ty, $bits_ty:ty, $mask_ty:ty } => { + impl Simd<$type, LANES> where LaneCount: SupportedLaneCount, { /// Raw transmutation to an unsigned integer vector type with the /// same size and number of lanes. #[inline] - pub fn to_bits(self) -> crate::$bits_ty { - assert_eq!(core::mem::size_of::(), core::mem::size_of::>()); + pub fn to_bits(self) -> Simd<$bits_ty, LANES> { + assert_eq!(core::mem::size_of::(), core::mem::size_of::>()); unsafe { core::mem::transmute_copy(&self) } } /// Raw transmutation from an unsigned integer vector type with the /// same size and number of lanes. #[inline] - pub fn from_bits(bits: crate::$bits_ty) -> Self { - assert_eq!(core::mem::size_of::(), core::mem::size_of::>()); + pub fn from_bits(bits: Simd<$bits_ty, LANES>) -> Self { + assert_eq!(core::mem::size_of::(), core::mem::size_of::>()); unsafe { core::mem::transmute_copy(&bits) } } @@ -67,58 +64,58 @@ macro_rules! impl_float_vector { #[inline] pub fn to_degrees(self) -> Self { // to_degrees uses a special constant for better precision, so extract that constant - self * Self::splat($type::to_degrees(1.)) + self * Self::splat(<$type>::to_degrees(1.)) } /// Converts each lane from degrees to radians. #[inline] pub fn to_radians(self) -> Self { - self * Self::splat($type::to_radians(1.)) + self * Self::splat(<$type>::to_radians(1.)) } /// Returns true for each lane if it has a positive sign, including /// `+0.0`, `NaN`s with positive sign bit and positive infinity. #[inline] - pub fn is_sign_positive(self) -> crate::$mask_ty { + pub fn is_sign_positive(self) -> Mask<$mask_ty, LANES> { !self.is_sign_negative() } /// Returns true for each lane if it has a negative sign, including /// `-0.0`, `NaN`s with negative sign bit and negative infinity. #[inline] - pub fn is_sign_negative(self) -> crate::$mask_ty { - let sign_bits = self.to_bits() & crate::$bits_ty::splat((!0 >> 1) + 1); - sign_bits.lanes_gt(crate::$bits_ty::splat(0)) + pub fn is_sign_negative(self) -> Mask<$mask_ty, LANES> { + let sign_bits = self.to_bits() & Simd::splat((!0 >> 1) + 1); + sign_bits.lanes_gt(Simd::splat(0)) } /// Returns true for each lane if its value is `NaN`. #[inline] - pub fn is_nan(self) -> crate::$mask_ty { + pub fn is_nan(self) -> Mask<$mask_ty, LANES> { self.lanes_ne(self) } /// Returns true for each lane if its value is positive infinity or negative infinity. #[inline] - pub fn is_infinite(self) -> crate::$mask_ty { + pub fn is_infinite(self) -> Mask<$mask_ty, LANES> { self.abs().lanes_eq(Self::splat(<$type>::INFINITY)) } /// Returns true for each lane if its value is neither infinite nor `NaN`. #[inline] - pub fn is_finite(self) -> crate::$mask_ty { + pub fn is_finite(self) -> Mask<$mask_ty, LANES> { self.abs().lanes_lt(Self::splat(<$type>::INFINITY)) } /// Returns true for each lane if its value is subnormal. #[inline] - pub fn is_subnormal(self) -> crate::$mask_ty { - self.abs().lanes_ne(Self::splat(0.0)) & (self.to_bits() & Self::splat(<$type>::INFINITY).to_bits()).lanes_eq(crate::$bits_ty::splat(0)) + pub fn is_subnormal(self) -> Mask<$mask_ty, LANES> { + self.abs().lanes_ne(Self::splat(0.0)) & (self.to_bits() & Self::splat(<$type>::INFINITY).to_bits()).lanes_eq(Simd::splat(0)) } /// Returns true for each lane if its value is neither neither zero, infinite, /// subnormal, or `NaN`. #[inline] - pub fn is_normal(self) -> crate::$mask_ty { + pub fn is_normal(self) -> Mask<$mask_ty, LANES> { !(self.abs().lanes_eq(Self::splat(0.0)) | self.is_nan() | self.is_subnormal() | self.is_infinite()) } @@ -129,7 +126,7 @@ macro_rules! impl_float_vector { /// * `NAN` if the number is `NAN` #[inline] pub fn signum(self) -> Self { - self.is_nan().select(Self::splat($type::NAN), Self::splat(1.0).copysign(self)) + self.is_nan().select(Self::splat(<$type>::NAN), Self::splat(1.0).copysign(self)) } /// Returns each lane with the magnitude of `self` and the sign of `sign`. @@ -186,39 +183,26 @@ macro_rules! impl_float_vector { }; } -/// A SIMD vector of containing `LANES` `f32` values. -#[repr(simd)] -pub struct SimdF32([f32; LANES]) -where - LaneCount: SupportedLaneCount; - -impl_float_vector! { SimdF32, f32, SimdU32, Mask32, SimdI32 } - -/// A SIMD vector of containing `LANES` `f64` values. -#[repr(simd)] -pub struct SimdF64([f64; LANES]) -where - LaneCount: SupportedLaneCount; - -impl_float_vector! { SimdF64, f64, SimdU64, Mask64, SimdI64 } +impl_float_vector! { f32, u32, i32 } +impl_float_vector! { f64, u64, i64 } /// Vector of two `f32` values -pub type f32x2 = SimdF32<2>; +pub type f32x2 = Simd; /// Vector of four `f32` values -pub type f32x4 = SimdF32<4>; +pub type f32x4 = Simd; /// Vector of eight `f32` values -pub type f32x8 = SimdF32<8>; +pub type f32x8 = Simd; /// Vector of 16 `f32` values -pub type f32x16 = SimdF32<16>; +pub type f32x16 = Simd; /// Vector of two `f64` values -pub type f64x2 = SimdF64<2>; +pub type f64x2 = Simd; /// Vector of four `f64` values -pub type f64x4 = SimdF64<4>; +pub type f64x4 = Simd; /// Vector of eight `f64` values -pub type f64x8 = SimdF64<8>; +pub type f64x8 = Simd; diff --git a/crates/core_simd/src/vector/int.rs b/crates/core_simd/src/vector/int.rs index 73c737762fb6..5f435e16b687 100644 --- a/crates/core_simd/src/vector/int.rs +++ b/crates/core_simd/src/vector/int.rs @@ -1,49 +1,23 @@ #![allow(non_camel_case_types)] -use crate::{LaneCount, SupportedLaneCount}; +use crate::{LaneCount, Mask, Simd, SupportedLaneCount}; /// Implements additional integer traits (Eq, Ord, Hash) on the specified vector `$name`, holding multiple `$lanes` of `$type`. macro_rules! impl_integer_vector { - { $name:ident, $type:ty, $mask_ty:ident, $mask_impl_ty:ident } => { - impl_vector! { $name, $type } - impl_integer_reductions! { $name, $type } - - impl Eq for $name where LaneCount: SupportedLaneCount {} - - impl Ord for $name where LaneCount: SupportedLaneCount { - #[inline] - fn cmp(&self, other: &Self) -> core::cmp::Ordering { - // TODO use SIMD cmp - self.as_array().cmp(other.as_ref()) - } - } - - impl core::hash::Hash for $name - where - LaneCount: SupportedLaneCount, - { - #[inline] - fn hash(&self, state: &mut H) - where - H: core::hash::Hasher - { - self.as_array().hash(state) - } - } - - impl $name + { $type:ty } => { + impl Simd<$type, LANES> where LaneCount: SupportedLaneCount, { /// Returns true for each positive lane and false if it is zero or negative. #[inline] - pub fn is_positive(self) -> crate::$mask_ty { + pub fn is_positive(self) -> Mask<$type, LANES> { self.lanes_gt(Self::splat(0)) } /// Returns true for each negative lane and false if it is zero or positive. #[inline] - pub fn is_negative(self) -> crate::$mask_ty { + pub fn is_negative(self) -> Mask<$type, LANES> { self.lanes_lt(Self::splat(0)) } @@ -62,102 +36,68 @@ macro_rules! impl_integer_vector { } } -/// A SIMD vector of containing `LANES` `isize` values. -#[repr(simd)] -pub struct SimdIsize([isize; LANES]) -where - LaneCount: SupportedLaneCount; - -impl_integer_vector! { SimdIsize, isize, MaskSize, SimdIsize } - -/// A SIMD vector of containing `LANES` `i16` values. -#[repr(simd)] -pub struct SimdI16([i16; LANES]) -where - LaneCount: SupportedLaneCount; - -impl_integer_vector! { SimdI16, i16, Mask16, SimdI16 } - -/// A SIMD vector of containing `LANES` `i32` values. -#[repr(simd)] -pub struct SimdI32([i32; LANES]) -where - LaneCount: SupportedLaneCount; - -impl_integer_vector! { SimdI32, i32, Mask32, SimdI32 } - -/// A SIMD vector of containing `LANES` `i64` values. -#[repr(simd)] -pub struct SimdI64([i64; LANES]) -where - LaneCount: SupportedLaneCount; - -impl_integer_vector! { SimdI64, i64, Mask64, SimdI64 } - -/// A SIMD vector of containing `LANES` `i8` values. -#[repr(simd)] -pub struct SimdI8([i8; LANES]) -where - LaneCount: SupportedLaneCount; - -impl_integer_vector! { SimdI8, i8, Mask8, SimdI8 } +impl_integer_vector! { isize } +impl_integer_vector! { i16 } +impl_integer_vector! { i32 } +impl_integer_vector! { i64 } +impl_integer_vector! { i8 } /// Vector of two `isize` values -pub type isizex2 = SimdIsize<2>; +pub type isizex2 = Simd; /// Vector of four `isize` values -pub type isizex4 = SimdIsize<4>; +pub type isizex4 = Simd; /// Vector of eight `isize` values -pub type isizex8 = SimdIsize<8>; +pub type isizex8 = Simd; /// Vector of two `i16` values -pub type i16x2 = SimdI16<2>; +pub type i16x2 = Simd; /// Vector of four `i16` values -pub type i16x4 = SimdI16<4>; +pub type i16x4 = Simd; /// Vector of eight `i16` values -pub type i16x8 = SimdI16<8>; +pub type i16x8 = Simd; /// Vector of 16 `i16` values -pub type i16x16 = SimdI16<16>; +pub type i16x16 = Simd; /// Vector of 32 `i16` values -pub type i16x32 = SimdI16<32>; +pub type i16x32 = Simd; /// Vector of two `i32` values -pub type i32x2 = SimdI32<2>; +pub type i32x2 = Simd; /// Vector of four `i32` values -pub type i32x4 = SimdI32<4>; +pub type i32x4 = Simd; /// Vector of eight `i32` values -pub type i32x8 = SimdI32<8>; +pub type i32x8 = Simd; /// Vector of 16 `i32` values -pub type i32x16 = SimdI32<16>; +pub type i32x16 = Simd; /// Vector of two `i64` values -pub type i64x2 = SimdI64<2>; +pub type i64x2 = Simd; /// Vector of four `i64` values -pub type i64x4 = SimdI64<4>; +pub type i64x4 = Simd; /// Vector of eight `i64` values -pub type i64x8 = SimdI64<8>; +pub type i64x8 = Simd; /// Vector of four `i8` values -pub type i8x4 = SimdI8<4>; +pub type i8x4 = Simd; /// Vector of eight `i8` values -pub type i8x8 = SimdI8<8>; +pub type i8x8 = Simd; /// Vector of 16 `i8` values -pub type i8x16 = SimdI8<16>; +pub type i8x16 = Simd; /// Vector of 32 `i8` values -pub type i8x32 = SimdI8<32>; +pub type i8x32 = Simd; /// Vector of 64 `i8` values -pub type i8x64 = SimdI8<64>; +pub type i8x64 = Simd; diff --git a/crates/core_simd/src/vector/ptr.rs b/crates/core_simd/src/vector/ptr.rs index 9dd1bfd0f365..fc4082a4b555 100644 --- a/crates/core_simd/src/vector/ptr.rs +++ b/crates/core_simd/src/vector/ptr.rs @@ -1,5 +1,5 @@ //! Private implementation details of public gather/scatter APIs. -use crate::{LaneCount, SimdUsize, SupportedLaneCount}; +use crate::{LaneCount, Simd, SupportedLaneCount}; use core::mem; /// A vector of *const T. @@ -20,9 +20,9 @@ where #[inline] #[must_use] - pub fn wrapping_add(self, addend: SimdUsize) -> Self { + pub fn wrapping_add(self, addend: Simd) -> Self { unsafe { - let x: SimdUsize = mem::transmute_copy(&self); + let x: Simd = mem::transmute_copy(&self); mem::transmute_copy(&{ x + (addend * mem::size_of::()) }) } } @@ -46,9 +46,9 @@ where #[inline] #[must_use] - pub fn wrapping_add(self, addend: SimdUsize) -> Self { + pub fn wrapping_add(self, addend: Simd) -> Self { unsafe { - let x: SimdUsize = mem::transmute_copy(&self); + let x: Simd = mem::transmute_copy(&self); mem::transmute_copy(&{ x + (addend * mem::size_of::()) }) } } diff --git a/crates/core_simd/src/vector/uint.rs b/crates/core_simd/src/vector/uint.rs index b19f694872ae..b3dd199a5463 100644 --- a/crates/core_simd/src/vector/uint.rs +++ b/crates/core_simd/src/vector/uint.rs @@ -1,134 +1,63 @@ #![allow(non_camel_case_types)] -use crate::{LaneCount, SupportedLaneCount}; - -/// Implements additional integer traits (Eq, Ord, Hash) on the specified vector `$name`, holding multiple `$lanes` of `$type`. -macro_rules! impl_unsigned_vector { - { $name:ident, $type:ty } => { - impl_vector! { $name, $type } - impl_integer_reductions! { $name, $type } - - impl Eq for $name where LaneCount: SupportedLaneCount {} - - impl Ord for $name where LaneCount: SupportedLaneCount { - #[inline] - fn cmp(&self, other: &Self) -> core::cmp::Ordering { - // TODO use SIMD cmp - self.as_array().cmp(other.as_ref()) - } - } - - impl core::hash::Hash for $name - where - LaneCount: SupportedLaneCount, - { - #[inline] - fn hash(&self, state: &mut H) - where - H: core::hash::Hasher - { - self.as_array().hash(state) - } - } - } -} - -/// A SIMD vector of containing `LANES` `usize` values. -#[repr(simd)] -pub struct SimdUsize([usize; LANES]) -where - LaneCount: SupportedLaneCount; - -impl_unsigned_vector! { SimdUsize, usize } - -/// A SIMD vector of containing `LANES` `u16` values. -#[repr(simd)] -pub struct SimdU16([u16; LANES]) -where - LaneCount: SupportedLaneCount; - -impl_unsigned_vector! { SimdU16, u16 } - -/// A SIMD vector of containing `LANES` `u32` values. -#[repr(simd)] -pub struct SimdU32([u32; LANES]) -where - LaneCount: SupportedLaneCount; - -impl_unsigned_vector! { SimdU32, u32 } - -/// A SIMD vector of containing `LANES` `u64` values. -#[repr(simd)] -pub struct SimdU64([u64; LANES]) -where - LaneCount: SupportedLaneCount; - -impl_unsigned_vector! { SimdU64, u64 } - -/// A SIMD vector of containing `LANES` `u8` values. -#[repr(simd)] -pub struct SimdU8([u8; LANES]) -where - LaneCount: SupportedLaneCount; - -impl_unsigned_vector! { SimdU8, u8 } +use crate::Simd; /// Vector of two `usize` values -pub type usizex2 = SimdUsize<2>; +pub type usizex2 = Simd; /// Vector of four `usize` values -pub type usizex4 = SimdUsize<4>; +pub type usizex4 = Simd; /// Vector of eight `usize` values -pub type usizex8 = SimdUsize<8>; +pub type usizex8 = Simd; /// Vector of two `u16` values -pub type u16x2 = SimdU16<2>; +pub type u16x2 = Simd; /// Vector of four `u16` values -pub type u16x4 = SimdU16<4>; +pub type u16x4 = Simd; /// Vector of eight `u16` values -pub type u16x8 = SimdU16<8>; +pub type u16x8 = Simd; /// Vector of 16 `u16` values -pub type u16x16 = SimdU16<16>; +pub type u16x16 = Simd; /// Vector of 32 `u16` values -pub type u16x32 = SimdU16<32>; +pub type u16x32 = Simd; /// Vector of two `u32` values -pub type u32x2 = SimdU32<2>; +pub type u32x2 = Simd; /// Vector of four `u32` values -pub type u32x4 = SimdU32<4>; +pub type u32x4 = Simd; /// Vector of eight `u32` values -pub type u32x8 = SimdU32<8>; +pub type u32x8 = Simd; /// Vector of 16 `u32` values -pub type u32x16 = SimdU32<16>; +pub type u32x16 = Simd; /// Vector of two `u64` values -pub type u64x2 = SimdU64<2>; +pub type u64x2 = Simd; /// Vector of four `u64` values -pub type u64x4 = SimdU64<4>; +pub type u64x4 = Simd; /// Vector of eight `u64` values -pub type u64x8 = SimdU64<8>; +pub type u64x8 = Simd; /// Vector of four `u8` values -pub type u8x4 = SimdU8<4>; +pub type u8x4 = Simd; /// Vector of eight `u8` values -pub type u8x8 = SimdU8<8>; +pub type u8x8 = Simd; /// Vector of 16 `u8` values -pub type u8x16 = SimdU8<16>; +pub type u8x16 = Simd; /// Vector of 32 `u8` values -pub type u8x32 = SimdU8<32>; +pub type u8x32 = Simd; /// Vector of 64 `u8` values -pub type u8x64 = SimdU8<64>; +pub type u8x64 = Simd; diff --git a/crates/core_simd/src/vector/vector_impl.rs b/crates/core_simd/src/vector/vector_impl.rs deleted file mode 100644 index 58ea244adfcb..000000000000 --- a/crates/core_simd/src/vector/vector_impl.rs +++ /dev/null @@ -1,257 +0,0 @@ -/// Implements common traits on the specified vector `$name`, holding multiple `$lanes` of `$type`. -macro_rules! impl_vector { - { $name:ident, $type:ty } => { - impl crate::vector::sealed::Sealed for $name - where - crate::LaneCount: crate::SupportedLaneCount, - {} - - impl crate::vector::Vector for $name - where - crate::LaneCount: crate::SupportedLaneCount, - { - type Scalar = $type; - const LANES: usize = LANES; - - #[inline] - fn splat(val: Self::Scalar) -> Self { - Self::splat(val) - } - } - - impl $name - where - crate::LaneCount: crate::SupportedLaneCount, - { - /// Construct a SIMD vector by setting all lanes to the given value. - pub const fn splat(value: $type) -> Self { - Self([value; LANES]) - } - - /// Returns an array reference containing the entire SIMD vector. - pub const fn as_array(&self) -> &[$type; LANES] { - &self.0 - } - - /// Returns a mutable array reference containing the entire SIMD vector. - pub fn as_mut_array(&mut self) -> &mut [$type; LANES] { - &mut self.0 - } - - /// Converts an array to a SIMD vector. - pub const fn from_array(array: [$type; LANES]) -> Self { - Self(array) - } - - /// Converts a SIMD vector to an array. - pub const fn to_array(self) -> [$type; LANES] { - self.0 - } - - /// SIMD gather: construct a SIMD vector by reading from a slice, using potentially discontiguous indices. - /// If an index is out of bounds, that lane instead selects the value from the "or" vector. - /// ``` - /// # #![feature(portable_simd)] - /// # use core_simd::*; - /// let vec: Vec = vec![10, 11, 12, 13, 14, 15, 16, 17, 18]; - /// let idxs = SimdUsize::<4>::from_array([9, 3, 0, 5]); - /// let alt = SimdI32::from_array([-5, -4, -3, -2]); - /// - /// let result = SimdI32::<4>::gather_or(&vec, idxs, alt); // Note the lane that is out-of-bounds. - /// assert_eq!(result, SimdI32::from_array([-5, 13, 10, 15])); - /// ``` - #[must_use] - #[inline] - pub fn gather_or(slice: &[$type], idxs: crate::SimdUsize, or: Self) -> Self { - Self::gather_select(slice, crate::MaskSize::splat(true), idxs, or) - } - - /// SIMD gather: construct a SIMD vector by reading from a slice, using potentially discontiguous indices. - /// Out-of-bounds indices instead use the default value for that lane (0). - /// ``` - /// # #![feature(portable_simd)] - /// # use core_simd::*; - /// let vec: Vec = vec![10, 11, 12, 13, 14, 15, 16, 17, 18]; - /// let idxs = SimdUsize::<4>::from_array([9, 3, 0, 5]); - /// - /// let result = SimdI32::<4>::gather_or_default(&vec, idxs); // Note the lane that is out-of-bounds. - /// assert_eq!(result, SimdI32::from_array([0, 13, 10, 15])); - /// ``` - #[must_use] - #[inline] - pub fn gather_or_default(slice: &[$type], idxs: crate::SimdUsize) -> Self { - Self::gather_or(slice, idxs, Self::splat(<$type>::default())) - } - - /// SIMD gather: construct a SIMD vector by reading from a slice, using potentially discontiguous indices. - /// Out-of-bounds or masked indices instead select the value from the "or" vector. - /// ``` - /// # #![feature(portable_simd)] - /// # use core_simd::*; - /// let vec: Vec = vec![10, 11, 12, 13, 14, 15, 16, 17, 18]; - /// let idxs = SimdUsize::<4>::from_array([9, 3, 0, 5]); - /// let alt = SimdI32::from_array([-5, -4, -3, -2]); - /// let mask = MaskSize::from_array([true, true, true, false]); // Note the mask of the last lane. - /// - /// let result = SimdI32::<4>::gather_select(&vec, mask, idxs, alt); // Note the lane that is out-of-bounds. - /// assert_eq!(result, SimdI32::from_array([-5, 13, 10, -2])); - /// ``` - #[must_use] - #[inline] - pub fn gather_select( - slice: &[$type], - mask: crate::MaskSize, - idxs: crate::SimdUsize, - or: Self, - ) -> Self - { - let mask = (mask & idxs.lanes_lt(crate::SimdUsize::splat(slice.len()))).to_int(); - let base_ptr = crate::vector::ptr::SimdConstPtr::splat(slice.as_ptr()); - // Ferris forgive me, I have done pointer arithmetic here. - let ptrs = base_ptr.wrapping_add(idxs); - // SAFETY: The ptrs have been bounds-masked to prevent memory-unsafe reads insha'allah - unsafe { crate::intrinsics::simd_gather(or, ptrs, mask) } - } - - /// SIMD scatter: write a SIMD vector's values into a slice, using potentially discontiguous indices. - /// Out-of-bounds indices are not written. - /// `scatter` writes "in order", so if an index receives two writes, only the last is guaranteed. - /// ``` - /// # #![feature(portable_simd)] - /// # use core_simd::*; - /// let mut vec: Vec = vec![10, 11, 12, 13, 14, 15, 16, 17, 18]; - /// let idxs = SimdUsize::<4>::from_array([9, 3, 0, 0]); - /// let vals = SimdI32::from_array([-27, 82, -41, 124]); - /// - /// vals.scatter(&mut vec, idxs); // index 0 receives two writes. - /// assert_eq!(vec, vec![124, 11, 12, 82, 14, 15, 16, 17, 18]); - /// ``` - #[inline] - pub fn scatter(self, slice: &mut [$type], idxs: crate::SimdUsize) { - self.scatter_select(slice, crate::MaskSize::splat(true), idxs) - } - - /// SIMD scatter: write a SIMD vector's values into a slice, using potentially discontiguous indices. - /// Out-of-bounds or masked indices are not written. - /// `scatter_select` writes "in order", so if an index receives two writes, only the last is guaranteed. - /// ``` - /// # #![feature(portable_simd)] - /// # use core_simd::*; - /// let mut vec: Vec = vec![10, 11, 12, 13, 14, 15, 16, 17, 18]; - /// let idxs = SimdUsize::<4>::from_array([9, 3, 0, 0]); - /// let vals = SimdI32::from_array([-27, 82, -41, 124]); - /// let mask = MaskSize::from_array([true, true, true, false]); // Note the mask of the last lane. - /// - /// vals.scatter_select(&mut vec, mask, idxs); // index 0's second write is masked, thus omitted. - /// assert_eq!(vec, vec![-41, 11, 12, 82, 14, 15, 16, 17, 18]); - /// ``` - #[inline] - pub fn scatter_select( - self, - slice: &mut [$type], - mask: crate::MaskSize, - idxs: crate::SimdUsize, - ) - { - // We must construct our scatter mask before we derive a pointer! - let mask = (mask & idxs.lanes_lt(crate::SimdUsize::splat(slice.len()))).to_int(); - // SAFETY: This block works with *mut T derived from &mut 'a [T], - // which means it is delicate in Rust's borrowing model, circa 2021: - // &mut 'a [T] asserts uniqueness, so deriving &'a [T] invalidates live *mut Ts! - // Even though this block is largely safe methods, it must be almost exactly this way - // to prevent invalidating the raw ptrs while they're live. - // Thus, entering this block requires all values to use being already ready: - // 0. idxs we want to write to, which are used to construct the mask. - // 1. mask, which depends on an initial &'a [T] and the idxs. - // 2. actual values to scatter (self). - // 3. &mut [T] which will become our base ptr. - unsafe { - // Now Entering ☢️ *mut T Zone - let base_ptr = crate::vector::ptr::SimdMutPtr::splat(slice.as_mut_ptr()); - // Ferris forgive me, I have done pointer arithmetic here. - let ptrs = base_ptr.wrapping_add(idxs); - // The ptrs have been bounds-masked to prevent memory-unsafe writes insha'allah - crate::intrinsics::simd_scatter(self, ptrs, mask) - // Cleared ☢️ *mut T Zone - } - } - } - - impl Copy for $name where crate::LaneCount: crate::SupportedLaneCount {} - - impl Clone for $name where crate::LaneCount: crate::SupportedLaneCount { - #[inline] - fn clone(&self) -> Self { - *self - } - } - - impl Default for $name where crate::LaneCount: crate::SupportedLaneCount { - #[inline] - fn default() -> Self { - Self::splat(<$type>::default()) - } - } - - impl PartialEq for $name where crate::LaneCount: crate::SupportedLaneCount { - #[inline] - fn eq(&self, other: &Self) -> bool { - // TODO use SIMD equality - self.to_array() == other.to_array() - } - } - - impl PartialOrd for $name where crate::LaneCount: crate::SupportedLaneCount { - #[inline] - fn partial_cmp(&self, other: &Self) -> Option { - // TODO use SIMD equalitya - self.to_array().partial_cmp(other.as_ref()) - } - } - - // array references - impl AsRef<[$type; LANES]> for $name where crate::LaneCount: crate::SupportedLaneCount { - #[inline] - fn as_ref(&self) -> &[$type; LANES] { - &self.0 - } - } - - impl AsMut<[$type; LANES]> for $name where crate::LaneCount: crate::SupportedLaneCount { - #[inline] - fn as_mut(&mut self) -> &mut [$type; LANES] { - &mut self.0 - } - } - - // slice references - impl AsRef<[$type]> for $name where crate::LaneCount: crate::SupportedLaneCount { - #[inline] - fn as_ref(&self) -> &[$type] { - &self.0 - } - } - - impl AsMut<[$type]> for $name where crate::LaneCount: crate::SupportedLaneCount { - #[inline] - fn as_mut(&mut self) -> &mut [$type] { - &mut self.0 - } - } - - // vector/array conversion - impl From<[$type; LANES]> for $name where crate::LaneCount: crate::SupportedLaneCount { - fn from(array: [$type; LANES]) -> Self { - Self(array) - } - } - - impl From<$name> for [$type; LANES] where crate::LaneCount: crate::SupportedLaneCount { - fn from(vector: $name) -> Self { - vector.to_array() - } - } - - impl_shuffle_2pow_lanes!{ $name } - } -} diff --git a/crates/core_simd/src/vendor/arm.rs b/crates/core_simd/src/vendor/arm.rs index 1a1e9bed1e1d..e39173a9c3c4 100644 --- a/crates/core_simd/src/vendor/arm.rs +++ b/crates/core_simd/src/vendor/arm.rs @@ -28,26 +28,26 @@ from_transmute! { unsafe u32x4 => uint32x4_t } from_transmute! { unsafe i32x2 => int32x2_t } from_transmute! { unsafe i32x4 => int32x4_t } -from_transmute! { unsafe SimdU64<1> => uint64x1_t } +from_transmute! { unsafe Simd => uint64x1_t } from_transmute! { unsafe u64x2 => uint64x2_t } -from_transmute! { unsafe SimdI64<1> => int64x1_t } +from_transmute! { unsafe Simd => int64x1_t } from_transmute! { unsafe i64x2 => int64x2_t } -from_transmute! { unsafe SimdU64<1> => poly64x1_t } +from_transmute! { unsafe Simd => poly64x1_t } from_transmute! { unsafe u64x2 => poly64x2_t } #[cfg(target_arch = "arm")] mod arm { use super::*; - from_transmute! { unsafe SimdU8<4> => uint8x4_t } - from_transmute! { unsafe SimdI8<4> => int8x4_t } + from_transmute! { unsafe Simd => uint8x4_t } + from_transmute! { unsafe Simd => int8x4_t } - from_transmute! { unsafe SimdU16<2> => uint16x2_t } - from_transmute! { unsafe SimdI16<2> => int16x2_t } + from_transmute! { unsafe Simd => uint16x2_t } + from_transmute! { unsafe Simd => int16x2_t } } #[cfg(target_arch = "aarch64")] mod aarch64 { use super::*; - from_transmute! { unsafe SimdF64<1> => float64x1_t } + from_transmute! { unsafe Simd => float64x1_t } from_transmute! { unsafe f64x2 => float64x2_t } } diff --git a/crates/core_simd/src/vendor/x86.rs b/crates/core_simd/src/vendor/x86.rs index 4de57de057e5..0090c3756481 100644 --- a/crates/core_simd/src/vendor/x86.rs +++ b/crates/core_simd/src/vendor/x86.rs @@ -45,10 +45,10 @@ mod p32 { use super::*; from_transmute! { unsafe usizex4 => __m128i } from_transmute! { unsafe usizex8 => __m256i } - from_transmute! { unsafe SimdUsize<16> => __m512i } + from_transmute! { unsafe Simd => __m512i } from_transmute! { unsafe isizex4 => __m128i } from_transmute! { unsafe isizex8 => __m256i } - from_transmute! { unsafe SimdIsize<16> => __m512i } + from_transmute! { unsafe Simd => __m512i } } #[cfg(target_pointer_width = "64")] diff --git a/crates/core_simd/tests/f32_ops.rs b/crates/core_simd/tests/f32_ops.rs index 98283110097e..414a832b1be4 100644 --- a/crates/core_simd/tests/f32_ops.rs +++ b/crates/core_simd/tests/f32_ops.rs @@ -2,4 +2,4 @@ #[macro_use] mod ops_macros; -impl_float_tests! { SimdF32, f32, i32 } +impl_float_tests! { f32, i32 } diff --git a/crates/core_simd/tests/f64_ops.rs b/crates/core_simd/tests/f64_ops.rs index 0818b0c5c5a9..e0a1fa33f332 100644 --- a/crates/core_simd/tests/f64_ops.rs +++ b/crates/core_simd/tests/f64_ops.rs @@ -2,4 +2,4 @@ #[macro_use] mod ops_macros; -impl_float_tests! { SimdF64, f64, i64 } +impl_float_tests! { f64, i64 } diff --git a/crates/core_simd/tests/i16_ops.rs b/crates/core_simd/tests/i16_ops.rs index 33d92faa5956..f6c5d74fbbcc 100644 --- a/crates/core_simd/tests/i16_ops.rs +++ b/crates/core_simd/tests/i16_ops.rs @@ -2,4 +2,4 @@ #[macro_use] mod ops_macros; -impl_signed_tests! { SimdI16, i16 } +impl_signed_tests! { i16 } diff --git a/crates/core_simd/tests/i32_ops.rs b/crates/core_simd/tests/i32_ops.rs index 481bca23e834..69a831c52a3f 100644 --- a/crates/core_simd/tests/i32_ops.rs +++ b/crates/core_simd/tests/i32_ops.rs @@ -2,4 +2,4 @@ #[macro_use] mod ops_macros; -impl_signed_tests! { SimdI32, i32 } +impl_signed_tests! { i32 } diff --git a/crates/core_simd/tests/i64_ops.rs b/crates/core_simd/tests/i64_ops.rs index 5ab0614c8480..37ac08117424 100644 --- a/crates/core_simd/tests/i64_ops.rs +++ b/crates/core_simd/tests/i64_ops.rs @@ -2,4 +2,4 @@ #[macro_use] mod ops_macros; -impl_signed_tests! { SimdI64, i64 } +impl_signed_tests! { i64 } diff --git a/crates/core_simd/tests/i8_ops.rs b/crates/core_simd/tests/i8_ops.rs index 0db9ee47a9e2..11e4a5cd6a9a 100644 --- a/crates/core_simd/tests/i8_ops.rs +++ b/crates/core_simd/tests/i8_ops.rs @@ -2,4 +2,4 @@ #[macro_use] mod ops_macros; -impl_signed_tests! { SimdI8, i8 } +impl_signed_tests! { i8 } diff --git a/crates/core_simd/tests/isize_ops.rs b/crates/core_simd/tests/isize_ops.rs index 8f5470b685c9..5cc9de2b7ff8 100644 --- a/crates/core_simd/tests/isize_ops.rs +++ b/crates/core_simd/tests/isize_ops.rs @@ -2,4 +2,4 @@ #[macro_use] mod ops_macros; -impl_signed_tests! { SimdIsize, isize } +impl_signed_tests! { isize } diff --git a/crates/core_simd/tests/masks.rs b/crates/core_simd/tests/masks.rs index 61d8e449744b..cf8039d153d5 100644 --- a/crates/core_simd/tests/masks.rs +++ b/crates/core_simd/tests/masks.rs @@ -7,9 +7,9 @@ use wasm_bindgen_test::*; wasm_bindgen_test_configure!(run_in_browser); macro_rules! test_mask_api { - { $name:ident } => { + { $type:ident } => { #[allow(non_snake_case)] - mod $name { + mod $type { #[cfg(target_arch = "wasm32")] use wasm_bindgen_test::*; @@ -17,7 +17,7 @@ macro_rules! test_mask_api { #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn set_and_test() { let values = [true, false, false, true, false, false, true, false]; - let mut mask = core_simd::$name::<8>::splat(false); + let mut mask = core_simd::Mask::<$type, 8>::splat(false); for (lane, value) in values.iter().copied().enumerate() { mask.set(lane, value); } @@ -29,7 +29,7 @@ macro_rules! test_mask_api { #[test] #[should_panic] fn set_invalid_lane() { - let mut mask = core_simd::$name::<8>::splat(false); + let mut mask = core_simd::Mask::<$type, 8>::splat(false); mask.set(8, true); let _ = mask; } @@ -37,24 +37,24 @@ macro_rules! test_mask_api { #[test] #[should_panic] fn test_invalid_lane() { - let mask = core_simd::$name::<8>::splat(false); + let mask = core_simd::Mask::<$type, 8>::splat(false); let _ = mask.test(8); } #[test] fn any() { - assert!(!core_simd::$name::<8>::splat(false).any()); - assert!(core_simd::$name::<8>::splat(true).any()); - let mut v = core_simd::$name::<8>::splat(false); + assert!(!core_simd::Mask::<$type, 8>::splat(false).any()); + assert!(core_simd::Mask::<$type, 8>::splat(true).any()); + let mut v = core_simd::Mask::<$type, 8>::splat(false); v.set(2, true); assert!(v.any()); } #[test] fn all() { - assert!(!core_simd::$name::<8>::splat(false).all()); - assert!(core_simd::$name::<8>::splat(true).all()); - let mut v = core_simd::$name::<8>::splat(false); + assert!(!core_simd::Mask::<$type, 8>::splat(false).all()); + assert!(core_simd::Mask::<$type, 8>::splat(true).all()); + let mut v = core_simd::Mask::<$type, 8>::splat(false); v.set(2, true); assert!(!v.all()); } @@ -62,10 +62,10 @@ macro_rules! test_mask_api { #[test] fn roundtrip_int_conversion() { let values = [true, false, false, true, false, false, true, false]; - let mask = core_simd::$name::<8>::from_array(values); + let mask = core_simd::Mask::<$type, 8>::from_array(values); let int = mask.to_int(); assert_eq!(int.to_array(), [-1, 0, 0, -1, 0, 0, -1, 0]); - assert_eq!(core_simd::$name::<8>::from_int(int), mask); + assert_eq!(core_simd::Mask::<$type, 8>::from_int(int), mask); } #[test] @@ -74,24 +74,24 @@ macro_rules! test_mask_api { true, false, false, true, false, false, true, false, true, true, false, false, false, false, false, true, ]; - let mask = core_simd::$name::<16>::from_array(values); + let mask = core_simd::Mask::<$type, 16>::from_array(values); let bitmask = mask.to_bitmask(); assert_eq!(bitmask, [0b01001001, 0b10000011]); - assert_eq!(core_simd::$name::<16>::from_bitmask(bitmask), mask); + assert_eq!(core_simd::Mask::<$type, 16>::from_bitmask(bitmask), mask); } } } } mod mask_api { - test_mask_api! { Mask8 } + test_mask_api! { i8 } } #[test] fn convert() { let values = [true, false, false, true, false, false, true, false]; assert_eq!( - core_simd::Mask8::from_array(values), - core_simd::Mask32::from_array(values).into() + core_simd::Mask::::from_array(values), + core_simd::Mask::::from_array(values).into() ); } diff --git a/crates/core_simd/tests/ops_macros.rs b/crates/core_simd/tests/ops_macros.rs index 81553c34aa77..0c45ea2367c9 100644 --- a/crates/core_simd/tests/ops_macros.rs +++ b/crates/core_simd/tests/ops_macros.rs @@ -3,19 +3,19 @@ /// Compares the vector operation to the equivalent scalar operation. #[macro_export] macro_rules! impl_unary_op_test { - { $vector:ty, $scalar:ty, $trait:ident :: $fn:ident, $scalar_fn:expr } => { + { $scalar:ty, $trait:ident :: $fn:ident, $scalar_fn:expr } => { test_helpers::test_lanes! { fn $fn() { test_helpers::test_unary_elementwise( - &<$vector as core::ops::$trait>::$fn, + & as core::ops::$trait>::$fn, &$scalar_fn, &|_| true, ); } } }; - { $vector:ty, $scalar:ty, $trait:ident :: $fn:ident } => { - impl_unary_op_test! { $vector, $scalar, $trait::$fn, <$scalar as core::ops::$trait>::$fn } + { $scalar:ty, $trait:ident :: $fn:ident } => { + impl_unary_op_test! { $scalar, $trait::$fn, <$scalar as core::ops::$trait>::$fn } }; } @@ -24,14 +24,15 @@ macro_rules! impl_unary_op_test { /// Compares the vector operation to the equivalent scalar operation. #[macro_export] macro_rules! impl_binary_op_test { - { $vector:ty, $scalar:ty, $trait:ident :: $fn:ident, $trait_assign:ident :: $fn_assign:ident, $scalar_fn:expr } => { + { $scalar:ty, $trait:ident :: $fn:ident, $trait_assign:ident :: $fn_assign:ident, $scalar_fn:expr } => { mod $fn { use super::*; + use core_simd::Simd; test_helpers::test_lanes! { fn normal() { test_helpers::test_binary_elementwise( - &<$vector as core::ops::$trait>::$fn, + & as core::ops::$trait>::$fn, &$scalar_fn, &|_, _| true, ); @@ -39,7 +40,7 @@ macro_rules! impl_binary_op_test { fn scalar_rhs() { test_helpers::test_binary_scalar_rhs_elementwise( - &<$vector as core::ops::$trait<$scalar>>::$fn, + & as core::ops::$trait<$scalar>>::$fn, &$scalar_fn, &|_, _| true, ); @@ -47,7 +48,7 @@ macro_rules! impl_binary_op_test { fn scalar_lhs() { test_helpers::test_binary_scalar_lhs_elementwise( - &<$scalar as core::ops::$trait<$vector>>::$fn, + &<$scalar as core::ops::$trait>>::$fn, &$scalar_fn, &|_, _| true, ); @@ -55,7 +56,7 @@ macro_rules! impl_binary_op_test { fn assign() { test_helpers::test_binary_elementwise( - &|mut a, b| { <$vector as core::ops::$trait_assign>::$fn_assign(&mut a, b); a }, + &|mut a, b| { as core::ops::$trait_assign>::$fn_assign(&mut a, b); a }, &$scalar_fn, &|_, _| true, ); @@ -63,7 +64,7 @@ macro_rules! impl_binary_op_test { fn assign_scalar_rhs() { test_helpers::test_binary_scalar_rhs_elementwise( - &|mut a, b| { <$vector as core::ops::$trait_assign<$scalar>>::$fn_assign(&mut a, b); a }, + &|mut a, b| { as core::ops::$trait_assign<$scalar>>::$fn_assign(&mut a, b); a }, &$scalar_fn, &|_, _| true, ); @@ -71,8 +72,8 @@ macro_rules! impl_binary_op_test { } } }; - { $vector:ty, $scalar:ty, $trait:ident :: $fn:ident, $trait_assign:ident :: $fn_assign:ident } => { - impl_binary_op_test! { $vector, $scalar, $trait::$fn, $trait_assign::$fn_assign, <$scalar as core::ops::$trait>::$fn } + { $scalar:ty, $trait:ident :: $fn:ident, $trait_assign:ident :: $fn_assign:ident } => { + impl_binary_op_test! { $scalar, $trait::$fn, $trait_assign::$fn_assign, <$scalar as core::ops::$trait>::$fn } }; } @@ -84,14 +85,15 @@ macro_rules! impl_binary_op_test { /// Compares the vector operation to the equivalent scalar operation. #[macro_export] macro_rules! impl_binary_checked_op_test { - { $vector:ty, $scalar:ty, $trait:ident :: $fn:ident, $trait_assign:ident :: $fn_assign:ident, $scalar_fn:expr, $check_fn:expr } => { + { $scalar:ty, $trait:ident :: $fn:ident, $trait_assign:ident :: $fn_assign:ident, $scalar_fn:expr, $check_fn:expr } => { mod $fn { use super::*; + use core_simd::Simd; test_helpers::test_lanes! { fn normal() { test_helpers::test_binary_elementwise( - &<$vector as core::ops::$trait>::$fn, + & as core::ops::$trait>::$fn, &$scalar_fn, &|x, y| x.iter().zip(y.iter()).all(|(x, y)| $check_fn(*x, *y)), ); @@ -99,7 +101,7 @@ macro_rules! impl_binary_checked_op_test { fn scalar_rhs() { test_helpers::test_binary_scalar_rhs_elementwise( - &<$vector as core::ops::$trait<$scalar>>::$fn, + & as core::ops::$trait<$scalar>>::$fn, &$scalar_fn, &|x, y| x.iter().all(|x| $check_fn(*x, y)), ); @@ -107,7 +109,7 @@ macro_rules! impl_binary_checked_op_test { fn scalar_lhs() { test_helpers::test_binary_scalar_lhs_elementwise( - &<$scalar as core::ops::$trait<$vector>>::$fn, + &<$scalar as core::ops::$trait>>::$fn, &$scalar_fn, &|x, y| y.iter().all(|y| $check_fn(x, *y)), ); @@ -115,7 +117,7 @@ macro_rules! impl_binary_checked_op_test { fn assign() { test_helpers::test_binary_elementwise( - &|mut a, b| { <$vector as core::ops::$trait_assign>::$fn_assign(&mut a, b); a }, + &|mut a, b| { as core::ops::$trait_assign>::$fn_assign(&mut a, b); a }, &$scalar_fn, &|x, y| x.iter().zip(y.iter()).all(|(x, y)| $check_fn(*x, *y)), ) @@ -123,7 +125,7 @@ macro_rules! impl_binary_checked_op_test { fn assign_scalar_rhs() { test_helpers::test_binary_scalar_rhs_elementwise( - &|mut a, b| { <$vector as core::ops::$trait_assign<$scalar>>::$fn_assign(&mut a, b); a }, + &|mut a, b| { as core::ops::$trait_assign<$scalar>>::$fn_assign(&mut a, b); a }, &$scalar_fn, &|x, y| x.iter().all(|x| $check_fn(*x, y)), ) @@ -131,8 +133,8 @@ macro_rules! impl_binary_checked_op_test { } } }; - { $vector:ty, $scalar:ty, $trait:ident :: $fn:ident, $trait_assign:ident :: $fn_assign:ident, $check_fn:expr } => { - impl_binary_nonzero_rhs_op_test! { $vector, $scalar, $trait::$fn, $trait_assign::$fn_assign, <$scalar as core::ops::$trait>::$fn, $check_fn } + { $scalar:ty, $trait:ident :: $fn:ident, $trait_assign:ident :: $fn_assign:ident, $check_fn:expr } => { + impl_binary_checked_op_test! { $scalar, $trait::$fn, $trait_assign::$fn_assign, <$scalar as core::ops::$trait>::$fn, $check_fn } }; } @@ -216,9 +218,9 @@ macro_rules! impl_common_integer_tests { /// Implement tests for signed integers. #[macro_export] macro_rules! impl_signed_tests { - { $vector:ident, $scalar:tt } => { + { $scalar:tt } => { mod $scalar { - type Vector = core_simd::$vector; + type Vector = core_simd::Simd; type Scalar = $scalar; impl_common_integer_tests! { Vector, Scalar } @@ -305,18 +307,18 @@ macro_rules! impl_signed_tests { } } - impl_binary_op_test!(Vector, Scalar, Add::add, AddAssign::add_assign, Scalar::wrapping_add); - impl_binary_op_test!(Vector, Scalar, Sub::sub, SubAssign::sub_assign, Scalar::wrapping_sub); - impl_binary_op_test!(Vector, Scalar, Mul::mul, MulAssign::mul_assign, Scalar::wrapping_mul); + impl_binary_op_test!(Scalar, Add::add, AddAssign::add_assign, Scalar::wrapping_add); + impl_binary_op_test!(Scalar, Sub::sub, SubAssign::sub_assign, Scalar::wrapping_sub); + impl_binary_op_test!(Scalar, Mul::mul, MulAssign::mul_assign, Scalar::wrapping_mul); // Exclude Div and Rem panicking cases - impl_binary_checked_op_test!(Vector, Scalar, Div::div, DivAssign::div_assign, Scalar::wrapping_div, |x, y| y != 0 && !(x == Scalar::MIN && y == -1)); - impl_binary_checked_op_test!(Vector, Scalar, Rem::rem, RemAssign::rem_assign, Scalar::wrapping_rem, |x, y| y != 0 && !(x == Scalar::MIN && y == -1)); + impl_binary_checked_op_test!(Scalar, Div::div, DivAssign::div_assign, Scalar::wrapping_div, |x, y| y != 0 && !(x == Scalar::MIN && y == -1)); + impl_binary_checked_op_test!(Scalar, Rem::rem, RemAssign::rem_assign, Scalar::wrapping_rem, |x, y| y != 0 && !(x == Scalar::MIN && y == -1)); - impl_unary_op_test!(Vector, Scalar, Not::not); - impl_binary_op_test!(Vector, Scalar, BitAnd::bitand, BitAndAssign::bitand_assign); - impl_binary_op_test!(Vector, Scalar, BitOr::bitor, BitOrAssign::bitor_assign); - impl_binary_op_test!(Vector, Scalar, BitXor::bitxor, BitXorAssign::bitxor_assign); + impl_unary_op_test!(Scalar, Not::not); + impl_binary_op_test!(Scalar, BitAnd::bitand, BitAndAssign::bitand_assign); + impl_binary_op_test!(Scalar, BitOr::bitor, BitOrAssign::bitor_assign); + impl_binary_op_test!(Scalar, BitXor::bitxor, BitXorAssign::bitxor_assign); } } } @@ -324,9 +326,9 @@ macro_rules! impl_signed_tests { /// Implement tests for unsigned integers. #[macro_export] macro_rules! impl_unsigned_tests { - { $vector:ident, $scalar:tt } => { + { $scalar:tt } => { mod $scalar { - type Vector = core_simd::$vector; + type Vector = core_simd::Simd; type Scalar = $scalar; impl_common_integer_tests! { Vector, Scalar } @@ -339,18 +341,18 @@ macro_rules! impl_unsigned_tests { } } - impl_binary_op_test!(Vector, Scalar, Add::add, AddAssign::add_assign, Scalar::wrapping_add); - impl_binary_op_test!(Vector, Scalar, Sub::sub, SubAssign::sub_assign, Scalar::wrapping_sub); - impl_binary_op_test!(Vector, Scalar, Mul::mul, MulAssign::mul_assign, Scalar::wrapping_mul); + impl_binary_op_test!(Scalar, Add::add, AddAssign::add_assign, Scalar::wrapping_add); + impl_binary_op_test!(Scalar, Sub::sub, SubAssign::sub_assign, Scalar::wrapping_sub); + impl_binary_op_test!(Scalar, Mul::mul, MulAssign::mul_assign, Scalar::wrapping_mul); // Exclude Div and Rem panicking cases - impl_binary_checked_op_test!(Vector, Scalar, Div::div, DivAssign::div_assign, Scalar::wrapping_div, |_, y| y != 0); - impl_binary_checked_op_test!(Vector, Scalar, Rem::rem, RemAssign::rem_assign, Scalar::wrapping_rem, |_, y| y != 0); + impl_binary_checked_op_test!(Scalar, Div::div, DivAssign::div_assign, Scalar::wrapping_div, |_, y| y != 0); + impl_binary_checked_op_test!(Scalar, Rem::rem, RemAssign::rem_assign, Scalar::wrapping_rem, |_, y| y != 0); - impl_unary_op_test!(Vector, Scalar, Not::not); - impl_binary_op_test!(Vector, Scalar, BitAnd::bitand, BitAndAssign::bitand_assign); - impl_binary_op_test!(Vector, Scalar, BitOr::bitor, BitOrAssign::bitor_assign); - impl_binary_op_test!(Vector, Scalar, BitXor::bitxor, BitXorAssign::bitxor_assign); + impl_unary_op_test!(Scalar, Not::not); + impl_binary_op_test!(Scalar, BitAnd::bitand, BitAndAssign::bitand_assign); + impl_binary_op_test!(Scalar, BitOr::bitor, BitOrAssign::bitor_assign); + impl_binary_op_test!(Scalar, BitXor::bitxor, BitXorAssign::bitxor_assign); } } } @@ -358,17 +360,17 @@ macro_rules! impl_unsigned_tests { /// Implement tests for floating point numbers. #[macro_export] macro_rules! impl_float_tests { - { $vector:ident, $scalar:tt, $int_scalar:tt } => { + { $scalar:tt, $int_scalar:tt } => { mod $scalar { - type Vector = core_simd::$vector; + type Vector = core_simd::Simd; type Scalar = $scalar; - impl_unary_op_test!(Vector, Scalar, Neg::neg); - impl_binary_op_test!(Vector, Scalar, Add::add, AddAssign::add_assign); - impl_binary_op_test!(Vector, Scalar, Sub::sub, SubAssign::sub_assign); - impl_binary_op_test!(Vector, Scalar, Mul::mul, MulAssign::mul_assign); - impl_binary_op_test!(Vector, Scalar, Div::div, DivAssign::div_assign); - impl_binary_op_test!(Vector, Scalar, Rem::rem, RemAssign::rem_assign); + impl_unary_op_test!(Scalar, Neg::neg); + impl_binary_op_test!(Scalar, Add::add, AddAssign::add_assign); + impl_binary_op_test!(Scalar, Sub::sub, SubAssign::sub_assign); + impl_binary_op_test!(Scalar, Mul::mul, MulAssign::mul_assign); + impl_binary_op_test!(Scalar, Div::div, DivAssign::div_assign); + impl_binary_op_test!(Scalar, Rem::rem, RemAssign::rem_assign); test_helpers::test_lanes! { fn is_sign_positive() { diff --git a/crates/core_simd/tests/permute.rs b/crates/core_simd/tests/permute.rs index 4c771002528f..ea52e8f5ca73 100644 --- a/crates/core_simd/tests/permute.rs +++ b/crates/core_simd/tests/permute.rs @@ -1,6 +1,6 @@ #![feature(portable_simd)] -use core_simd::SimdU32; +use core_simd::Simd; #[cfg(target_arch = "wasm32")] use wasm_bindgen_test::*; @@ -11,7 +11,7 @@ wasm_bindgen_test_configure!(run_in_browser); #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn simple_shuffle() { - let a = SimdU32::from_array([2, 4, 1, 9]); + let a = Simd::from_array([2, 4, 1, 9]); let b = a; assert_eq!(a.shuffle::<{ [3, 1, 4, 6] }>(b).to_array(), [9, 4, 2, 1]); } @@ -19,15 +19,15 @@ fn simple_shuffle() { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn reverse() { - let a = SimdU32::from_array([0, 1, 2, 3, 4, 5, 6, 7]); + let a = Simd::from_array([0, 1, 2, 3, 4, 5, 6, 7]); assert_eq!(a.reverse().to_array(), [7, 6, 5, 4, 3, 2, 1, 0]); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn interleave() { - let a = SimdU32::from_array([0, 1, 2, 3, 4, 5, 6, 7]); - let b = SimdU32::from_array([8, 9, 10, 11, 12, 13, 14, 15]); + let a = Simd::from_array([0, 1, 2, 3, 4, 5, 6, 7]); + let b = Simd::from_array([8, 9, 10, 11, 12, 13, 14, 15]); let (lo, hi) = a.interleave(b); assert_eq!(lo.to_array(), [0, 8, 1, 9, 2, 10, 3, 11]); assert_eq!(hi.to_array(), [4, 12, 5, 13, 6, 14, 7, 15]); diff --git a/crates/core_simd/tests/round.rs b/crates/core_simd/tests/round.rs index 37044a751125..11d617a6c2c5 100644 --- a/crates/core_simd/tests/round.rs +++ b/crates/core_simd/tests/round.rs @@ -1,9 +1,9 @@ #![feature(portable_simd)] macro_rules! float_rounding_test { - { $vector:ident, $scalar:tt, $int_scalar:tt } => { + { $scalar:tt, $int_scalar:tt } => { mod $scalar { - type Vector = core_simd::$vector; + type Vector = core_simd::Simd<$scalar, LANES>; type Scalar = $scalar; type IntScalar = $int_scalar; @@ -88,5 +88,5 @@ macro_rules! float_rounding_test { } } -float_rounding_test! { SimdF32, f32, i32 } -float_rounding_test! { SimdF64, f64, i64 } +float_rounding_test! { f32, i32 } +float_rounding_test! { f64, i64 } diff --git a/crates/core_simd/tests/to_bytes.rs b/crates/core_simd/tests/to_bytes.rs index 22c97c95d927..c66c9d5bd36f 100644 --- a/crates/core_simd/tests/to_bytes.rs +++ b/crates/core_simd/tests/to_bytes.rs @@ -2,13 +2,13 @@ #![allow(incomplete_features)] #![cfg(feature = "const_evaluatable_checked")] -use core_simd::SimdU32; +use core_simd::Simd; #[test] fn byte_convert() { - let int = SimdU32::from_array([0xdeadbeef, 0x8badf00d]); + let int = Simd::::from_array([0xdeadbeef, 0x8badf00d]); let bytes = int.to_ne_bytes(); assert_eq!(int[0].to_ne_bytes(), bytes[..4]); assert_eq!(int[1].to_ne_bytes(), bytes[4..]); - assert_eq!(SimdU32::from_ne_bytes(bytes), int); + assert_eq!(Simd::::from_ne_bytes(bytes), int); } diff --git a/crates/core_simd/tests/u16_ops.rs b/crates/core_simd/tests/u16_ops.rs index d220dae64568..9ae3bd6a47d0 100644 --- a/crates/core_simd/tests/u16_ops.rs +++ b/crates/core_simd/tests/u16_ops.rs @@ -2,4 +2,4 @@ #[macro_use] mod ops_macros; -impl_unsigned_tests! { SimdU16, u16 } +impl_unsigned_tests! { u16 } diff --git a/crates/core_simd/tests/u32_ops.rs b/crates/core_simd/tests/u32_ops.rs index f27cc30a17fc..de34b73d6526 100644 --- a/crates/core_simd/tests/u32_ops.rs +++ b/crates/core_simd/tests/u32_ops.rs @@ -2,4 +2,4 @@ #[macro_use] mod ops_macros; -impl_unsigned_tests! { SimdU32, u32 } +impl_unsigned_tests! { u32 } diff --git a/crates/core_simd/tests/u64_ops.rs b/crates/core_simd/tests/u64_ops.rs index ec3df39c53c3..8ee5a318c83d 100644 --- a/crates/core_simd/tests/u64_ops.rs +++ b/crates/core_simd/tests/u64_ops.rs @@ -2,4 +2,4 @@ #[macro_use] mod ops_macros; -impl_unsigned_tests! { SimdU64, u64 } +impl_unsigned_tests! { u64 } diff --git a/crates/core_simd/tests/u8_ops.rs b/crates/core_simd/tests/u8_ops.rs index 2c52a52b9216..6d7211121284 100644 --- a/crates/core_simd/tests/u8_ops.rs +++ b/crates/core_simd/tests/u8_ops.rs @@ -2,4 +2,4 @@ #[macro_use] mod ops_macros; -impl_unsigned_tests! { SimdU8, u8 } +impl_unsigned_tests! { u8 } diff --git a/crates/core_simd/tests/usize_ops.rs b/crates/core_simd/tests/usize_ops.rs index 070edc4e266f..9c7b1687a085 100644 --- a/crates/core_simd/tests/usize_ops.rs +++ b/crates/core_simd/tests/usize_ops.rs @@ -2,4 +2,4 @@ #[macro_use] mod ops_macros; -impl_unsigned_tests! { SimdUsize, usize } +impl_unsigned_tests! { usize }