diff --git a/crates/core_simd/src/lib.rs b/crates/core_simd/src/lib.rs index 413a886f6c5..09eace325c5 100644 --- a/crates/core_simd/src/lib.rs +++ b/crates/core_simd/src/lib.rs @@ -1,5 +1,6 @@ #![no_std] #![feature( + arbitrary_self_types, convert_float_to_int, f16, core_intrinsics, diff --git a/crates/core_simd/src/masks.rs b/crates/core_simd/src/masks.rs index cb5d54020f7..bc4cc3e98ca 100644 --- a/crates/core_simd/src/masks.rs +++ b/crates/core_simd/src/masks.rs @@ -291,6 +291,80 @@ where unsafe { core::intrinsics::simd::simd_reduce_all(self.0) } } + /// Test if each element is equal to the corresponding element in `other`. + #[inline] + #[must_use = "method returns a new mask and does not mutate the original value"] + pub fn simd_eq(self, other: Self) -> Self { + // Safety: `self` is a mask vector, and the result of comparison is always a valid mask. + unsafe { Self::from_simd_unchecked(core::intrinsics::simd::simd_eq(self.0, other.0)) } + } + + /// Test if each element is not equal to the corresponding element in `other`. + #[inline] + #[must_use = "method returns a new mask and does not mutate the original value"] + pub fn simd_ne(self, other: Self) -> Self { + // Safety: `self` is a mask vector, and the result of comparison is always a valid mask. + unsafe { Self::from_simd_unchecked(core::intrinsics::simd::simd_ne(self.0, other.0)) } + } + + /// Test if each element is less than the corresponding element in `other`. + #[inline] + #[must_use = "method returns a new mask and does not mutate the original value"] + pub fn simd_lt(self, other: Self) -> Self { + // Safety: `self` is a mask vector, and the result of comparison is always a valid mask. + unsafe { Self::from_simd_unchecked(core::intrinsics::simd::simd_lt(self.0, other.0)) } + } + + /// Test if each element is less than or equal to the corresponding element in `other`. + #[inline] + #[must_use = "method returns a new mask and does not mutate the original value"] + pub fn simd_le(self, other: Self) -> Self { + // Safety: `self` is a mask vector, and the result of comparison is always a valid mask. + unsafe { Self::from_simd_unchecked(core::intrinsics::simd::simd_le(self.0, other.0)) } + } + + /// Test if each element is greater than the corresponding element in `other`. + #[inline] + #[must_use = "method returns a new mask and does not mutate the original value"] + pub fn simd_gt(self, other: Self) -> Self { + // Safety: `self` is a mask vector, and the result of comparison is always a valid mask. + unsafe { Self::from_simd_unchecked(core::intrinsics::simd::simd_gt(self.0, other.0)) } + } + + /// Test if each element is greater than or equal to the corresponding element in `other`. + #[inline] + #[must_use = "method returns a new mask and does not mutate the original value"] + pub fn simd_ge(self, other: Self) -> Self { + // Safety: `self` is a mask vector, and the result of comparison is always a valid mask. + unsafe { Self::from_simd_unchecked(core::intrinsics::simd::simd_ge(self.0, other.0)) } + } + + /// Returns the element-wise maximum with `other`. + #[inline] + #[must_use = "method returns a new mask and does not mutate the original value"] + pub fn simd_max(self, other: Self) -> Self { + self.simd_gt(other).select(other, self) + } + + /// Returns the element-wise minimum with `other`. + #[inline] + #[must_use = "method returns a new mask and does not mutate the original value"] + pub fn simd_min(self, other: Self) -> Self { + self.simd_lt(other).select(other, self) + } + + /// Restrict each element to a certain interval. + #[inline] + #[must_use = "method returns a new mask and does not mutate the original value"] + #[track_caller] + pub fn simd_clamp(self, min: Self, max: Self) -> Self { + assert!( + min.simd_le(max).all(), + "each element in `min` must be less than or equal to the corresponding element in `max`", + ); + self.simd_max(min).simd_min(max) + } + /// Creates a bitmask from a mask. /// /// Each bit is set if the corresponding element in the mask is `true`. @@ -667,3 +741,10 @@ 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 } + +impl core::ops::Receiver for Mask +where + T: MaskElement, +{ + type Target = T; +} diff --git a/crates/core_simd/src/simd/cmp/eq.rs b/crates/core_simd/src/simd/cmp/eq.rs index 76836404cbc..3ffd6c83aee 100644 --- a/crates/core_simd/src/simd/cmp/eq.rs +++ b/crates/core_simd/src/simd/cmp/eq.rs @@ -4,35 +4,41 @@ use crate::simd::{ }; /// Parallel `PartialEq`. -pub trait SimdPartialEq { - /// The mask type returned by each comparison. - type Mask; - +pub trait SimdPartialEq: SimdElement { /// Test if each element is equal to the corresponding element in `other`. #[must_use = "method returns a new mask and does not mutate the original value"] - fn simd_eq(self, other: Self) -> Self::Mask; + fn simd_eq( + self: Simd, + other: Simd, + ) -> Mask<::Mask, N>; /// Test if each element is not equal to the corresponding element in `other`. #[must_use = "method returns a new mask and does not mutate the original value"] - fn simd_ne(self, other: Self) -> Self::Mask; + fn simd_ne( + self: Simd, + other: Simd, + ) -> Mask<::Mask, N>; } macro_rules! impl_number { { $($number:ty),* } => { $( - impl SimdPartialEq for Simd<$number, N> - { - type Mask = Mask<<$number as SimdElement>::Mask, N>; - + impl SimdPartialEq for $number { #[inline] - fn simd_eq(self, other: Self) -> Self::Mask { + fn simd_eq( + self: Simd, + other: Simd, + ) -> Mask<::Mask, N> { // Safety: `self` is a vector, and the result of the comparison // is always a valid mask. unsafe { Mask::from_simd_unchecked(core::intrinsics::simd::simd_eq(self, other)) } } #[inline] - fn simd_ne(self, other: Self) -> Self::Mask { + fn simd_ne( + self: Simd, + other: Simd, + ) -> Mask<::Mask, N> { // Safety: `self` is a vector, and the result of the comparison // is always a valid mask. unsafe { Mask::from_simd_unchecked(core::intrinsics::simd::simd_ne(self, other)) } @@ -44,57 +50,26 @@ macro_rules! impl_number { impl_number! { f16, f32, f64, u8, u16, u32, u64, usize, i8, i16, i32, i64, isize } -macro_rules! impl_mask { - { $($integer:ty),* } => { - $( - impl SimdPartialEq for Mask<$integer, N> - { - type Mask = Self; - - #[inline] - fn simd_eq(self, other: Self) -> Self::Mask { - // Safety: `self` is a vector, and the result of the comparison - // is always a valid mask. - unsafe { Self::from_simd_unchecked(core::intrinsics::simd::simd_eq(self.to_simd(), other.to_simd())) } - } - - #[inline] - fn simd_ne(self, other: Self) -> Self::Mask { - // Safety: `self` is a vector, and the result of the comparison - // is always a valid mask. - unsafe { Self::from_simd_unchecked(core::intrinsics::simd::simd_ne(self.to_simd(), other.to_simd())) } - } - } - )* - } -} - -impl_mask! { i8, i16, i32, i64, isize } - -impl SimdPartialEq for Simd<*const T, N> { - type Mask = Mask; - +impl SimdPartialEq for *const T { #[inline] - fn simd_eq(self, other: Self) -> Self::Mask { + fn simd_eq(self: Simd, other: Simd) -> Mask { self.addr().simd_eq(other.addr()) } #[inline] - fn simd_ne(self, other: Self) -> Self::Mask { + fn simd_ne(self: Simd, other: Simd) -> Mask { self.addr().simd_ne(other.addr()) } } -impl SimdPartialEq for Simd<*mut T, N> { - type Mask = Mask; - +impl SimdPartialEq for *mut T { #[inline] - fn simd_eq(self, other: Self) -> Self::Mask { + fn simd_eq(self: Simd, other: Simd) -> Mask { self.addr().simd_eq(other.addr()) } #[inline] - fn simd_ne(self, other: Self) -> Self::Mask { + fn simd_ne(self: Simd, other: Simd) -> Mask { self.addr().simd_ne(other.addr()) } } diff --git a/crates/core_simd/src/simd/cmp/ord.rs b/crates/core_simd/src/simd/cmp/ord.rs index 5a4e74c753b..a6f718b8f6e 100644 --- a/crates/core_simd/src/simd/cmp/ord.rs +++ b/crates/core_simd/src/simd/cmp/ord.rs @@ -1,5 +1,5 @@ use crate::simd::{ - Mask, Select, Simd, + Mask, Select, Simd, SimdElement, cmp::SimdPartialEq, ptr::{SimdConstPtr, SimdMutPtr}, }; @@ -8,30 +8,42 @@ use crate::simd::{ pub trait SimdPartialOrd: SimdPartialEq { /// Test if each element is less than the corresponding element in `other`. #[must_use = "method returns a new mask and does not mutate the original value"] - fn simd_lt(self, other: Self) -> Self::Mask; + fn simd_lt( + self: Simd, + other: Simd, + ) -> Mask<::Mask, N>; /// Test if each element is less than or equal to the corresponding element in `other`. #[must_use = "method returns a new mask and does not mutate the original value"] - fn simd_le(self, other: Self) -> Self::Mask; + fn simd_le( + self: Simd, + other: Simd, + ) -> Mask<::Mask, N>; /// Test if each element is greater than the corresponding element in `other`. #[must_use = "method returns a new mask and does not mutate the original value"] - fn simd_gt(self, other: Self) -> Self::Mask; + fn simd_gt( + self: Simd, + other: Simd, + ) -> Mask<::Mask, N>; /// Test if each element is greater than or equal to the corresponding element in `other`. #[must_use = "method returns a new mask and does not mutate the original value"] - fn simd_ge(self, other: Self) -> Self::Mask; + fn simd_ge( + self: Simd, + other: Simd, + ) -> Mask<::Mask, N>; } /// Parallel `Ord`. pub trait SimdOrd: SimdPartialOrd { /// Returns the element-wise maximum with `other`. #[must_use = "method returns a new vector and does not mutate the original value"] - fn simd_max(self, other: Self) -> Self; + fn simd_max(self: Simd, other: Simd) -> Simd; /// Returns the element-wise minimum with `other`. #[must_use = "method returns a new vector and does not mutate the original value"] - fn simd_min(self, other: Self) -> Self; + fn simd_min(self: Simd, other: Simd) -> Simd; /// Restrict each element to a certain interval. /// @@ -42,58 +54,76 @@ pub trait SimdOrd: SimdPartialOrd { /// /// Panics if `min > max` on any element. #[must_use = "method returns a new vector and does not mutate the original value"] - fn simd_clamp(self, min: Self, max: Self) -> Self; + fn simd_clamp( + self: Simd, + min: Simd, + max: Simd, + ) -> Simd; } macro_rules! impl_integer { { $($integer:ty),* } => { $( - impl SimdPartialOrd for Simd<$integer, N> - { + impl SimdPartialOrd for $integer { #[inline] - fn simd_lt(self, other: Self) -> Self::Mask { + fn simd_lt( + self: Simd, + other: Simd, + ) -> Mask<::Mask, N> { // Safety: `self` is a vector, and the result of the comparison // is always a valid mask. unsafe { Mask::from_simd_unchecked(core::intrinsics::simd::simd_lt(self, other)) } } #[inline] - fn simd_le(self, other: Self) -> Self::Mask { + fn simd_le( + self: Simd, + other: Simd, + ) -> Mask<::Mask, N> { // Safety: `self` is a vector, and the result of the comparison // is always a valid mask. unsafe { Mask::from_simd_unchecked(core::intrinsics::simd::simd_le(self, other)) } } #[inline] - fn simd_gt(self, other: Self) -> Self::Mask { + fn simd_gt( + self: Simd, + other: Simd, + ) -> Mask<::Mask, N> { // Safety: `self` is a vector, and the result of the comparison // is always a valid mask. unsafe { Mask::from_simd_unchecked(core::intrinsics::simd::simd_gt(self, other)) } } #[inline] - fn simd_ge(self, other: Self) -> Self::Mask { + fn simd_ge( + self: Simd, + other: Simd, + ) -> Mask<::Mask, N> { // Safety: `self` is a vector, and the result of the comparison // is always a valid mask. unsafe { Mask::from_simd_unchecked(core::intrinsics::simd::simd_ge(self, other)) } } } - impl SimdOrd for Simd<$integer, N> - { + impl SimdOrd for $integer { #[inline] - fn simd_max(self, other: Self) -> Self { + fn simd_max(self: Simd, other: Simd) -> Simd { self.simd_lt(other).select(other, self) } #[inline] - fn simd_min(self, other: Self) -> Self { + fn simd_min(self: Simd, other: Simd) -> Simd { self.simd_gt(other).select(other, self) } #[inline] #[track_caller] - fn simd_clamp(self, min: Self, max: Self) -> Self { + fn simd_clamp( + self: Simd, + min: Simd, + max: Simd, + ) -> Simd { assert!( min.simd_le(max).all(), "each element in `min` must be less than or equal to the corresponding element in `max`", @@ -110,31 +140,42 @@ impl_integer! { u8, u16, u32, u64, usize, i8, i16, i32, i64, isize } macro_rules! impl_float { { $($float:ty),* } => { $( - impl SimdPartialOrd for Simd<$float, N> - { + impl SimdPartialOrd for $float { #[inline] - fn simd_lt(self, other: Self) -> Self::Mask { + fn simd_lt( + self: Simd, + other: Simd, + ) -> Mask<::Mask, N> { // Safety: `self` is a vector, and the result of the comparison // is always a valid mask. unsafe { Mask::from_simd_unchecked(core::intrinsics::simd::simd_lt(self, other)) } } #[inline] - fn simd_le(self, other: Self) -> Self::Mask { + fn simd_le( + self: Simd, + other: Simd, + ) -> Mask<::Mask, N> { // Safety: `self` is a vector, and the result of the comparison // is always a valid mask. unsafe { Mask::from_simd_unchecked(core::intrinsics::simd::simd_le(self, other)) } } #[inline] - fn simd_gt(self, other: Self) -> Self::Mask { + fn simd_gt( + self: Simd, + other: Simd, + ) -> Mask<::Mask, N> { // Safety: `self` is a vector, and the result of the comparison // is always a valid mask. unsafe { Mask::from_simd_unchecked(core::intrinsics::simd::simd_gt(self, other)) } } #[inline] - fn simd_ge(self, other: Self) -> Self::Mask { + fn simd_ge( + self: Simd, + other: Simd, + ) -> Mask<::Mask, N> { // Safety: `self` is a vector, and the result of the comparison // is always a valid mask. unsafe { Mask::from_simd_unchecked(core::intrinsics::simd::simd_ge(self, other)) } @@ -146,104 +187,46 @@ macro_rules! impl_float { impl_float! { f16, f32, f64 } -macro_rules! impl_mask { - { $($integer:ty),* } => { - $( - impl SimdPartialOrd for Mask<$integer, N> - { - #[inline] - fn simd_lt(self, other: Self) -> Self::Mask { - // Safety: `self` is a vector, and the result of the comparison - // is always a valid mask. - unsafe { Self::from_simd_unchecked(core::intrinsics::simd::simd_lt(self.to_simd(), other.to_simd())) } - } - - #[inline] - fn simd_le(self, other: Self) -> Self::Mask { - // Safety: `self` is a vector, and the result of the comparison - // is always a valid mask. - unsafe { Self::from_simd_unchecked(core::intrinsics::simd::simd_le(self.to_simd(), other.to_simd())) } - } - - #[inline] - fn simd_gt(self, other: Self) -> Self::Mask { - // Safety: `self` is a vector, and the result of the comparison - // is always a valid mask. - unsafe { Self::from_simd_unchecked(core::intrinsics::simd::simd_gt(self.to_simd(), other.to_simd())) } - } - - #[inline] - fn simd_ge(self, other: Self) -> Self::Mask { - // Safety: `self` is a vector, and the result of the comparison - // is always a valid mask. - unsafe { Self::from_simd_unchecked(core::intrinsics::simd::simd_ge(self.to_simd(), other.to_simd())) } - } - } - - impl SimdOrd for Mask<$integer, N> - { - #[inline] - fn simd_max(self, other: Self) -> Self { - self.simd_gt(other).select(other, self) - } - - #[inline] - fn simd_min(self, other: Self) -> Self { - self.simd_lt(other).select(other, self) - } - - #[inline] - #[track_caller] - fn simd_clamp(self, min: Self, max: Self) -> Self { - assert!( - min.simd_le(max).all(), - "each element in `min` must be less than or equal to the corresponding element in `max`", - ); - self.simd_max(min).simd_min(max) - } - } - )* - } -} - -impl_mask! { i8, i16, i32, i64, isize } - -impl SimdPartialOrd for Simd<*const T, N> { +impl SimdPartialOrd for *const T { #[inline] - fn simd_lt(self, other: Self) -> Self::Mask { + fn simd_lt(self: Simd, other: Simd) -> Mask { self.addr().simd_lt(other.addr()) } #[inline] - fn simd_le(self, other: Self) -> Self::Mask { + fn simd_le(self: Simd, other: Simd) -> Mask { self.addr().simd_le(other.addr()) } #[inline] - fn simd_gt(self, other: Self) -> Self::Mask { + fn simd_gt(self: Simd, other: Simd) -> Mask { self.addr().simd_gt(other.addr()) } #[inline] - fn simd_ge(self, other: Self) -> Self::Mask { + fn simd_ge(self: Simd, other: Simd) -> Mask { self.addr().simd_ge(other.addr()) } } -impl SimdOrd for Simd<*const T, N> { +impl SimdOrd for *const T { #[inline] - fn simd_max(self, other: Self) -> Self { + fn simd_max(self: Simd, other: Simd) -> Simd { self.simd_lt(other).select(other, self) } #[inline] - fn simd_min(self, other: Self) -> Self { + fn simd_min(self: Simd, other: Simd) -> Simd { self.simd_gt(other).select(other, self) } #[inline] #[track_caller] - fn simd_clamp(self, min: Self, max: Self) -> Self { + fn simd_clamp( + self: Simd, + min: Simd, + max: Simd, + ) -> Simd { assert!( min.simd_le(max).all(), "each element in `min` must be less than or equal to the corresponding element in `max`", @@ -252,42 +235,46 @@ impl SimdOrd for Simd<*const T, N> { } } -impl SimdPartialOrd for Simd<*mut T, N> { +impl SimdPartialOrd for *mut T { #[inline] - fn simd_lt(self, other: Self) -> Self::Mask { + fn simd_lt(self: Simd, other: Simd) -> Mask { self.addr().simd_lt(other.addr()) } #[inline] - fn simd_le(self, other: Self) -> Self::Mask { + fn simd_le(self: Simd, other: Simd) -> Mask { self.addr().simd_le(other.addr()) } #[inline] - fn simd_gt(self, other: Self) -> Self::Mask { + fn simd_gt(self: Simd, other: Simd) -> Mask { self.addr().simd_gt(other.addr()) } #[inline] - fn simd_ge(self, other: Self) -> Self::Mask { + fn simd_ge(self: Simd, other: Simd) -> Mask { self.addr().simd_ge(other.addr()) } } -impl SimdOrd for Simd<*mut T, N> { +impl SimdOrd for *mut T { #[inline] - fn simd_max(self, other: Self) -> Self { + fn simd_max(self: Simd, other: Simd) -> Simd { self.simd_lt(other).select(other, self) } #[inline] - fn simd_min(self, other: Self) -> Self { + fn simd_min(self: Simd, other: Simd) -> Simd { self.simd_gt(other).select(other, self) } #[inline] #[track_caller] - fn simd_clamp(self, min: Self, max: Self) -> Self { + fn simd_clamp( + self: Simd, + min: Simd, + max: Simd, + ) -> Simd { assert!( min.simd_le(max).all(), "each element in `min` must be less than or equal to the corresponding element in `max`", diff --git a/crates/core_simd/src/simd/num/float.rs b/crates/core_simd/src/simd/num/float.rs index 14a31b52787..f1f62d4586e 100644 --- a/crates/core_simd/src/simd/num/float.rs +++ b/crates/core_simd/src/simd/num/float.rs @@ -5,19 +5,9 @@ use crate::simd::{ }; /// Operations on SIMD vectors of floats. -pub trait SimdFloat: Copy + Sealed { - /// Mask type used for manipulating this SIMD vector type. - type Mask; - - /// Scalar type contained by this SIMD vector type. - type Scalar; - +pub trait SimdFloat: SimdElement + Copy + Sealed { /// Bit representation of this SIMD vector type. - type Bits; - - /// A SIMD vector with a different element type. - type Cast; - + type Bits: SimdElement; /// Performs elementwise conversion of this vector's elements to another SIMD-valid type. /// /// This follows the semantics of Rust's `as` conversion for floats (truncating or saturating @@ -30,7 +20,7 @@ pub trait SimdFloat: Copy + Sealed { /// # #[cfg(not(feature = "as_crate"))] use core::simd; /// # use simd::prelude::*; /// let floats: Simd = Simd::from_array([1.9, -4.5, f32::INFINITY, f32::NAN]); - /// let ints = floats.cast::(); + /// let ints = floats.cast::(); /// assert_eq!(ints, Simd::from_array([1, -4, i32::MAX, 0])); /// /// // Formally equivalent, but `Simd::cast` can optimize better. @@ -42,7 +32,7 @@ pub trait SimdFloat: Copy + Sealed { /// assert_eq!(floats_again, Simd::from_array([1.0, -4.0, 2147483647.0, 0.0])); /// ``` #[must_use] - fn cast(self) -> Self::Cast; + fn cast(self: Simd) -> Simd; /// Rounds toward zero and converts to the same-width integer type, assuming that /// the value is finite and fits in that type. @@ -57,68 +47,72 @@ pub trait SimdFloat: Copy + Sealed { /// If these requirements are infeasible or costly, consider using the safe function [cast], /// which saturates on conversion. /// - /// [cast]: Simd::cast - unsafe fn to_int_unchecked(self) -> Self::Cast + /// [cast]: SimdFloat::cast + unsafe fn to_int_unchecked(self: Simd) -> Simd where - Self::Scalar: core::convert::FloatToInt; + Self: core::convert::FloatToInt; /// Raw transmutation to an unsigned integer vector type with the /// same size and number of elements. #[must_use = "method returns a new vector and does not mutate the original value"] - fn to_bits(self) -> Self::Bits; + fn to_bits(self: Simd) -> Simd; /// Raw transmutation from an unsigned integer vector type with the /// same size and number of elements. #[must_use = "method returns a new vector and does not mutate the original value"] - fn from_bits(bits: Self::Bits) -> Self; + fn simd_from_bits(bits: Simd) -> Simd; /// Produces a vector where every element has the absolute value of the /// equivalently-indexed element in `self`. #[must_use = "method returns a new vector and does not mutate the original value"] - fn abs(self) -> Self; + fn abs(self: Simd) -> Simd; /// Takes the reciprocal (inverse) of each element, `1/x`. #[must_use = "method returns a new vector and does not mutate the original value"] - fn recip(self) -> Self; + fn recip(self: Simd) -> Simd; /// Converts each element from radians to degrees. #[must_use = "method returns a new vector and does not mutate the original value"] - fn to_degrees(self) -> Self; + fn to_degrees(self: Simd) -> Simd; /// Converts each element from degrees to radians. #[must_use = "method returns a new vector and does not mutate the original value"] - fn to_radians(self) -> Self; + fn to_radians(self: Simd) -> Simd; /// Returns true for each element if it has a positive sign, including /// `+0.0`, `NaN`s with positive sign bit and positive infinity. #[must_use = "method returns a new mask and does not mutate the original value"] - fn is_sign_positive(self) -> Self::Mask; + fn is_sign_positive( + self: Simd, + ) -> Mask<::Mask, N>; /// Returns true for each element if it has a negative sign, including /// `-0.0`, `NaN`s with negative sign bit and negative infinity. #[must_use = "method returns a new mask and does not mutate the original value"] - fn is_sign_negative(self) -> Self::Mask; + fn is_sign_negative( + self: Simd, + ) -> Mask<::Mask, N>; /// Returns true for each element if its value is `NaN`. #[must_use = "method returns a new mask and does not mutate the original value"] - fn is_nan(self) -> Self::Mask; + fn is_nan(self: Simd) -> Mask<::Mask, N>; /// Returns true for each element if its value is positive infinity or negative infinity. #[must_use = "method returns a new mask and does not mutate the original value"] - fn is_infinite(self) -> Self::Mask; + fn is_infinite(self: Simd) -> Mask<::Mask, N>; /// Returns true for each element if its value is neither infinite nor `NaN`. #[must_use = "method returns a new mask and does not mutate the original value"] - fn is_finite(self) -> Self::Mask; + fn is_finite(self: Simd) -> Mask<::Mask, N>; /// Returns true for each element if its value is subnormal. #[must_use = "method returns a new mask and does not mutate the original value"] - fn is_subnormal(self) -> Self::Mask; + fn is_subnormal(self: Simd) -> Mask<::Mask, N>; /// Returns true for each element if its value is neither zero, infinite, /// subnormal, nor `NaN`. #[must_use = "method returns a new mask and does not mutate the original value"] - fn is_normal(self) -> Self::Mask; + fn is_normal(self: Simd) -> Mask<::Mask, N>; /// Replaces each element with a number that represents its sign. /// @@ -126,25 +120,25 @@ pub trait SimdFloat: Copy + Sealed { /// * `-1.0` if the number is negative, `-0.0`, or `NEG_INFINITY` /// * `NAN` if the number is `NAN` #[must_use = "method returns a new vector and does not mutate the original value"] - fn signum(self) -> Self; + fn signum(self: Simd) -> Simd; /// Returns each element with the magnitude of `self` and the sign of `sign`. /// /// For any element containing a `NAN`, a `NAN` with the sign of `sign` is returned. #[must_use = "method returns a new vector and does not mutate the original value"] - fn copysign(self, sign: Self) -> Self; + fn copysign(self: Simd, sign: Simd) -> Simd; /// Returns the minimum of each element. /// /// If one of the values is `NAN`, then the other value is returned. #[must_use = "method returns a new vector and does not mutate the original value"] - fn simd_min(self, other: Self) -> Self; + fn simd_min(self: Simd, other: Simd) -> Simd; /// Returns the maximum of each element. /// /// If one of the values is `NAN`, then the other value is returned. #[must_use = "method returns a new vector and does not mutate the original value"] - fn simd_max(self, other: Self) -> Self; + fn simd_max(self: Simd, other: Simd) -> Simd; /// Restrict each element to a certain interval unless it is NaN. /// @@ -152,7 +146,11 @@ pub trait SimdFloat: Copy + Sealed { /// greater than `max`, and the corresponding element in `min` if the element is less /// than `min`. Otherwise returns the element in `self`. #[must_use = "method returns a new vector and does not mutate the original value"] - fn simd_clamp(self, min: Self, max: Self) -> Self; + fn simd_clamp( + self: Simd, + min: Simd, + max: Simd, + ) -> Simd; /// Returns the sum of the elements of the vector. /// @@ -166,7 +164,7 @@ pub trait SimdFloat: Copy + Sealed { /// let v = f32x2::from_array([1., 2.]); /// assert_eq!(v.reduce_sum(), 3.); /// ``` - fn reduce_sum(self) -> Self::Scalar; + fn reduce_sum(self: Simd) -> Self; /// Reducing multiply. Returns the product of the elements of the vector. /// @@ -180,7 +178,7 @@ pub trait SimdFloat: Copy + Sealed { /// let v = f32x2::from_array([3., 4.]); /// assert_eq!(v.reduce_product(), 12.); /// ``` - fn reduce_product(self) -> Self::Scalar; + fn reduce_product(self: Simd) -> Self; /// Returns the maximum element in the vector. /// @@ -207,7 +205,7 @@ pub trait SimdFloat: Copy + Sealed { /// let v = f32x2::from_array([f32::NAN, f32::NAN]); /// assert!(v.reduce_max().is_nan()); /// ``` - fn reduce_max(self) -> Self::Scalar; + fn reduce_max(self: Simd) -> Self; /// Returns the minimum element in the vector. /// @@ -234,168 +232,138 @@ pub trait SimdFloat: Copy + Sealed { /// let v = f32x2::from_array([f32::NAN, f32::NAN]); /// assert!(v.reduce_min().is_nan()); /// ``` - fn reduce_min(self) -> Self::Scalar; + fn reduce_min(self: Simd) -> Self; } macro_rules! impl_trait { { $($ty:ty { bits: $bits_ty:ty, mask: $mask_ty:ty }),* } => { $( - impl Sealed for Simd<$ty, N> {} + impl Sealed for $ty {} - impl SimdFloat for Simd<$ty, N> - { - type Mask = Mask<<$mask_ty as SimdElement>::Mask, N>; - type Scalar = $ty; - type Bits = Simd<$bits_ty, N>; - type Cast = Simd; + impl SimdFloat for $ty { + type Bits = $bits_ty; - #[cfg(not(target_arch = "aarch64"))] #[inline] - fn cast(self) -> Self::Cast - { + fn cast(self: Simd) -> Simd { // Safety: supported types are guaranteed by SimdCast unsafe { core::intrinsics::simd::simd_as(self) } } - // workaround for https://github.com/llvm/llvm-project/issues/94694 (fixed in LLVM 20) - // tracked in: https://github.com/rust-lang/rust/issues/135982 - #[cfg(target_arch = "aarch64")] - #[inline] - fn cast(self) -> Self::Cast - { - const { assert!(N <= 64) }; - if N <= 2 || N == 4 || N == 8 || N == 16 || N == 32 || N == 64 { - // Safety: supported types are guaranteed by SimdCast - unsafe { core::intrinsics::simd::simd_as(self) } - } else if N < 4 { - let x = self.resize::<4>(Default::default()).cast(); - x.resize::(x[0]) - } else if N < 8 { - let x = self.resize::<8>(Default::default()).cast(); - x.resize::(x[0]) - } else if N < 16 { - let x = self.resize::<16>(Default::default()).cast(); - x.resize::(x[0]) - } else if N < 32 { - let x = self.resize::<32>(Default::default()).cast(); - x.resize::(x[0]) - } else { - let x = self.resize::<64>(Default::default()).cast(); - x.resize::(x[0]) - } - } - #[inline] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - unsafe fn to_int_unchecked(self) -> Self::Cast + unsafe fn to_int_unchecked(self: Simd) -> Simd where - Self::Scalar: core::convert::FloatToInt, + Self: core::convert::FloatToInt, { // Safety: supported types are guaranteed by SimdCast, the caller is responsible for the extra invariants unsafe { core::intrinsics::simd::simd_cast(self) } } #[inline] - fn to_bits(self) -> Simd<$bits_ty, N> { - assert_eq!(size_of::(), size_of::()); + fn to_bits(self: Simd) -> Simd { + assert_eq!(size_of::>(), size_of::>()); // Safety: transmuting between vector types is safe unsafe { core::mem::transmute_copy(&self) } } #[inline] - fn from_bits(bits: Simd<$bits_ty, N>) -> Self { - assert_eq!(size_of::(), size_of::()); + fn simd_from_bits(bits: Simd) -> Simd { + assert_eq!(size_of::>(), size_of::>()); // Safety: transmuting between vector types is safe unsafe { core::mem::transmute_copy(&bits) } } #[inline] - fn abs(self) -> Self { + fn abs(self: Simd) -> Simd { // Safety: `self` is a float vector unsafe { core::intrinsics::simd::simd_fabs(self) } } #[inline] - fn recip(self) -> Self { - Self::splat(1.0) / self + fn recip(self: Simd) -> Simd { + Simd::splat(1.0) / self } #[inline] - fn to_degrees(self) -> Self { + fn to_degrees(self: Simd) -> Simd { // to_degrees uses a special constant for better precision, so extract that constant - self * Self::splat(Self::Scalar::to_degrees(1.)) + self * Simd::splat(<$ty>::to_degrees(1.)) } #[inline] - fn to_radians(self) -> Self { - self * Self::splat(Self::Scalar::to_radians(1.)) + fn to_radians(self: Simd) -> Simd { + self * Simd::splat(<$ty>::to_radians(1.)) } #[inline] - fn is_sign_positive(self) -> Self::Mask { + fn is_sign_positive(self: Simd) -> Mask<::Mask, N> { !self.is_sign_negative() } #[inline] - fn is_sign_negative(self) -> Self::Mask { + fn is_sign_negative(self: Simd) -> Mask<::Mask, N> { let sign_bits = self.to_bits() & Simd::splat((!0 >> 1) + 1); sign_bits.simd_gt(Simd::splat(0)) } #[inline] - fn is_nan(self) -> Self::Mask { + fn is_nan(self: Simd) -> Mask<::Mask, N> { self.simd_ne(self) } #[inline] - fn is_infinite(self) -> Self::Mask { - self.abs().simd_eq(Self::splat(Self::Scalar::INFINITY)) + fn is_infinite(self: Simd) -> Mask<::Mask, N> { + self.abs().simd_eq(Simd::splat(<$ty>::INFINITY)) } #[inline] - fn is_finite(self) -> Self::Mask { - self.abs().simd_lt(Self::splat(Self::Scalar::INFINITY)) + fn is_finite(self: Simd) -> Mask<::Mask, N> { + self.abs().simd_lt(Simd::splat(<$ty>::INFINITY)) } #[inline] - fn is_subnormal(self) -> Self::Mask { + fn is_subnormal(self: Simd) -> Mask<::Mask, N> { // On some architectures (e.g. armv7 and some ppc) subnormals are flushed to zero, // so this comparison must be done with integers. - let not_zero = self.abs().to_bits().simd_ne(Self::splat(0.0).to_bits()); - not_zero & (self.to_bits() & Self::splat(Self::Scalar::INFINITY).to_bits()).simd_eq(Simd::splat(0)) + let not_zero = self.abs().to_bits().simd_ne(Simd::splat(0.0 as $ty).to_bits()); + not_zero & (self.to_bits() & Simd::splat(<$ty>::INFINITY).to_bits()).simd_eq(Simd::splat(0)) } #[inline] - fn is_normal(self) -> Self::Mask { - !(self.abs().simd_eq(Self::splat(0.0)) | self.is_nan() | self.is_subnormal() | self.is_infinite()) + fn is_normal(self: Simd) -> Mask<::Mask, N> { + !(self.abs().simd_eq(Simd::splat(0.0)) | self.is_nan() | self.is_subnormal() | self.is_infinite()) } #[inline] - fn signum(self) -> Self { - self.is_nan().select(Self::splat(Self::Scalar::NAN), Self::splat(1.0).copysign(self)) + fn signum(self: Simd) -> Simd { + self.is_nan().select(Simd::splat(<$ty>::NAN), Simd::splat(1.0).copysign(self)) } #[inline] - fn copysign(self, sign: Self) -> Self { - let sign_bit = sign.to_bits() & Self::splat(-0.).to_bits(); - let magnitude = self.to_bits() & !Self::splat(-0.).to_bits(); - Self::from_bits(sign_bit | magnitude) + fn copysign(self: Simd, sign: Simd) -> Simd { + let sign_bit = sign.to_bits() & Simd::splat(-0. as $ty).to_bits(); + let magnitude = self.to_bits() & !Simd::splat(-0. as $ty).to_bits(); + Self::simd_from_bits(sign_bit | magnitude) } #[inline] - fn simd_min(self, other: Self) -> Self { + fn simd_min(self: Simd, other: Simd) -> Simd { // Safety: `self` and `other` are float vectors unsafe { core::intrinsics::simd::simd_minimum_number_nsz(self, other) } } #[inline] - fn simd_max(self, other: Self) -> Self { + fn simd_max(self: Simd, other: Simd) -> Simd { // Safety: `self` and `other` are floating point vectors unsafe { core::intrinsics::simd::simd_maximum_number_nsz(self, other) } } #[inline] - fn simd_clamp(self, min: Self, max: Self) -> Self { + fn simd_clamp( + self: Simd, + min: Simd, + max: Simd, + ) -> Simd { assert!( min.simd_le(max).all(), "each element in `min` must be less than or equal to the corresponding element in `max`", @@ -407,7 +375,7 @@ macro_rules! impl_trait { } #[inline] - fn reduce_sum(self) -> Self::Scalar { + fn reduce_sum(self: Simd) -> Self { // LLVM sum is inaccurate on i586 if cfg!(all(target_arch = "x86", not(target_feature = "sse2"))) { self.as_array().iter().sum() @@ -418,7 +386,7 @@ macro_rules! impl_trait { } #[inline] - fn reduce_product(self) -> Self::Scalar { + fn reduce_product(self: Simd) -> Self { // LLVM product is inaccurate on i586 if cfg!(all(target_arch = "x86", not(target_feature = "sse2"))) { self.as_array().iter().product() @@ -429,15 +397,15 @@ macro_rules! impl_trait { } #[inline] - fn reduce_max(self) -> Self::Scalar { + fn reduce_max(self: Simd) -> Self { // LLVM has no intrinsic we can use here // (https://github.com/llvm/llvm-project/issues/185827). - self.as_array().iter().copied().fold(Self::Scalar::NAN, Self::Scalar::max) + self.as_array().iter().copied().fold(<$ty>::NAN, <$ty>::max) } #[inline] - fn reduce_min(self) -> Self::Scalar { - self.as_array().iter().copied().fold(Self::Scalar::NAN, Self::Scalar::min) + fn reduce_min(self: Simd) -> Self { + self.as_array().iter().copied().fold(<$ty>::NAN, <$ty>::min) } } )* diff --git a/crates/core_simd/src/simd/num/int.rs b/crates/core_simd/src/simd/num/int.rs index eee54d39688..33552a9ba57 100644 --- a/crates/core_simd/src/simd/num/int.rs +++ b/crates/core_simd/src/simd/num/int.rs @@ -4,25 +4,16 @@ use crate::simd::{ }; /// Operations on SIMD vectors of signed integers. -pub trait SimdInt: Copy + Sealed { - /// Mask type used for manipulating this SIMD vector type. - type Mask; - - /// Scalar type contained by this SIMD vector type. - type Scalar; - - /// A SIMD vector of unsigned integers with the same element size. - type Unsigned; - - /// A SIMD vector with a different element type. - type Cast; +pub trait SimdInt: SimdElement + Copy + Sealed { + /// Unsigned element type with the same width as `T`. + type Unsigned: SimdElement; /// Performs elementwise conversion of this vector's elements to another SIMD-valid type. /// /// This follows the semantics of Rust's `as` conversion for casting integers (wrapping to /// other integer types, and saturating to float types). #[must_use] - fn cast(self) -> Self::Cast; + fn cast(self: Simd) -> Simd; /// Lanewise saturating add. /// @@ -40,7 +31,7 @@ pub trait SimdInt: Copy + Sealed { /// assert_eq!(unsat, Simd::from_array([-1, MAX, MIN, -2])); /// assert_eq!(sat, Simd::from_array([-1, MAX, MAX, MAX])); /// ``` - fn saturating_add(self, second: Self) -> Self; + fn saturating_add(self: Simd, second: Simd) -> Simd; /// Lanewise saturating subtract. /// @@ -58,7 +49,7 @@ pub trait SimdInt: Copy + Sealed { /// assert_eq!(unsat, Simd::from_array([1, MAX, MIN, 0])); /// assert_eq!(sat, Simd::from_array([MIN, MIN, MIN, 0])); /// ``` - fn saturating_sub(self, second: Self) -> Self; + fn saturating_sub(self: Simd, second: Simd) -> Simd; /// Lanewise absolute value, implemented in Rust. /// Every element becomes its absolute value. @@ -73,7 +64,7 @@ pub trait SimdInt: Copy + Sealed { /// let xs = Simd::from_array([MIN, MIN + 1, -5, 0]); /// assert_eq!(xs.abs(), Simd::from_array([MIN, MAX, 5, 0])); /// ``` - fn abs(self) -> Self; + fn abs(self: Simd) -> Simd; /// Lanewise absolute difference. /// Every element becomes the absolute difference of `self` and `second`. @@ -89,7 +80,10 @@ pub trait SimdInt: Copy + Sealed { /// let b = Simd::from_array([MAX, MIN, -80, -120]); /// assert_eq!(a.abs_diff(b), Simd::from_array([u32::MAX, u32::MAX, 180, 20])); /// ``` - fn abs_diff(self, second: Self) -> Self::Unsigned; + fn abs_diff( + self: Simd, + second: Simd, + ) -> Simd; /// Lanewise saturating absolute value, implemented in Rust. /// As abs(), except the MIN value becomes MAX instead of itself. @@ -107,7 +101,7 @@ pub trait SimdInt: Copy + Sealed { /// assert_eq!(unsat, Simd::from_array([MIN, 2, 0, 3])); /// assert_eq!(sat, Simd::from_array([MAX, 2, 0, 3])); /// ``` - fn saturating_abs(self) -> Self; + fn saturating_abs(self: Simd) -> Simd; /// Lanewise saturating negation, implemented in Rust. /// As neg(), except the MIN value becomes MAX instead of itself. @@ -125,19 +119,19 @@ pub trait SimdInt: Copy + Sealed { /// assert_eq!(unsat, Simd::from_array([MIN, 2, -3, MIN + 1])); /// assert_eq!(sat, Simd::from_array([MAX, 2, -3, MIN + 1])); /// ``` - fn saturating_neg(self) -> Self; + fn saturating_neg(self: Simd) -> Simd; /// Returns true for each positive element and false if it is zero or negative. - fn is_positive(self) -> Self::Mask; + fn is_positive(self: Simd) -> Mask<::Mask, N>; /// Returns true for each negative element and false if it is zero or positive. - fn is_negative(self) -> Self::Mask; + fn is_negative(self: Simd) -> Mask<::Mask, N>; /// Returns numbers representing the sign of each element. /// * `0` if the number is zero /// * `1` if the number is positive /// * `-1` if the number is negative - fn signum(self) -> Self; + fn signum(self: Simd) -> Simd; /// Returns the sum of the elements of the vector, with wrapping addition. /// @@ -155,7 +149,7 @@ pub trait SimdInt: Copy + Sealed { /// let v = i32x4::from_array([i32::MAX, 1, 0, 0]); /// assert_eq!(v.reduce_sum(), i32::MIN); /// ``` - fn reduce_sum(self) -> Self::Scalar; + fn reduce_sum(self: Simd) -> Self; /// Returns the product of the elements of the vector, with wrapping multiplication. /// @@ -173,7 +167,7 @@ pub trait SimdInt: Copy + Sealed { /// let v = i32x4::from_array([i32::MAX, 2, 1, 1]); /// assert!(v.reduce_product() < i32::MAX); /// ``` - fn reduce_product(self) -> Self::Scalar; + fn reduce_product(self: Simd) -> Self; /// Returns the maximum element in the vector. /// @@ -187,7 +181,7 @@ pub trait SimdInt: Copy + Sealed { /// let v = i32x4::from_array([1, 2, 3, 4]); /// assert_eq!(v.reduce_max(), 4); /// ``` - fn reduce_max(self) -> Self::Scalar; + fn reduce_max(self: Simd) -> Self; /// Returns the minimum element in the vector. /// @@ -201,88 +195,94 @@ pub trait SimdInt: Copy + Sealed { /// let v = i32x4::from_array([1, 2, 3, 4]); /// assert_eq!(v.reduce_min(), 1); /// ``` - fn reduce_min(self) -> Self::Scalar; + fn reduce_min(self: Simd) -> Self; /// Returns the cumulative bitwise "and" across the elements of the vector. - fn reduce_and(self) -> Self::Scalar; + fn reduce_and(self: Simd) -> Self; /// Returns the cumulative bitwise "or" across the elements of the vector. - fn reduce_or(self) -> Self::Scalar; + fn reduce_or(self: Simd) -> Self; /// Returns the cumulative bitwise "xor" across the elements of the vector. - fn reduce_xor(self) -> Self::Scalar; + fn reduce_xor(self: Simd) -> Self; /// Reverses the byte order of each element. - fn swap_bytes(self) -> Self; + fn swap_bytes(self: Simd) -> Simd; /// Reverses the order of bits in each elemnent. /// The least significant bit becomes the most significant bit, second least-significant bit becomes second most-significant bit, etc. - fn reverse_bits(self) -> Self; + fn reverse_bits(self: Simd) -> Simd; /// Returns the number of ones in the binary representation of each element. - fn count_ones(self) -> Self::Unsigned; + fn count_ones(self: Simd) -> Simd; /// Returns the number of zeros in the binary representation of each element. - fn count_zeros(self) -> Self::Unsigned; + fn count_zeros(self: Simd) -> Simd; /// Returns the number of leading zeros in the binary representation of each element. - fn leading_zeros(self) -> Self::Unsigned; + fn leading_zeros(self: Simd) -> Simd; /// Returns the number of trailing zeros in the binary representation of each element. - fn trailing_zeros(self) -> Self::Unsigned; + fn trailing_zeros(self: Simd) -> Simd; /// Returns the number of leading ones in the binary representation of each element. - fn leading_ones(self) -> Self::Unsigned; + fn leading_ones(self: Simd) -> Simd; /// Returns the number of trailing ones in the binary representation of each element. - fn trailing_ones(self) -> Self::Unsigned; + fn trailing_ones(self: Simd) -> Simd; } macro_rules! impl_trait { { $($ty:ident ($unsigned:ident)),* } => { $( - impl Sealed for Simd<$ty, N> {} + impl Sealed for $ty {} - impl SimdInt for Simd<$ty, N> { - type Mask = Mask<<$ty as SimdElement>::Mask, N>; - type Scalar = $ty; - type Unsigned = Simd<$unsigned, N>; - type Cast = Simd; + impl SimdInt for $ty { + type Unsigned = $unsigned; #[inline] - fn cast(self) -> Self::Cast { + fn cast(self: Simd) -> Simd { // Safety: supported types are guaranteed by SimdCast unsafe { core::intrinsics::simd::simd_as(self) } } #[inline] - fn saturating_add(self, second: Self) -> Self { + fn saturating_add( + self: Simd, + second: Simd, + ) -> Simd { // Safety: `self` is a vector unsafe { core::intrinsics::simd::simd_saturating_add(self, second) } } #[inline] - fn saturating_sub(self, second: Self) -> Self { + fn saturating_sub( + self: Simd, + second: Simd, + ) -> Simd { // Safety: `self` is a vector unsafe { core::intrinsics::simd::simd_saturating_sub(self, second) } } #[inline] - fn abs(self) -> Self { + fn abs(self: Simd) -> Simd { const SHR: $ty = <$ty>::BITS as $ty - 1; let m = self >> Simd::splat(SHR); (self^m) - m } #[inline] - fn abs_diff(self, second: Self) -> Self::Unsigned { + fn abs_diff( + self: Simd, + second: Simd, + ) -> Simd { let max = self.simd_max(second); let min = self.simd_min(second); (max - min).cast() } #[inline] - fn saturating_abs(self) -> Self { + fn saturating_abs(self: Simd) -> Simd { // arith shift for -1 or 0 mask based on sign bit, giving 2s complement const SHR: $ty = <$ty>::BITS as $ty - 1; let m = self >> Simd::splat(SHR); @@ -290,110 +290,110 @@ macro_rules! impl_trait { } #[inline] - fn saturating_neg(self) -> Self { - Self::splat(0).saturating_sub(self) + fn saturating_neg(self: Simd) -> Simd { + ::saturating_sub::(Simd::splat(0), self) } #[inline] - fn is_positive(self) -> Self::Mask { - self.simd_gt(Self::splat(0)) + fn is_positive(self: Simd) -> Mask<<$ty as SimdElement>::Mask, N> { + self.simd_gt(Simd::splat(0)) } #[inline] - fn is_negative(self) -> Self::Mask { - self.simd_lt(Self::splat(0)) + fn is_negative(self: Simd) -> Mask<<$ty as SimdElement>::Mask, N> { + self.simd_lt(Simd::splat(0)) } #[inline] - fn signum(self) -> Self { + fn signum(self: Simd) -> Simd { self.is_positive().select( - Self::splat(1), - self.is_negative().select(Self::splat(-1), Self::splat(0)) + Simd::splat(1), + self.is_negative().select(Simd::splat(-1), Simd::splat(0)) ) } #[inline] - fn reduce_sum(self) -> Self::Scalar { + fn reduce_sum(self: Simd) -> Self { // Safety: `self` is an integer vector unsafe { core::intrinsics::simd::simd_reduce_add_ordered(self, 0) } } #[inline] - fn reduce_product(self) -> Self::Scalar { + fn reduce_product(self: Simd) -> Self { // Safety: `self` is an integer vector unsafe { core::intrinsics::simd::simd_reduce_mul_ordered(self, 1) } } #[inline] - fn reduce_max(self) -> Self::Scalar { + fn reduce_max(self: Simd) -> Self { // Safety: `self` is an integer vector unsafe { core::intrinsics::simd::simd_reduce_max(self) } } #[inline] - fn reduce_min(self) -> Self::Scalar { + fn reduce_min(self: Simd) -> Self { // Safety: `self` is an integer vector unsafe { core::intrinsics::simd::simd_reduce_min(self) } } #[inline] - fn reduce_and(self) -> Self::Scalar { + fn reduce_and(self: Simd) -> Self { // Safety: `self` is an integer vector unsafe { core::intrinsics::simd::simd_reduce_and(self) } } #[inline] - fn reduce_or(self) -> Self::Scalar { + fn reduce_or(self: Simd) -> Self { // Safety: `self` is an integer vector unsafe { core::intrinsics::simd::simd_reduce_or(self) } } #[inline] - fn reduce_xor(self) -> Self::Scalar { + fn reduce_xor(self: Simd) -> Self { // Safety: `self` is an integer vector unsafe { core::intrinsics::simd::simd_reduce_xor(self) } } #[inline] - fn swap_bytes(self) -> Self { + fn swap_bytes(self: Simd) -> Simd { // Safety: `self` is an integer vector unsafe { core::intrinsics::simd::simd_bswap(self) } } #[inline] - fn reverse_bits(self) -> Self { + fn reverse_bits(self: Simd) -> Simd { // Safety: `self` is an integer vector unsafe { core::intrinsics::simd::simd_bitreverse(self) } } #[inline] - fn count_ones(self) -> Self::Unsigned { - self.cast::<$unsigned>().count_ones() + fn count_ones(self: Simd) -> Simd { + self.cast::().count_ones() } #[inline] - fn count_zeros(self) -> Self::Unsigned { - self.cast::<$unsigned>().count_zeros() + fn count_zeros(self: Simd) -> Simd { + self.cast::().count_zeros() } #[inline] - fn leading_zeros(self) -> Self::Unsigned { - self.cast::<$unsigned>().leading_zeros() + fn leading_zeros(self: Simd) -> Simd { + self.cast::().leading_zeros() } #[inline] - fn trailing_zeros(self) -> Self::Unsigned { - self.cast::<$unsigned>().trailing_zeros() + fn trailing_zeros(self: Simd) -> Simd { + self.cast::().trailing_zeros() } #[inline] - fn leading_ones(self) -> Self::Unsigned { - self.cast::<$unsigned>().leading_ones() + fn leading_ones(self: Simd) -> Simd { + self.cast::().leading_ones() } #[inline] - fn trailing_ones(self) -> Self::Unsigned { - self.cast::<$unsigned>().trailing_ones() + fn trailing_ones(self: Simd) -> Simd { + self.cast::().trailing_ones() } } )* diff --git a/crates/core_simd/src/simd/num/uint.rs b/crates/core_simd/src/simd/num/uint.rs index 606107a1f06..8b05b422b13 100644 --- a/crates/core_simd/src/simd/num/uint.rs +++ b/crates/core_simd/src/simd/num/uint.rs @@ -2,25 +2,21 @@ use super::sealed::Sealed; use crate::simd::{Simd, SimdCast, SimdElement, cmp::SimdOrd}; /// Operations on SIMD vectors of unsigned integers. -pub trait SimdUint: Copy + Sealed { - /// Scalar type contained by this SIMD vector type. - type Scalar; - - /// A SIMD vector with a different element type. - type Cast; - +pub trait SimdUint: SimdElement + Copy + Sealed { + /// Signed element type with the same width as `T`. + type Signed: SimdElement; /// Performs elementwise conversion of this vector's elements to another SIMD-valid type. /// /// This follows the semantics of Rust's `as` conversion for casting integers (wrapping to /// other integer types, and saturating to float types). #[must_use] - fn cast(self) -> Self::Cast; + fn cast(self: Simd) -> Simd; /// Wrapping negation. /// /// Like [`u32::wrapping_neg`], all applications of this function will wrap, with the exception /// of `-0`. - fn wrapping_neg(self) -> Self; + fn wrapping_neg(self: Simd) -> Simd; /// Lanewise saturating add. /// @@ -38,7 +34,7 @@ pub trait SimdUint: Copy + Sealed { /// assert_eq!(unsat, Simd::from_array([1, 0, MAX, MAX - 1])); /// assert_eq!(sat, max); /// ``` - fn saturating_add(self, second: Self) -> Self; + fn saturating_add(self: Simd, second: Simd) -> Simd; /// Lanewise saturating subtract. /// @@ -56,7 +52,7 @@ pub trait SimdUint: Copy + Sealed { /// assert_eq!(unsat, Simd::from_array([3, 2, 1, 0])); /// assert_eq!(sat, Simd::splat(0)); /// ``` - fn saturating_sub(self, second: Self) -> Self; + fn saturating_sub(self: Simd, second: Simd) -> Simd; /// Lanewise absolute difference. /// Every element becomes the absolute difference of `self` and `second`. @@ -72,180 +68,187 @@ pub trait SimdUint: Copy + Sealed { /// let b = Simd::from_array([MAX, 0, 80, 200]); /// assert_eq!(a.abs_diff(b), Simd::from_array([MAX, MAX, 20, 180])); /// ``` - fn abs_diff(self, second: Self) -> Self; + fn abs_diff(self: Simd, second: Simd) -> Simd; /// Returns the sum of the elements of the vector, with wrapping addition. - fn reduce_sum(self) -> Self::Scalar; + fn reduce_sum(self: Simd) -> Self; /// Returns the product of the elements of the vector, with wrapping multiplication. - fn reduce_product(self) -> Self::Scalar; + fn reduce_product(self: Simd) -> Self; /// Returns the maximum element in the vector. - fn reduce_max(self) -> Self::Scalar; + fn reduce_max(self: Simd) -> Self; /// Returns the minimum element in the vector. - fn reduce_min(self) -> Self::Scalar; + fn reduce_min(self: Simd) -> Self; /// Returns the cumulative bitwise "and" across the elements of the vector. - fn reduce_and(self) -> Self::Scalar; + fn reduce_and(self: Simd) -> Self; /// Returns the cumulative bitwise "or" across the elements of the vector. - fn reduce_or(self) -> Self::Scalar; + fn reduce_or(self: Simd) -> Self; /// Returns the cumulative bitwise "xor" across the elements of the vector. - fn reduce_xor(self) -> Self::Scalar; + fn reduce_xor(self: Simd) -> Self; /// Reverses the byte order of each element. - fn swap_bytes(self) -> Self; + fn swap_bytes(self: Simd) -> Simd; /// Reverses the order of bits in each elemnent. /// The least significant bit becomes the most significant bit, second least-significant bit becomes second most-significant bit, etc. - fn reverse_bits(self) -> Self; + fn reverse_bits(self: Simd) -> Simd; /// Returns the number of ones in the binary representation of each element. - fn count_ones(self) -> Self; + fn count_ones(self: Simd) -> Simd; /// Returns the number of zeros in the binary representation of each element. - fn count_zeros(self) -> Self; + fn count_zeros(self: Simd) -> Simd; /// Returns the number of leading zeros in the binary representation of each element. - fn leading_zeros(self) -> Self; + fn leading_zeros(self: Simd) -> Simd; /// Returns the number of trailing zeros in the binary representation of each element. - fn trailing_zeros(self) -> Self; + fn trailing_zeros(self: Simd) -> Simd; /// Returns the number of leading ones in the binary representation of each element. - fn leading_ones(self) -> Self; + fn leading_ones(self: Simd) -> Simd; /// Returns the number of trailing ones in the binary representation of each element. - fn trailing_ones(self) -> Self; + fn trailing_ones(self: Simd) -> Simd; } macro_rules! impl_trait { { $($ty:ident ($signed:ident)),* } => { $( - impl Sealed for Simd<$ty, N> {} + impl Sealed for $ty {} - impl SimdUint for Simd<$ty, N> - { - type Scalar = $ty; - type Cast = Simd; + impl SimdUint for $ty { + type Signed = $signed; #[inline] - fn cast(self) -> Self::Cast { + fn cast(self: Simd) -> Simd { // Safety: supported types are guaranteed by SimdCast unsafe { core::intrinsics::simd::simd_as(self) } } #[inline] - fn wrapping_neg(self) -> Self { + fn wrapping_neg(self: Simd) -> Simd { use crate::simd::num::SimdInt; - (-self.cast::<$signed>()).cast() + (-self.cast::()).cast::() } #[inline] - fn saturating_add(self, second: Self) -> Self { + fn saturating_add( + self: Simd, + second: Simd, + ) -> Simd { // Safety: `self` is a vector unsafe { core::intrinsics::simd::simd_saturating_add(self, second) } } #[inline] - fn saturating_sub(self, second: Self) -> Self { + fn saturating_sub( + self: Simd, + second: Simd, + ) -> Simd { // Safety: `self` is a vector unsafe { core::intrinsics::simd::simd_saturating_sub(self, second) } } #[inline] - fn abs_diff(self, second: Self) -> Self { + fn abs_diff( + self: Simd, + second: Simd, + ) -> Simd { let max = self.simd_max(second); let min = self.simd_min(second); max - min } #[inline] - fn reduce_sum(self) -> Self::Scalar { + fn reduce_sum(self: Simd) -> Self { // Safety: `self` is an integer vector unsafe { core::intrinsics::simd::simd_reduce_add_ordered(self, 0) } } #[inline] - fn reduce_product(self) -> Self::Scalar { + fn reduce_product(self: Simd) -> Self { // Safety: `self` is an integer vector unsafe { core::intrinsics::simd::simd_reduce_mul_ordered(self, 1) } } #[inline] - fn reduce_max(self) -> Self::Scalar { + fn reduce_max(self: Simd) -> Self { // Safety: `self` is an integer vector unsafe { core::intrinsics::simd::simd_reduce_max(self) } } #[inline] - fn reduce_min(self) -> Self::Scalar { + fn reduce_min(self: Simd) -> Self { // Safety: `self` is an integer vector unsafe { core::intrinsics::simd::simd_reduce_min(self) } } #[inline] - fn reduce_and(self) -> Self::Scalar { + fn reduce_and(self: Simd) -> Self { // Safety: `self` is an integer vector unsafe { core::intrinsics::simd::simd_reduce_and(self) } } #[inline] - fn reduce_or(self) -> Self::Scalar { + fn reduce_or(self: Simd) -> Self { // Safety: `self` is an integer vector unsafe { core::intrinsics::simd::simd_reduce_or(self) } } #[inline] - fn reduce_xor(self) -> Self::Scalar { + fn reduce_xor(self: Simd) -> Self { // Safety: `self` is an integer vector unsafe { core::intrinsics::simd::simd_reduce_xor(self) } } #[inline] - fn swap_bytes(self) -> Self { + fn swap_bytes(self: Simd) -> Simd { // Safety: `self` is an integer vector unsafe { core::intrinsics::simd::simd_bswap(self) } } #[inline] - fn reverse_bits(self) -> Self { + fn reverse_bits(self: Simd) -> Simd { // Safety: `self` is an integer vector unsafe { core::intrinsics::simd::simd_bitreverse(self) } } #[inline] - fn count_ones(self) -> Self { + fn count_ones(self: Simd) -> Simd { // Safety: `self` is an integer vector unsafe { core::intrinsics::simd::simd_ctpop(self) } } #[inline] - fn count_zeros(self) -> Self { + fn count_zeros(self: Simd) -> Simd { (!self).count_ones() } #[inline] - fn leading_zeros(self) -> Self { + fn leading_zeros(self: Simd) -> Simd { // Safety: `self` is an integer vector unsafe { core::intrinsics::simd::simd_ctlz(self) } } #[inline] - fn trailing_zeros(self) -> Self { + fn trailing_zeros(self: Simd) -> Simd { // Safety: `self` is an integer vector unsafe { core::intrinsics::simd::simd_cttz(self) } } #[inline] - fn leading_ones(self) -> Self { + fn leading_ones(self: Simd) -> Simd { (!self).leading_zeros() } #[inline] - fn trailing_ones(self) -> Self { + fn trailing_ones(self: Simd) -> Simd { (!self).trailing_zeros() } } diff --git a/crates/core_simd/src/simd/ptr.rs b/crates/core_simd/src/simd/ptr.rs index a27367ceb79..57064a71ac9 100644 --- a/crates/core_simd/src/simd/ptr.rs +++ b/crates/core_simd/src/simd/ptr.rs @@ -5,6 +5,9 @@ mod mut_ptr; mod sealed { pub trait Sealed {} + + impl Sealed for *const T {} + impl Sealed for *mut T {} } pub use const_ptr::*; diff --git a/crates/core_simd/src/simd/ptr/const_ptr.rs b/crates/core_simd/src/simd/ptr/const_ptr.rs index be2b9e6b483..01e024eca7e 100644 --- a/crates/core_simd/src/simd/ptr/const_ptr.rs +++ b/crates/core_simd/src/simd/ptr/const_ptr.rs @@ -1,45 +1,33 @@ use super::sealed::Sealed; -use crate::simd::{Mask, Simd, cmp::SimdPartialEq, num::SimdUint}; +use crate::simd::{Mask, Simd, SimdElement, cmp::SimdPartialEq, num::SimdUint}; /// Operations on SIMD vectors of constant pointers. -pub trait SimdConstPtr: Copy + Sealed { - /// Vector of `usize` with the same number of elements. - type Usize; - - /// Vector of `isize` with the same number of elements. - type Isize; - - /// Vector of const pointers with the same number of elements. - type CastPtr; - - /// Vector of mutable pointers to the same type. - type MutPtr; - - /// Mask type used for manipulating this SIMD vector type. - type Mask; +pub trait SimdConstPtr: SimdElement + Copy + Sealed { + /// The pointee type referenced by these pointers. + type Pointee; /// Returns `true` for each element that is null. - fn is_null(self) -> Self::Mask; + fn is_null(self: Simd) -> Mask; /// Casts to a pointer of another type. /// /// Equivalent to calling [`pointer::cast`] on each element. - fn cast(self) -> Self::CastPtr; + fn cast(self: Simd) -> Simd<*const U, N>; /// Changes constness without changing the type. /// /// Equivalent to calling [`pointer::cast_mut`] on each element. - fn cast_mut(self) -> Self::MutPtr; + fn cast_mut(self: Simd) -> Simd<*mut Self::Pointee, N>; /// Gets the "address" portion of the pointer. /// /// Equivalent to calling [`pointer::addr`] on each element. - fn addr(self) -> Self::Usize; + fn addr(self: Simd) -> Simd; /// Creates a new pointer with the given address. /// /// Equivalent to calling [`pointer::with_addr`] on each element. - fn with_addr(self, addr: Self::Usize) -> Self; + fn with_addr(self: Simd, addr: Simd) -> Simd; /// Exposes the "provenance" part of the pointer for future use in /// [`super::with_exposed_provenance`] and returns the "address" portion. @@ -47,40 +35,37 @@ pub trait SimdConstPtr: Copy + Sealed { /// Equivalent to calling [`pointer::expose_provenance`] on each element. /// /// See [`super::with_exposed_provenance`] for the matching constructor. - fn expose_provenance(self) -> Self::Usize; + fn expose_provenance(self: Simd) -> Simd; /// Calculates the offset from a pointer using wrapping arithmetic. /// /// Equivalent to calling [`pointer::wrapping_offset`] on each element. - fn wrapping_offset(self, offset: Self::Isize) -> Self; + fn wrapping_offset( + self: Simd, + offset: Simd, + ) -> Simd; /// Calculates the offset from a pointer using wrapping arithmetic. /// /// Equivalent to calling [`pointer::wrapping_add`] on each element. - fn wrapping_add(self, count: Self::Usize) -> Self; + fn wrapping_add(self: Simd, count: Simd) -> Simd; /// Calculates the offset from a pointer using wrapping arithmetic. /// /// Equivalent to calling [`pointer::wrapping_sub`] on each element. - fn wrapping_sub(self, count: Self::Usize) -> Self; + fn wrapping_sub(self: Simd, count: Simd) -> Simd; } -impl Sealed for Simd<*const T, N> {} - -impl SimdConstPtr for Simd<*const T, N> { - type Usize = Simd; - type Isize = Simd; - type CastPtr = Simd<*const U, N>; - type MutPtr = Simd<*mut T, N>; - type Mask = Mask; +impl SimdConstPtr for *const T { + type Pointee = T; #[inline] - fn is_null(self) -> Self::Mask { - Simd::splat(core::ptr::null()).simd_eq(self) + fn is_null(self: Simd) -> Mask { + Simd::splat(core::ptr::null::()).simd_eq(self) } #[inline] - fn cast(self) -> Self::CastPtr { + fn cast(self: Simd) -> Simd<*const U, N> { // SimdElement currently requires zero-sized metadata, so this should never fail. // If this ever changes, `simd_cast_ptr` should produce a post-mono error. use core::ptr::Pointee; @@ -92,13 +77,13 @@ impl SimdConstPtr for Simd<*const T, N> { } #[inline] - fn cast_mut(self) -> Self::MutPtr { + fn cast_mut(self: Simd) -> Simd<*mut Self::Pointee, N> { // Safety: pointers can be cast unsafe { core::intrinsics::simd::simd_cast_ptr(self) } } #[inline] - fn addr(self) -> Self::Usize { + fn addr(self: Simd) -> Simd { // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic. // SAFETY: Pointer-to-integer transmutes are valid (if you are okay with losing the // provenance). @@ -106,36 +91,39 @@ impl SimdConstPtr for Simd<*const T, N> { } #[inline] - fn with_addr(self, addr: Self::Usize) -> Self { + fn with_addr(self: Simd, addr: Simd) -> Simd { // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic. // // In the mean-time, this operation is defined to be "as if" it was // a wrapping_offset, so we can emulate it as such. This should properly // restore pointer provenance even under today's compiler. - self.cast::() - .wrapping_offset(addr.cast::() - self.addr().cast::()) - .cast() + self.cast::() + .wrapping_offset(addr.cast::() - self.addr().cast::()) + .cast::() } #[inline] - fn expose_provenance(self) -> Self::Usize { + fn expose_provenance(self: Simd) -> Simd { // Safety: `self` is a pointer vector unsafe { core::intrinsics::simd::simd_expose_provenance(self) } } #[inline] - fn wrapping_offset(self, count: Self::Isize) -> Self { + fn wrapping_offset( + self: Simd, + count: Simd, + ) -> Simd { // Safety: simd_arith_offset takes a vector of pointers and a vector of offsets unsafe { core::intrinsics::simd::simd_arith_offset(self, count) } } #[inline] - fn wrapping_add(self, count: Self::Usize) -> Self { + fn wrapping_add(self: Simd, count: Simd) -> Simd { self.wrapping_offset(count.cast()) } #[inline] - fn wrapping_sub(self, count: Self::Usize) -> Self { - self.wrapping_offset(-count.cast::()) + fn wrapping_sub(self: Simd, count: Simd) -> Simd { + self.wrapping_offset(-count.cast::()) } } diff --git a/crates/core_simd/src/simd/ptr/mut_ptr.rs b/crates/core_simd/src/simd/ptr/mut_ptr.rs index 78b5bef4d97..c2f93e88638 100644 --- a/crates/core_simd/src/simd/ptr/mut_ptr.rs +++ b/crates/core_simd/src/simd/ptr/mut_ptr.rs @@ -1,45 +1,33 @@ use super::sealed::Sealed; -use crate::simd::{Mask, Simd, cmp::SimdPartialEq, num::SimdUint}; +use crate::simd::{Mask, Simd, SimdElement, cmp::SimdPartialEq, num::SimdUint}; /// Operations on SIMD vectors of mutable pointers. -pub trait SimdMutPtr: Copy + Sealed { - /// Vector of `usize` with the same number of elements. - type Usize; - - /// Vector of `isize` with the same number of elements. - type Isize; - - /// Vector of const pointers with the same number of elements. - type CastPtr; - - /// Vector of constant pointers to the same type. - type ConstPtr; - - /// Mask type used for manipulating this SIMD vector type. - type Mask; +pub trait SimdMutPtr: SimdElement + Copy + Sealed { + /// The pointee type referenced by these pointers. + type Pointee; /// Returns `true` for each element that is null. - fn is_null(self) -> Self::Mask; + fn is_null(self: Simd) -> Mask; /// Casts to a pointer of another type. /// /// Equivalent to calling [`pointer::cast`] on each element. - fn cast(self) -> Self::CastPtr; + fn cast(self: Simd) -> Simd<*mut U, N>; /// Changes constness without changing the type. /// /// Equivalent to calling [`pointer::cast_const`] on each element. - fn cast_const(self) -> Self::ConstPtr; + fn cast_const(self: Simd) -> Simd<*const Self::Pointee, N>; /// Gets the "address" portion of the pointer. /// /// Equivalent to calling [`pointer::addr`] on each element. - fn addr(self) -> Self::Usize; + fn addr(self: Simd) -> Simd; /// Creates a new pointer with the given address. /// /// Equivalent to calling [`pointer::with_addr`] on each element. - fn with_addr(self, addr: Self::Usize) -> Self; + fn with_addr(self: Simd, addr: Simd) -> Simd; /// Exposes the "provenance" part of the pointer for future use in /// [`super::with_exposed_provenance_mut`] and returns the "address" portion. @@ -47,40 +35,37 @@ pub trait SimdMutPtr: Copy + Sealed { /// Equivalent to calling [`pointer::expose_provenance`] on each element. /// /// See [`super::with_exposed_provenance_mut`] for the matching constructor. - fn expose_provenance(self) -> Self::Usize; + fn expose_provenance(self: Simd) -> Simd; /// Calculates the offset from a pointer using wrapping arithmetic. /// /// Equivalent to calling [`pointer::wrapping_offset`] on each element. - fn wrapping_offset(self, offset: Self::Isize) -> Self; + fn wrapping_offset( + self: Simd, + offset: Simd, + ) -> Simd; /// Calculates the offset from a pointer using wrapping arithmetic. /// /// Equivalent to calling [`pointer::wrapping_add`] on each element. - fn wrapping_add(self, count: Self::Usize) -> Self; + fn wrapping_add(self: Simd, count: Simd) -> Simd; /// Calculates the offset from a pointer using wrapping arithmetic. /// /// Equivalent to calling [`pointer::wrapping_sub`] on each element. - fn wrapping_sub(self, count: Self::Usize) -> Self; + fn wrapping_sub(self: Simd, count: Simd) -> Simd; } -impl Sealed for Simd<*mut T, N> {} - -impl SimdMutPtr for Simd<*mut T, N> { - type Usize = Simd; - type Isize = Simd; - type CastPtr = Simd<*mut U, N>; - type ConstPtr = Simd<*const T, N>; - type Mask = Mask; +impl SimdMutPtr for *mut T { + type Pointee = T; #[inline] - fn is_null(self) -> Self::Mask { - Simd::splat(core::ptr::null_mut()).simd_eq(self) + fn is_null(self: Simd) -> Mask { + Simd::splat(core::ptr::null_mut::()).simd_eq(self) } #[inline] - fn cast(self) -> Self::CastPtr { + fn cast(self: Simd) -> Simd<*mut U, N> { // SimdElement currently requires zero-sized metadata, so this should never fail. // If this ever changes, `simd_cast_ptr` should produce a post-mono error. use core::ptr::Pointee; @@ -92,13 +77,13 @@ impl SimdMutPtr for Simd<*mut T, N> { } #[inline] - fn cast_const(self) -> Self::ConstPtr { + fn cast_const(self: Simd) -> Simd<*const Self::Pointee, N> { // Safety: pointers can be cast unsafe { core::intrinsics::simd::simd_cast_ptr(self) } } #[inline] - fn addr(self) -> Self::Usize { + fn addr(self: Simd) -> Simd { // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic. // SAFETY: Pointer-to-integer transmutes are valid (if you are okay with losing the // provenance). @@ -106,36 +91,39 @@ impl SimdMutPtr for Simd<*mut T, N> { } #[inline] - fn with_addr(self, addr: Self::Usize) -> Self { + fn with_addr(self: Simd, addr: Simd) -> Simd { // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic. // // In the mean-time, this operation is defined to be "as if" it was // a wrapping_offset, so we can emulate it as such. This should properly // restore pointer provenance even under today's compiler. - self.cast::() - .wrapping_offset(addr.cast::() - self.addr().cast::()) - .cast() + self.cast::() + .wrapping_offset(addr.cast::() - self.addr().cast::()) + .cast::() } #[inline] - fn expose_provenance(self) -> Self::Usize { + fn expose_provenance(self: Simd) -> Simd { // Safety: `self` is a pointer vector unsafe { core::intrinsics::simd::simd_expose_provenance(self) } } #[inline] - fn wrapping_offset(self, count: Self::Isize) -> Self { + fn wrapping_offset( + self: Simd, + count: Simd, + ) -> Simd { // Safety: simd_arith_offset takes a vector of pointers and a vector of offsets unsafe { core::intrinsics::simd::simd_arith_offset(self, count) } } #[inline] - fn wrapping_add(self, count: Self::Usize) -> Self { + fn wrapping_add(self: Simd, count: Simd) -> Simd { self.wrapping_offset(count.cast()) } #[inline] - fn wrapping_sub(self, count: Self::Usize) -> Self { - self.wrapping_offset(-count.cast::()) + fn wrapping_sub(self: Simd, count: Simd) -> Simd { + self.wrapping_offset(-count.cast::()) } } diff --git a/crates/core_simd/src/to_bytes.rs b/crates/core_simd/src/to_bytes.rs index 1fd285e457d..a645d83e145 100644 --- a/crates/core_simd/src/to_bytes.rs +++ b/crates/core_simd/src/to_bytes.rs @@ -13,14 +13,7 @@ use sealed::Sealed; /// Converts SIMD vectors to vectors of bytes pub trait ToBytes: Sealed { /// This type, reinterpreted as bytes. - type Bytes: Copy - + Unpin - + Send - + Sync - + AsRef<[u8]> - + AsMut<[u8]> - + SimdUint - + 'static; + type Bytes: Copy + Unpin + Send + Sync + AsRef<[u8]> + AsMut<[u8]> + 'static; /// Returns the memory representation of this integer as a byte array in native byte /// order. @@ -46,8 +39,8 @@ pub trait ToBytes: Sealed { } macro_rules! swap_bytes { - { f32, $x:expr } => { Simd::from_bits($x.to_bits().swap_bytes()) }; - { f64, $x:expr } => { Simd::from_bits($x.to_bits().swap_bytes()) }; + { f32, $x:expr } => { ::simd_from_bits($x.to_bits().swap_bytes()) }; + { f64, $x:expr } => { ::simd_from_bits($x.to_bits().swap_bytes()) }; { $ty:ty, $x:expr } => { $x.swap_bytes() } } diff --git a/crates/core_simd/src/vector.rs b/crates/core_simd/src/vector.rs index fbef69f267a..6c84847730e 100644 --- a/crates/core_simd/src/vector.rs +++ b/crates/core_simd/src/vector.rs @@ -880,6 +880,13 @@ where impl Copy for Simd where T: SimdElement {} +impl core::ops::Receiver for Simd +where + T: SimdElement, +{ + type Target = T; +} + impl Clone for Simd where T: SimdElement, @@ -1172,10 +1179,7 @@ impl Sealed for *const T {} // Safety: (thin) const pointers are valid SIMD element types, and are supported by this API // // Fat pointers may be supported in the future. -unsafe impl SimdElement for *const T -where - T: core::ptr::Pointee, -{ +unsafe impl SimdElement for *const T { type Mask = isize; } @@ -1184,10 +1188,7 @@ impl Sealed for *mut T {} // Safety: (thin) mut pointers are valid SIMD element types, and are supported by this API // // Fat pointers may be supported in the future. -unsafe impl SimdElement for *mut T -where - T: core::ptr::Pointee, -{ +unsafe impl SimdElement for *mut T { type Mask = isize; } diff --git a/crates/core_simd/tests/cast.rs b/crates/core_simd/tests/cast.rs index 185e1945faa..8701f758e50 100644 --- a/crates/core_simd/tests/cast.rs +++ b/crates/core_simd/tests/cast.rs @@ -11,7 +11,7 @@ macro_rules! cast_types { test_helpers::test_lanes! { fn cast_as() { test_helpers::test_unary_elementwise( - &Vector::::cast::<$target>, + &|x: Vector| -> Simd<$target, N> { x.cast() }, &|x| x as $target, &|_| true, ) diff --git a/crates/core_simd/tests/ops_macros.rs b/crates/core_simd/tests/ops_macros.rs index 6de78f51e59..c0a100f8a8d 100644 --- a/crates/core_simd/tests/ops_macros.rs +++ b/crates/core_simd/tests/ops_macros.rs @@ -202,7 +202,7 @@ macro_rules! impl_common_integer_tests { fn swap_bytes() { test_helpers::test_unary_elementwise( - &$vector::::swap_bytes, + &|x: $vector::| x.swap_bytes(), &$scalar::swap_bytes, &|_| true, ) @@ -210,7 +210,7 @@ macro_rules! impl_common_integer_tests { fn reverse_bits() { test_helpers::test_unary_elementwise( - &$vector::::reverse_bits, + &|x: $vector::| x.reverse_bits(), &$scalar::reverse_bits, &|_| true, ) @@ -218,7 +218,7 @@ macro_rules! impl_common_integer_tests { fn count_ones() { test_helpers::test_unary_elementwise( - &$vector::::count_ones, + &|x: $vector::| x.count_ones(), &|x| x.count_ones() as _, &|_| true, ) @@ -226,7 +226,7 @@ macro_rules! impl_common_integer_tests { fn count_zeros() { test_helpers::test_unary_elementwise( - &$vector::::count_zeros, + &|x: $vector::| x.count_zeros(), &|x| x.count_zeros() as _, &|_| true, ) @@ -234,7 +234,7 @@ macro_rules! impl_common_integer_tests { fn leading_zeros() { test_helpers::test_unary_elementwise( - &$vector::::leading_zeros, + &|x: $vector::| x.leading_zeros(), &|x| x.leading_zeros() as _, &|_| true, ) @@ -242,7 +242,7 @@ macro_rules! impl_common_integer_tests { fn trailing_zeros() { test_helpers::test_unary_elementwise( - &$vector::::trailing_zeros, + &|x: $vector::| x.trailing_zeros(), &|x| x.trailing_zeros() as _, &|_| true, ) @@ -250,7 +250,7 @@ macro_rules! impl_common_integer_tests { fn leading_ones() { test_helpers::test_unary_elementwise( - &$vector::::leading_ones, + &|x: $vector::| x.leading_ones(), &|x| x.leading_ones() as _, &|_| true, ) @@ -258,7 +258,7 @@ macro_rules! impl_common_integer_tests { fn trailing_ones() { test_helpers::test_unary_elementwise( - &$vector::::trailing_ones, + &|x: $vector::| x.trailing_ones(), &|x| x.trailing_ones() as _, &|_| true, ) @@ -289,7 +289,7 @@ macro_rules! impl_signed_tests { fn is_positive() { test_helpers::test_unary_mask_elementwise( - &Vector::::is_positive, + &|x: Vector| x.is_positive(), &Scalar::is_positive, &|_| true, ); @@ -297,7 +297,7 @@ macro_rules! impl_signed_tests { fn is_negative() { test_helpers::test_unary_mask_elementwise( - &Vector::::is_negative, + &|x: Vector| x.is_negative(), &Scalar::is_negative, &|_| true, ); @@ -305,7 +305,7 @@ macro_rules! impl_signed_tests { fn signum() { test_helpers::test_unary_elementwise( - &Vector::::signum, + &|x: Vector| x.signum(), &Scalar::signum, &|_| true, ) @@ -325,7 +325,7 @@ macro_rules! impl_signed_tests { fn abs_diff() { test_helpers::test_binary_elementwise( - &Vector::::abs_diff, + &|x: Vector, y: Vector| x.abs_diff(y), &Scalar::abs_diff, &|_, _| true, ) @@ -438,7 +438,7 @@ macro_rules! impl_unsigned_tests { test_helpers::test_lanes! { fn wrapping_neg() { test_helpers::test_unary_elementwise( - &Vector::::wrapping_neg, + &|x: Vector| x.wrapping_neg(), &Scalar::wrapping_neg, &|_| true, ); @@ -446,7 +446,7 @@ macro_rules! impl_unsigned_tests { fn abs_diff() { test_helpers::test_binary_elementwise( - &Vector::::abs_diff, + &|x: Vector, y: Vector| x.abs_diff(y), &Scalar::abs_diff, &|_, _| true, ) @@ -488,7 +488,7 @@ macro_rules! impl_float_tests { test_helpers::test_lanes! { fn is_sign_positive() { test_helpers::test_unary_mask_elementwise( - &Vector::::is_sign_positive, + &|x: Vector| x.is_sign_positive(), &Scalar::is_sign_positive, &|_| true, ); @@ -496,7 +496,7 @@ macro_rules! impl_float_tests { fn is_sign_negative() { test_helpers::test_unary_mask_elementwise( - &Vector::::is_sign_negative, + &|x: Vector| x.is_sign_negative(), &Scalar::is_sign_negative, &|_| true, ); @@ -504,7 +504,7 @@ macro_rules! impl_float_tests { fn is_finite() { test_helpers::test_unary_mask_elementwise( - &Vector::::is_finite, + &|x: Vector| x.is_finite(), &Scalar::is_finite, &|_| true, ); @@ -512,7 +512,7 @@ macro_rules! impl_float_tests { fn is_infinite() { test_helpers::test_unary_mask_elementwise( - &Vector::::is_infinite, + &|x: Vector| x.is_infinite(), &Scalar::is_infinite, &|_| true, ); @@ -520,7 +520,7 @@ macro_rules! impl_float_tests { fn is_nan() { test_helpers::test_unary_mask_elementwise( - &Vector::::is_nan, + &|x: Vector| x.is_nan(), &Scalar::is_nan, &|_| true, ); @@ -531,7 +531,7 @@ macro_rules! impl_float_tests { // https://github.com/rust-lang/portable-simd/issues/439 #[cfg(not(target_arch = "arm"))] test_helpers::test_unary_mask_elementwise( - &Vector::::is_normal, + &|x: Vector| x.is_normal(), &Scalar::is_normal, &|_| true, ); @@ -542,7 +542,7 @@ macro_rules! impl_float_tests { // https://github.com/rust-lang/portable-simd/issues/439 #[cfg(not(target_arch = "arm"))] test_helpers::test_unary_mask_elementwise( - &Vector::::is_subnormal, + &|x: Vector| x.is_subnormal(), &Scalar::is_subnormal, &|_| true, ); @@ -550,7 +550,7 @@ macro_rules! impl_float_tests { fn abs() { test_helpers::test_unary_elementwise( - &Vector::::abs, + &|x: Vector| x.abs(), &Scalar::abs, &|_| true, ) @@ -558,7 +558,7 @@ macro_rules! impl_float_tests { fn recip() { test_helpers::test_unary_elementwise( - &Vector::::recip, + &|x: Vector| x.recip(), &Scalar::recip, &|_| true, ) @@ -566,7 +566,7 @@ macro_rules! impl_float_tests { fn to_degrees() { test_helpers::test_unary_elementwise_flush_subnormals( - &Vector::::to_degrees, + &|x: Vector| x.to_degrees(), &Scalar::to_degrees, &|_| true, ) @@ -574,7 +574,7 @@ macro_rules! impl_float_tests { fn to_radians() { test_helpers::test_unary_elementwise_flush_subnormals( - &Vector::::to_radians, + &|x: Vector| x.to_radians(), &Scalar::to_radians, &|_| true, ) @@ -582,7 +582,7 @@ macro_rules! impl_float_tests { fn signum() { test_helpers::test_unary_elementwise( - &Vector::::signum, + &|x: Vector| x.signum(), &Scalar::signum, &|_| true, ) @@ -590,7 +590,7 @@ macro_rules! impl_float_tests { fn copysign() { test_helpers::test_binary_elementwise( - &Vector::::copysign, + &|x: Vector, y: Vector| x.copysign(y), &Scalar::copysign, &|_, _| true, ) @@ -599,7 +599,7 @@ macro_rules! impl_float_tests { fn simd_min() { // Regular conditions (both values aren't zero) test_helpers::test_binary_elementwise( - &Vector::::simd_min, + &|x: Vector, y: Vector| x.simd_min(y), &Scalar::min, // Reject the case where both values are zero with different signs &|a, b| { @@ -622,7 +622,7 @@ macro_rules! impl_float_tests { fn simd_max() { // Regular conditions (both values aren't zero) test_helpers::test_binary_elementwise( - &Vector::::simd_max, + &|x: Vector, y: Vector| x.simd_max(y), &Scalar::max, // Reject the case where both values are zero with different signs &|a, b| { diff --git a/crates/core_simd/tests/pointers.rs b/crates/core_simd/tests/pointers.rs index 06670cc9dd9..417f6cd084b 100644 --- a/crates/core_simd/tests/pointers.rs +++ b/crates/core_simd/tests/pointers.rs @@ -10,7 +10,7 @@ macro_rules! common_tests { test_helpers::test_lanes! { fn is_null() { test_helpers::test_unary_mask_elementwise( - &Simd::<*$constness u32, LANES>::is_null, + &|x: Simd::<*$constness u32, LANES>| x.is_null(), &<*$constness u32>::is_null, &|_| true, ); @@ -18,7 +18,7 @@ macro_rules! common_tests { fn addr() { test_helpers::test_unary_elementwise( - &Simd::<*$constness u32, LANES>::addr, + &|x: Simd::<*$constness u32, LANES>| x.addr(), &<*$constness u32>::addr, &|_| true, ); @@ -26,7 +26,7 @@ macro_rules! common_tests { fn with_addr() { test_helpers::test_binary_elementwise( - &Simd::<*$constness u32, LANES>::with_addr, + &|x: Simd::<*$constness u32, LANES>, y: Simd| x.with_addr(y), &<*$constness u32>::with_addr, &|_, _| true, ); @@ -34,7 +34,7 @@ macro_rules! common_tests { fn expose_provenance() { test_helpers::test_unary_elementwise( - &Simd::<*$constness u32, LANES>::expose_provenance, + &|x: Simd::<*$constness u32, LANES>| x.expose_provenance(), &<*$constness u32>::expose_provenance, &|_| true, ); @@ -42,7 +42,7 @@ macro_rules! common_tests { fn wrapping_offset() { test_helpers::test_binary_elementwise( - &Simd::<*$constness u32, LANES>::wrapping_offset, + &|x: Simd::<*$constness u32, LANES>, y: Simd| x.wrapping_offset(y), &<*$constness u32>::wrapping_offset, &|_, _| true, ); @@ -50,7 +50,7 @@ macro_rules! common_tests { fn wrapping_add() { test_helpers::test_binary_elementwise( - &Simd::<*$constness u32, LANES>::wrapping_add, + &|x: Simd::<*$constness u32, LANES>, y: Simd| x.wrapping_add(y), &<*$constness u32>::wrapping_add, &|_, _| true, ); @@ -58,7 +58,7 @@ macro_rules! common_tests { fn wrapping_sub() { test_helpers::test_binary_elementwise( - &Simd::<*$constness u32, LANES>::wrapping_sub, + &|x: Simd::<*$constness u32, LANES>, y: Simd| x.wrapping_sub(y), &<*$constness u32>::wrapping_sub, &|_, _| true, ); @@ -74,7 +74,7 @@ mod const_ptr { test_helpers::test_lanes! { fn cast_mut() { test_helpers::test_unary_elementwise( - &Simd::<*const u32, LANES>::cast_mut, + &|x: Simd::<*const u32, LANES>| x.cast_mut(), &<*const u32>::cast_mut, &|_| true, ); @@ -106,7 +106,7 @@ mod mut_ptr { test_helpers::test_lanes! { fn cast_const() { test_helpers::test_unary_elementwise( - &Simd::<*mut u32, LANES>::cast_const, + &|x: Simd::<*mut u32, LANES>| x.cast_const(), &<*mut u32>::cast_const, &|_| true, ); diff --git a/crates/core_simd/tests/round.rs b/crates/core_simd/tests/round.rs index 95b17f41582..b38d8668876 100644 --- a/crates/core_simd/tests/round.rs +++ b/crates/core_simd/tests/round.rs @@ -72,7 +72,7 @@ macro_rules! float_rounding_test { runner.run( &test_helpers::array::UniformArrayStrategy::new(-MAX_REPRESENTABLE_VALUE..MAX_REPRESENTABLE_VALUE), |x| { - let result_1 = unsafe { Vector::from_array(x).to_int_unchecked::().to_array() }; + let result_1 = unsafe { Vector::from_array(x).to_int_unchecked::().to_array() }; let result_2 = { let mut result: [IntScalar; LANES] = [0; LANES]; for (i, o) in x.iter().zip(result.iter_mut()) {