From 84db2a21b0c8853f281566591d30e6794e3840d3 Mon Sep 17 00:00:00 2001 From: Caleb Zulawski Date: Fri, 7 Nov 2025 01:03:17 -0500 Subject: [PATCH 1/6] Use generic trait parameters to minimize associated types --- crates/core_simd/src/simd/cmp/eq.rs | 46 ++++----- crates/core_simd/src/simd/cmp/ord.rs | 78 +++++++------- crates/core_simd/src/simd/num/float.rs | 113 +++++++++------------ crates/core_simd/src/simd/num/int.rs | 105 +++++++++---------- crates/core_simd/src/simd/num/uint.rs | 53 +++++----- crates/core_simd/src/simd/ptr/const_ptr.rs | 61 ++++------- crates/core_simd/src/simd/ptr/mut_ptr.rs | 61 ++++------- crates/core_simd/src/to_bytes.rs | 9 +- 8 files changed, 224 insertions(+), 302 deletions(-) diff --git a/crates/core_simd/src/simd/cmp/eq.rs b/crates/core_simd/src/simd/cmp/eq.rs index 76836404cbc..96c03f1e81e 100644 --- a/crates/core_simd/src/simd/cmp/eq.rs +++ b/crates/core_simd/src/simd/cmp/eq.rs @@ -4,35 +4,32 @@ use crate::simd::{ }; /// Parallel `PartialEq`. -pub trait SimdPartialEq { - /// The mask type returned by each comparison. - type Mask; - +pub trait SimdPartialEq +where + T: 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, other: Self) -> 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, other: Self) -> 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<$number, N> for Simd<$number, N> { #[inline] - fn simd_eq(self, other: Self) -> Self::Mask { + fn simd_eq(self, other: Self) -> Mask<<$number as SimdElement>::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, other: Self) -> Mask<<$number as SimdElement>::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)) } @@ -47,19 +44,16 @@ 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; - + impl SimdPartialEq<$integer, N> for Mask<$integer, N> { #[inline] - fn simd_eq(self, other: Self) -> Self::Mask { + fn simd_eq(self, other: Self) -> Mask<<$integer as SimdElement>::Mask, N> { // 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 { + fn simd_ne(self, other: Self) -> Mask<<$integer as SimdElement>::Mask, N> { // 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())) } @@ -71,30 +65,26 @@ macro_rules! impl_mask { impl_mask! { i8, i16, i32, i64, isize } -impl SimdPartialEq for Simd<*const T, N> { - type Mask = Mask; - +impl SimdPartialEq<*const T, N> for Simd<*const T, N> { #[inline] - fn simd_eq(self, other: Self) -> Self::Mask { + fn simd_eq(self, other: Self) -> Mask { self.addr().simd_eq(other.addr()) } #[inline] - fn simd_ne(self, other: Self) -> Self::Mask { + fn simd_ne(self, other: Self) -> Mask { self.addr().simd_ne(other.addr()) } } -impl SimdPartialEq for Simd<*mut T, N> { - type Mask = Mask; - +impl SimdPartialEq<*mut T, N> for Simd<*mut T, N> { #[inline] - fn simd_eq(self, other: Self) -> Self::Mask { + fn simd_eq(self, other: Self) -> Mask { self.addr().simd_eq(other.addr()) } #[inline] - fn simd_ne(self, other: Self) -> Self::Mask { + fn simd_ne(self, other: Self) -> 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..081512489ed 100644 --- a/crates/core_simd/src/simd/cmp/ord.rs +++ b/crates/core_simd/src/simd/cmp/ord.rs @@ -1,30 +1,36 @@ use crate::simd::{ - Mask, Select, Simd, + Mask, Select, Simd, SimdElement, cmp::SimdPartialEq, ptr::{SimdConstPtr, SimdMutPtr}, }; /// Parallel `PartialOrd`. -pub trait SimdPartialOrd: SimdPartialEq { +pub trait SimdPartialOrd: SimdPartialEq +where + T: SimdElement, +{ /// 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, other: Self) -> 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, other: Self) -> 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, other: Self) -> 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, other: Self) -> Mask<::Mask, N>; } /// Parallel `Ord`. -pub trait SimdOrd: SimdPartialOrd { +pub trait SimdOrd: SimdPartialOrd +where + T: SimdElement, +{ /// 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; @@ -48,38 +54,38 @@ pub trait SimdOrd: SimdPartialOrd { macro_rules! impl_integer { { $($integer:ty),* } => { $( - impl SimdPartialOrd for Simd<$integer, N> + impl SimdPartialOrd<$integer, N> for Simd<$integer, N> { #[inline] - fn simd_lt(self, other: Self) -> Self::Mask { + fn simd_lt(self, other: Self) -> Mask<<$integer as SimdElement>::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, other: Self) -> Mask<<$integer as SimdElement>::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, other: Self) -> Mask<<$integer as SimdElement>::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, other: Self) -> Mask<<$integer as SimdElement>::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<$integer, N> for Simd<$integer, N> { #[inline] fn simd_max(self, other: Self) -> Self { @@ -110,31 +116,31 @@ 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<$float, N> for Simd<$float, N> { #[inline] - fn simd_lt(self, other: Self) -> Self::Mask { + fn simd_lt(self, other: Self) -> Mask<<$float as SimdElement>::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, other: Self) -> Mask<<$float as SimdElement>::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, other: Self) -> Mask<<$float as SimdElement>::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, other: Self) -> Mask<<$float as SimdElement>::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)) } @@ -149,38 +155,38 @@ impl_float! { f16, f32, f64 } macro_rules! impl_mask { { $($integer:ty),* } => { $( - impl SimdPartialOrd for Mask<$integer, N> + impl SimdPartialOrd<$integer, N> for Mask<$integer, N> { #[inline] - fn simd_lt(self, other: Self) -> Self::Mask { + fn simd_lt(self, other: Self) -> Mask<<$integer as SimdElement>::Mask, N> { // 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 { + fn simd_le(self, other: Self) -> Mask<<$integer as SimdElement>::Mask, N> { // 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 { + fn simd_gt(self, other: Self) -> Mask<<$integer as SimdElement>::Mask, N> { // 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 { + fn simd_ge(self, other: Self) -> Mask<<$integer as SimdElement>::Mask, N> { // 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> + impl SimdOrd<$integer, N> for Mask<$integer, N> { #[inline] fn simd_max(self, other: Self) -> Self { @@ -208,29 +214,29 @@ macro_rules! impl_mask { impl_mask! { i8, i16, i32, i64, isize } -impl SimdPartialOrd for Simd<*const T, N> { +impl SimdPartialOrd<*const T, N> for Simd<*const T, N> { #[inline] - fn simd_lt(self, other: Self) -> Self::Mask { + fn simd_lt(self, other: Self) -> Mask { self.addr().simd_lt(other.addr()) } #[inline] - fn simd_le(self, other: Self) -> Self::Mask { + fn simd_le(self, other: Self) -> Mask { self.addr().simd_le(other.addr()) } #[inline] - fn simd_gt(self, other: Self) -> Self::Mask { + fn simd_gt(self, other: Self) -> Mask { self.addr().simd_gt(other.addr()) } #[inline] - fn simd_ge(self, other: Self) -> Self::Mask { + fn simd_ge(self, other: Self) -> Mask { self.addr().simd_ge(other.addr()) } } -impl SimdOrd for Simd<*const T, N> { +impl SimdOrd<*const T, N> for Simd<*const T, N> { #[inline] fn simd_max(self, other: Self) -> Self { self.simd_lt(other).select(other, self) @@ -252,29 +258,29 @@ impl SimdOrd for Simd<*const T, N> { } } -impl SimdPartialOrd for Simd<*mut T, N> { +impl SimdPartialOrd<*mut T, N> for Simd<*mut T, N> { #[inline] - fn simd_lt(self, other: Self) -> Self::Mask { + fn simd_lt(self, other: Self) -> Mask { self.addr().simd_lt(other.addr()) } #[inline] - fn simd_le(self, other: Self) -> Self::Mask { + fn simd_le(self, other: Self) -> Mask { self.addr().simd_le(other.addr()) } #[inline] - fn simd_gt(self, other: Self) -> Self::Mask { + fn simd_gt(self, other: Self) -> Mask { self.addr().simd_gt(other.addr()) } #[inline] - fn simd_ge(self, other: Self) -> Self::Mask { + fn simd_ge(self, other: Self) -> Mask { self.addr().simd_ge(other.addr()) } } -impl SimdOrd for Simd<*mut T, N> { +impl SimdOrd<*mut T, N> for Simd<*mut T, N> { #[inline] fn simd_max(self, other: Self) -> Self { self.simd_lt(other).select(other, self) diff --git a/crates/core_simd/src/simd/num/float.rs b/crates/core_simd/src/simd/num/float.rs index 14a31b52787..c72ec24e2f1 100644 --- a/crates/core_simd/src/simd/num/float.rs +++ b/crates/core_simd/src/simd/num/float.rs @@ -5,19 +5,12 @@ 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: Copy + Sealed +where + T: SimdElement, +{ /// 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 @@ -42,7 +35,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; /// Rounds toward zero and converts to the same-width integer type, assuming that /// the value is finite and fits in that type. @@ -58,19 +51,19 @@ pub trait SimdFloat: Copy + Sealed { /// which saturates on conversion. /// /// [cast]: Simd::cast - unsafe fn to_int_unchecked(self) -> Self::Cast + unsafe fn to_int_unchecked(self) -> Simd where - Self::Scalar: core::convert::FloatToInt; + T: 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; /// 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 from_bits(bits: Simd) -> Self; /// Produces a vector where every element has the absolute value of the /// equivalently-indexed element in `self`. @@ -92,33 +85,33 @@ pub trait SimdFloat: Copy + Sealed { /// 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) -> 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) -> 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) -> 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) -> 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) -> 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) -> 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) -> Mask<::Mask, N>; /// Replaces each element with a number that represents its sign. /// @@ -166,7 +159,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) -> T; /// Reducing multiply. Returns the product of the elements of the vector. /// @@ -180,7 +173,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) -> T; /// Returns the maximum element in the vector. /// @@ -207,7 +200,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) -> T; /// Returns the minimum element in the vector. /// @@ -234,7 +227,7 @@ 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) -> T; } macro_rules! impl_trait { @@ -242,17 +235,12 @@ macro_rules! impl_trait { $( impl Sealed for Simd<$ty, N> {} - 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<$ty, N> for Simd<$ty, N> { + type Bits = $bits_ty; #[cfg(not(target_arch = "aarch64"))] #[inline] - fn cast(self) -> Self::Cast - { + fn cast(self) -> Simd { // Safety: supported types are guaranteed by SimdCast unsafe { core::intrinsics::simd::simd_as(self) } } @@ -261,8 +249,7 @@ macro_rules! impl_trait { // tracked in: https://github.com/rust-lang/rust/issues/135982 #[cfg(target_arch = "aarch64")] #[inline] - fn cast(self) -> Self::Cast - { + fn cast(self) -> Simd { const { assert!(N <= 64) }; if N <= 2 || N == 4 || N == 8 || N == 16 || N == 32 || N == 64 { // Safety: supported types are guaranteed by SimdCast @@ -287,24 +274,24 @@ macro_rules! impl_trait { #[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 where - Self::Scalar: core::convert::FloatToInt, + $ty: 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 { + 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 from_bits(bits: Simd) -> Self { + assert_eq!(size_of::(), size_of::>()); // Safety: transmuting between vector types is safe unsafe { core::mem::transmute_copy(&bits) } } @@ -323,56 +310,56 @@ macro_rules! impl_trait { #[inline] fn to_degrees(self) -> Self { // to_degrees uses a special constant for better precision, so extract that constant - self * Self::splat(Self::Scalar::to_degrees(1.)) + self * Self::splat(<$ty>::to_degrees(1.)) } #[inline] fn to_radians(self) -> Self { - self * Self::splat(Self::Scalar::to_radians(1.)) + self * Self::splat(<$ty>::to_radians(1.)) } #[inline] - fn is_sign_positive(self) -> Self::Mask { + fn is_sign_positive(self) -> Mask<<$mask_ty as SimdElement>::Mask, N> { !self.is_sign_negative() } #[inline] - fn is_sign_negative(self) -> Self::Mask { + fn is_sign_negative(self) -> Mask<<$mask_ty as SimdElement>::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) -> Mask<<$mask_ty as SimdElement>::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) -> Mask<<$mask_ty as SimdElement>::Mask, N> { + self.abs().simd_eq(Self::splat(<$ty>::INFINITY)) } #[inline] - fn is_finite(self) -> Self::Mask { - self.abs().simd_lt(Self::splat(Self::Scalar::INFINITY)) + fn is_finite(self) -> Mask<<$mask_ty as SimdElement>::Mask, N> { + self.abs().simd_lt(Self::splat(<$ty>::INFINITY)) } #[inline] - fn is_subnormal(self) -> Self::Mask { + fn is_subnormal(self) -> Mask<<$mask_ty as SimdElement>::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)) + not_zero & (self.to_bits() & Self::splat(<$ty>::INFINITY).to_bits()).simd_eq(Simd::splat(0)) } #[inline] - fn is_normal(self) -> Self::Mask { + fn is_normal(self) -> Mask<<$mask_ty as SimdElement>::Mask, N> { !(self.abs().simd_eq(Self::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)) + self.is_nan().select(Self::splat(<$ty>::NAN), Self::splat(1.0).copysign(self)) } #[inline] @@ -407,7 +394,7 @@ macro_rules! impl_trait { } #[inline] - fn reduce_sum(self) -> Self::Scalar { + fn reduce_sum(self) -> $ty { // LLVM sum is inaccurate on i586 if cfg!(all(target_arch = "x86", not(target_feature = "sse2"))) { self.as_array().iter().sum() @@ -418,7 +405,7 @@ macro_rules! impl_trait { } #[inline] - fn reduce_product(self) -> Self::Scalar { + fn reduce_product(self) -> $ty { // LLVM product is inaccurate on i586 if cfg!(all(target_arch = "x86", not(target_feature = "sse2"))) { self.as_array().iter().product() @@ -429,15 +416,15 @@ macro_rules! impl_trait { } #[inline] - fn reduce_max(self) -> Self::Scalar { + fn reduce_max(self) -> $ty { // 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) -> $ty { + 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..10f51ecf3ae 100644 --- a/crates/core_simd/src/simd/num/int.rs +++ b/crates/core_simd/src/simd/num/int.rs @@ -4,25 +4,19 @@ 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: Copy + Sealed +where + T: SimdElement, +{ + /// 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; /// Lanewise saturating add. /// @@ -89,7 +83,7 @@ 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, second: Self) -> Simd; /// Lanewise saturating absolute value, implemented in Rust. /// As abs(), except the MIN value becomes MAX instead of itself. @@ -128,10 +122,10 @@ pub trait SimdInt: Copy + Sealed { fn saturating_neg(self) -> Self; /// Returns true for each positive element and false if it is zero or negative. - fn is_positive(self) -> Self::Mask; + fn is_positive(self) -> 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) -> Mask<::Mask, N>; /// Returns numbers representing the sign of each element. /// * `0` if the number is zero @@ -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) -> T; /// 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) -> T; /// 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) -> T; /// Returns the minimum element in the vector. /// @@ -201,16 +195,16 @@ 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) -> T; /// Returns the cumulative bitwise "and" across the elements of the vector. - fn reduce_and(self) -> Self::Scalar; + fn reduce_and(self) -> T; /// Returns the cumulative bitwise "or" across the elements of the vector. - fn reduce_or(self) -> Self::Scalar; + fn reduce_or(self) -> T; /// Returns the cumulative bitwise "xor" across the elements of the vector. - fn reduce_xor(self) -> Self::Scalar; + fn reduce_xor(self) -> T; /// Reverses the byte order of each element. fn swap_bytes(self) -> Self; @@ -220,22 +214,22 @@ pub trait SimdInt: Copy + Sealed { fn reverse_bits(self) -> Self; /// Returns the number of ones in the binary representation of each element. - fn count_ones(self) -> Self::Unsigned; + fn count_ones(self) -> Simd; /// Returns the number of zeros in the binary representation of each element. - fn count_zeros(self) -> Self::Unsigned; + fn count_zeros(self) -> 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; /// Returns the number of trailing zeros in the binary representation of each element. - fn trailing_zeros(self) -> Self::Unsigned; + fn trailing_zeros(self) -> 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; /// Returns the number of trailing ones in the binary representation of each element. - fn trailing_ones(self) -> Self::Unsigned; + fn trailing_ones(self) -> Simd; } macro_rules! impl_trait { @@ -243,14 +237,11 @@ macro_rules! impl_trait { $( impl Sealed for Simd<$ty, N> {} - 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<$ty, N> for Simd<$ty, N> { + type Unsigned = $unsigned; #[inline] - fn cast(self) -> Self::Cast { + fn cast(self) -> Simd { // Safety: supported types are guaranteed by SimdCast unsafe { core::intrinsics::simd::simd_as(self) } } @@ -275,7 +266,7 @@ macro_rules! impl_trait { } #[inline] - fn abs_diff(self, second: Self) -> Self::Unsigned { + fn abs_diff(self, second: Self) -> Simd { let max = self.simd_max(second); let min = self.simd_min(second); (max - min).cast() @@ -295,12 +286,12 @@ macro_rules! impl_trait { } #[inline] - fn is_positive(self) -> Self::Mask { + fn is_positive(self) -> Mask<<$ty as SimdElement>::Mask, N> { self.simd_gt(Self::splat(0)) } #[inline] - fn is_negative(self) -> Self::Mask { + fn is_negative(self) -> Mask<<$ty as SimdElement>::Mask, N> { self.simd_lt(Self::splat(0)) } @@ -313,43 +304,43 @@ macro_rules! impl_trait { } #[inline] - fn reduce_sum(self) -> Self::Scalar { + fn reduce_sum(self) -> $ty { // 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) -> $ty { // 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) -> $ty { // 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) -> $ty { // 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) -> $ty { // 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) -> $ty { // 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) -> $ty { // Safety: `self` is an integer vector unsafe { core::intrinsics::simd::simd_reduce_xor(self) } } @@ -367,33 +358,33 @@ macro_rules! impl_trait { } #[inline] - fn count_ones(self) -> Self::Unsigned { - self.cast::<$unsigned>().count_ones() + fn count_ones(self) -> Simd { + self.cast::().count_ones() } #[inline] - fn count_zeros(self) -> Self::Unsigned { - self.cast::<$unsigned>().count_zeros() + fn count_zeros(self) -> Simd { + self.cast::().count_zeros() } #[inline] - fn leading_zeros(self) -> Self::Unsigned { - self.cast::<$unsigned>().leading_zeros() + fn leading_zeros(self) -> Simd { + self.cast::().leading_zeros() } #[inline] - fn trailing_zeros(self) -> Self::Unsigned { - self.cast::<$unsigned>().trailing_zeros() + fn trailing_zeros(self) -> Simd { + self.cast::().trailing_zeros() } #[inline] - fn leading_ones(self) -> Self::Unsigned { - self.cast::<$unsigned>().leading_ones() + fn leading_ones(self) -> Simd { + self.cast::().leading_ones() } #[inline] - fn trailing_ones(self) -> Self::Unsigned { - self.cast::<$unsigned>().trailing_ones() + fn trailing_ones(self) -> 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..ae4e98e469a 100644 --- a/crates/core_simd/src/simd/num/uint.rs +++ b/crates/core_simd/src/simd/num/uint.rs @@ -2,19 +2,18 @@ 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: Copy + Sealed +where + T: SimdElement, +{ + /// 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; /// Wrapping negation. /// @@ -75,25 +74,25 @@ pub trait SimdUint: Copy + Sealed { fn abs_diff(self, second: Self) -> Self; /// Returns the sum of the elements of the vector, with wrapping addition. - fn reduce_sum(self) -> Self::Scalar; + fn reduce_sum(self) -> T; /// Returns the product of the elements of the vector, with wrapping multiplication. - fn reduce_product(self) -> Self::Scalar; + fn reduce_product(self) -> T; /// Returns the maximum element in the vector. - fn reduce_max(self) -> Self::Scalar; + fn reduce_max(self) -> T; /// Returns the minimum element in the vector. - fn reduce_min(self) -> Self::Scalar; + fn reduce_min(self) -> T; /// Returns the cumulative bitwise "and" across the elements of the vector. - fn reduce_and(self) -> Self::Scalar; + fn reduce_and(self) -> T; /// Returns the cumulative bitwise "or" across the elements of the vector. - fn reduce_or(self) -> Self::Scalar; + fn reduce_or(self) -> T; /// Returns the cumulative bitwise "xor" across the elements of the vector. - fn reduce_xor(self) -> Self::Scalar; + fn reduce_xor(self) -> T; /// Reverses the byte order of each element. fn swap_bytes(self) -> Self; @@ -126,13 +125,11 @@ macro_rules! impl_trait { $( impl Sealed for Simd<$ty, N> {} - impl SimdUint for Simd<$ty, N> - { - type Scalar = $ty; - type Cast = Simd; + impl SimdUint<$ty, N> for Simd<$ty, N> { + type Signed = $signed; #[inline] - fn cast(self) -> Self::Cast { + fn cast(self) -> Simd { // Safety: supported types are guaranteed by SimdCast unsafe { core::intrinsics::simd::simd_as(self) } } @@ -140,7 +137,7 @@ macro_rules! impl_trait { #[inline] fn wrapping_neg(self) -> Self { use crate::simd::num::SimdInt; - (-self.cast::<$signed>()).cast() + (-self.cast::()).cast() } #[inline] @@ -163,43 +160,43 @@ macro_rules! impl_trait { } #[inline] - fn reduce_sum(self) -> Self::Scalar { + fn reduce_sum(self) -> $ty { // 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) -> $ty { // 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) -> $ty { // 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) -> $ty { // 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) -> $ty { // 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) -> $ty { // 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) -> $ty { // Safety: `self` is an integer vector unsafe { core::intrinsics::simd::simd_reduce_xor(self) } } diff --git a/crates/core_simd/src/simd/ptr/const_ptr.rs b/crates/core_simd/src/simd/ptr/const_ptr.rs index be2b9e6b483..ad88488e0d1 100644 --- a/crates/core_simd/src/simd/ptr/const_ptr.rs +++ b/crates/core_simd/src/simd/ptr/const_ptr.rs @@ -2,44 +2,29 @@ use super::sealed::Sealed; use crate::simd::{Mask, Simd, 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: Copy + Sealed { /// Returns `true` for each element that is null. - fn is_null(self) -> Self::Mask; + fn is_null(self) -> 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<*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<*mut T, 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; /// 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, addr: Simd) -> Self; /// Exposes the "provenance" part of the pointer for future use in /// [`super::with_exposed_provenance`] and returns the "address" portion. @@ -47,40 +32,34 @@ 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; /// 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, offset: Simd) -> Self; /// 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, count: Simd) -> Self; /// 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, count: Simd) -> Self; } 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 Simd<*const T, N> { #[inline] - fn is_null(self) -> Self::Mask { + fn is_null(self) -> Mask { Simd::splat(core::ptr::null()).simd_eq(self) } #[inline] - fn cast(self) -> Self::CastPtr { + fn cast(self) -> 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 +71,13 @@ impl SimdConstPtr for Simd<*const T, N> { } #[inline] - fn cast_mut(self) -> Self::MutPtr { + fn cast_mut(self) -> Simd<*mut T, N> { // Safety: pointers can be cast unsafe { core::intrinsics::simd::simd_cast_ptr(self) } } #[inline] - fn addr(self) -> Self::Usize { + fn addr(self) -> 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,7 +85,7 @@ impl SimdConstPtr for Simd<*const T, N> { } #[inline] - fn with_addr(self, addr: Self::Usize) -> Self { + fn with_addr(self, addr: Simd) -> Self { // 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 @@ -118,24 +97,24 @@ impl SimdConstPtr for Simd<*const T, N> { } #[inline] - fn expose_provenance(self) -> Self::Usize { + fn expose_provenance(self) -> 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, count: Simd) -> Self { // 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, count: Simd) -> Self { self.wrapping_offset(count.cast()) } #[inline] - fn wrapping_sub(self, count: Self::Usize) -> Self { + fn wrapping_sub(self, count: Simd) -> Self { 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..e5195b41b96 100644 --- a/crates/core_simd/src/simd/ptr/mut_ptr.rs +++ b/crates/core_simd/src/simd/ptr/mut_ptr.rs @@ -2,44 +2,29 @@ use super::sealed::Sealed; use crate::simd::{Mask, Simd, 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: Copy + Sealed { /// Returns `true` for each element that is null. - fn is_null(self) -> Self::Mask; + fn is_null(self) -> 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<*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<*const T, 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; /// 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, addr: Simd) -> Self; /// Exposes the "provenance" part of the pointer for future use in /// [`super::with_exposed_provenance_mut`] and returns the "address" portion. @@ -47,40 +32,34 @@ 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; /// 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, offset: Simd) -> Self; /// 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, count: Simd) -> Self; /// 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, count: Simd) -> Self; } 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 Simd<*mut T, N> { #[inline] - fn is_null(self) -> Self::Mask { + fn is_null(self) -> Mask { Simd::splat(core::ptr::null_mut()).simd_eq(self) } #[inline] - fn cast(self) -> Self::CastPtr { + fn cast(self) -> 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 +71,13 @@ impl SimdMutPtr for Simd<*mut T, N> { } #[inline] - fn cast_const(self) -> Self::ConstPtr { + fn cast_const(self) -> Simd<*const T, N> { // Safety: pointers can be cast unsafe { core::intrinsics::simd::simd_cast_ptr(self) } } #[inline] - fn addr(self) -> Self::Usize { + fn addr(self) -> 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,7 +85,7 @@ impl SimdMutPtr for Simd<*mut T, N> { } #[inline] - fn with_addr(self, addr: Self::Usize) -> Self { + fn with_addr(self, addr: Simd) -> Self { // 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 @@ -118,24 +97,24 @@ impl SimdMutPtr for Simd<*mut T, N> { } #[inline] - fn expose_provenance(self) -> Self::Usize { + fn expose_provenance(self) -> 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, count: Simd) -> Self { // 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, count: Simd) -> Self { self.wrapping_offset(count.cast()) } #[inline] - fn wrapping_sub(self, count: Self::Usize) -> Self { + fn wrapping_sub(self, count: Simd) -> Self { 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..927c9c7c6c8 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. From fea6be7a17bc72933fb17d7a7802fd5bbbaa7167 Mon Sep 17 00:00:00 2001 From: Caleb Zulawski Date: Thu, 7 May 2026 22:17:06 -0400 Subject: [PATCH 2/6] Implement traits over scalars with Simd as a self type --- crates/core_simd/src/lib.rs | 1 + crates/core_simd/src/masks.rs | 81 ++++++++ crates/core_simd/src/simd/cmp/eq.rs | 63 +++---- crates/core_simd/src/simd/cmp/ord.rs | 205 ++++++++++----------- crates/core_simd/src/simd/num/float.rs | 165 +++++++++-------- crates/core_simd/src/simd/num/int.rs | 143 +++++++------- crates/core_simd/src/simd/num/uint.rs | 100 +++++----- crates/core_simd/src/simd/ptr.rs | 3 + crates/core_simd/src/simd/ptr/const_ptr.rs | 71 ++++--- crates/core_simd/src/simd/ptr/mut_ptr.rs | 71 ++++--- crates/core_simd/src/to_bytes.rs | 4 +- crates/core_simd/src/vector.rs | 7 + crates/core_simd/tests/cast.rs | 2 +- crates/core_simd/tests/ops_macros.rs | 58 +++--- crates/core_simd/tests/pointers.rs | 18 +- crates/core_simd/tests/round.rs | 2 +- 16 files changed, 555 insertions(+), 439 deletions(-) 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 96c03f1e81e..3ffd6c83aee 100644 --- a/crates/core_simd/src/simd/cmp/eq.rs +++ b/crates/core_simd/src/simd/cmp/eq.rs @@ -4,32 +4,41 @@ use crate::simd::{ }; /// Parallel `PartialEq`. -pub trait SimdPartialEq -where - T: SimdElement, -{ +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) -> Mask<::Mask, N>; + 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) -> Mask<::Mask, N>; + fn simd_ne( + self: Simd, + other: Simd, + ) -> Mask<::Mask, N>; } macro_rules! impl_number { { $($number:ty),* } => { $( - impl SimdPartialEq<$number, N> for Simd<$number, N> { + impl SimdPartialEq for $number { #[inline] - fn simd_eq(self, other: Self) -> Mask<<$number as SimdElement>::Mask, N> { + 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) -> Mask<<$number as SimdElement>::Mask, N> { + 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)) } @@ -41,50 +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<$integer, N> for Mask<$integer, N> { - #[inline] - fn simd_eq(self, other: Self) -> Mask<<$integer as SimdElement>::Mask, N> { - // 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) -> Mask<<$integer as SimdElement>::Mask, N> { - // 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<*const T, N> for Simd<*const T, N> { +impl SimdPartialEq for *const T { #[inline] - fn simd_eq(self, other: Self) -> Mask { + fn simd_eq(self: Simd, other: Simd) -> Mask { self.addr().simd_eq(other.addr()) } #[inline] - fn simd_ne(self, other: Self) -> Mask { + fn simd_ne(self: Simd, other: Simd) -> Mask { self.addr().simd_ne(other.addr()) } } -impl SimdPartialEq<*mut T, N> for Simd<*mut T, N> { +impl SimdPartialEq for *mut T { #[inline] - fn simd_eq(self, other: Self) -> Mask { + fn simd_eq(self: Simd, other: Simd) -> Mask { self.addr().simd_eq(other.addr()) } #[inline] - fn simd_ne(self, other: 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 081512489ed..a6f718b8f6e 100644 --- a/crates/core_simd/src/simd/cmp/ord.rs +++ b/crates/core_simd/src/simd/cmp/ord.rs @@ -5,39 +5,45 @@ use crate::simd::{ }; /// Parallel `PartialOrd`. -pub trait SimdPartialOrd: SimdPartialEq -where - T: SimdElement, -{ +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) -> Mask<::Mask, N>; + 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) -> Mask<::Mask, N>; + 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) -> Mask<::Mask, N>; + 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) -> Mask<::Mask, N>; + fn simd_ge( + self: Simd, + other: Simd, + ) -> Mask<::Mask, N>; } /// Parallel `Ord`. -pub trait SimdOrd: SimdPartialOrd -where - T: SimdElement, -{ +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. /// @@ -48,58 +54,76 @@ where /// /// 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<$integer, N> for Simd<$integer, N> - { + impl SimdPartialOrd for $integer { #[inline] - fn simd_lt(self, other: Self) -> Mask<<$integer as SimdElement>::Mask, N> { + 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) -> Mask<<$integer as SimdElement>::Mask, N> { + 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) -> Mask<<$integer as SimdElement>::Mask, N> { + 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) -> Mask<<$integer as SimdElement>::Mask, N> { + 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<$integer, N> 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`", @@ -116,31 +140,42 @@ impl_integer! { u8, u16, u32, u64, usize, i8, i16, i32, i64, isize } macro_rules! impl_float { { $($float:ty),* } => { $( - impl SimdPartialOrd<$float, N> for Simd<$float, N> - { + impl SimdPartialOrd for $float { #[inline] - fn simd_lt(self, other: Self) -> Mask<<$float as SimdElement>::Mask, N> { + 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) -> Mask<<$float as SimdElement>::Mask, N> { + 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) -> Mask<<$float as SimdElement>::Mask, N> { + 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) -> Mask<<$float as SimdElement>::Mask, N> { + 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)) } @@ -152,104 +187,46 @@ macro_rules! impl_float { impl_float! { f16, f32, f64 } -macro_rules! impl_mask { - { $($integer:ty),* } => { - $( - impl SimdPartialOrd<$integer, N> for Mask<$integer, N> - { - #[inline] - fn simd_lt(self, other: Self) -> Mask<<$integer as SimdElement>::Mask, N> { - // 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) -> Mask<<$integer as SimdElement>::Mask, N> { - // 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) -> Mask<<$integer as SimdElement>::Mask, N> { - // 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) -> Mask<<$integer as SimdElement>::Mask, N> { - // 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<$integer, N> 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<*const T, N> for Simd<*const T, N> { +impl SimdPartialOrd for *const T { #[inline] - fn simd_lt(self, other: Self) -> Mask { + fn simd_lt(self: Simd, other: Simd) -> Mask { self.addr().simd_lt(other.addr()) } #[inline] - fn simd_le(self, other: Self) -> Mask { + fn simd_le(self: Simd, other: Simd) -> Mask { self.addr().simd_le(other.addr()) } #[inline] - fn simd_gt(self, other: Self) -> Mask { + fn simd_gt(self: Simd, other: Simd) -> Mask { self.addr().simd_gt(other.addr()) } #[inline] - fn simd_ge(self, other: Self) -> Mask { + fn simd_ge(self: Simd, other: Simd) -> Mask { self.addr().simd_ge(other.addr()) } } -impl SimdOrd<*const T, N> 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`", @@ -258,42 +235,46 @@ impl SimdOrd<*const T, N> for Simd<*const T, N> { } } -impl SimdPartialOrd<*mut T, N> for Simd<*mut T, N> { +impl SimdPartialOrd for *mut T { #[inline] - fn simd_lt(self, other: Self) -> Mask { + fn simd_lt(self: Simd, other: Simd) -> Mask { self.addr().simd_lt(other.addr()) } #[inline] - fn simd_le(self, other: Self) -> Mask { + fn simd_le(self: Simd, other: Simd) -> Mask { self.addr().simd_le(other.addr()) } #[inline] - fn simd_gt(self, other: Self) -> Mask { + fn simd_gt(self: Simd, other: Simd) -> Mask { self.addr().simd_gt(other.addr()) } #[inline] - fn simd_ge(self, other: Self) -> Mask { + fn simd_ge(self: Simd, other: Simd) -> Mask { self.addr().simd_ge(other.addr()) } } -impl SimdOrd<*mut T, N> 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 c72ec24e2f1..31802528a9f 100644 --- a/crates/core_simd/src/simd/num/float.rs +++ b/crates/core_simd/src/simd/num/float.rs @@ -5,10 +5,7 @@ use crate::simd::{ }; /// Operations on SIMD vectors of floats. -pub trait SimdFloat: Copy + Sealed -where - T: SimdElement, -{ +pub trait SimdFloat: SimdElement + Copy + Sealed { /// Bit representation of this SIMD vector type. type Bits: SimdElement; /// Performs elementwise conversion of this vector's elements to another SIMD-valid type. @@ -23,7 +20,7 @@ where /// # #[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. @@ -35,7 +32,7 @@ where /// assert_eq!(floats_again, Simd::from_array([1.0, -4.0, 2147483647.0, 0.0])); /// ``` #[must_use] - fn cast(self) -> Simd; + 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. @@ -50,68 +47,72 @@ where /// 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) -> Simd + /// [cast]: SimdFloat::cast + unsafe fn to_int_unchecked(self: Simd) -> Simd where - T: 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) -> Simd; + 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: Simd) -> Self; + fn 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) -> Mask<::Mask, N>; + 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) -> Mask<::Mask, N>; + 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) -> Mask<::Mask, N>; + 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) -> Mask<::Mask, N>; + 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) -> Mask<::Mask, N>; + 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) -> Mask<::Mask, N>; + 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) -> Mask<::Mask, N>; + fn is_normal(self: Simd) -> Mask<::Mask, N>; /// Replaces each element with a number that represents its sign. /// @@ -119,25 +120,25 @@ where /// * `-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. /// @@ -145,7 +146,11 @@ where /// 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. /// @@ -159,7 +164,7 @@ where /// let v = f32x2::from_array([1., 2.]); /// assert_eq!(v.reduce_sum(), 3.); /// ``` - fn reduce_sum(self) -> T; + fn reduce_sum(self: Simd) -> Self; /// Reducing multiply. Returns the product of the elements of the vector. /// @@ -173,7 +178,7 @@ where /// let v = f32x2::from_array([3., 4.]); /// assert_eq!(v.reduce_product(), 12.); /// ``` - fn reduce_product(self) -> T; + fn reduce_product(self: Simd) -> Self; /// Returns the maximum element in the vector. /// @@ -200,7 +205,7 @@ where /// let v = f32x2::from_array([f32::NAN, f32::NAN]); /// assert!(v.reduce_max().is_nan()); /// ``` - fn reduce_max(self) -> T; + fn reduce_max(self: Simd) -> Self; /// Returns the minimum element in the vector. /// @@ -227,20 +232,20 @@ where /// let v = f32x2::from_array([f32::NAN, f32::NAN]); /// assert!(v.reduce_min().is_nan()); /// ``` - fn reduce_min(self) -> T; + 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<$ty, N> for Simd<$ty, N> { + impl SimdFloat for $ty { type Bits = $bits_ty; #[cfg(not(target_arch = "aarch64"))] #[inline] - fn cast(self) -> Simd { + fn cast(self: Simd) -> Simd { // Safety: supported types are guaranteed by SimdCast unsafe { core::intrinsics::simd::simd_as(self) } } @@ -249,140 +254,144 @@ macro_rules! impl_trait { // tracked in: https://github.com/rust-lang/rust/issues/135982 #[cfg(target_arch = "aarch64")] #[inline] - fn cast(self) -> Simd { + fn cast(self: Simd) -> Simd { 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(); + let x = self.resize::<4>(Default::default()).cast::(); x.resize::(x[0]) } else if N < 8 { - let x = self.resize::<8>(Default::default()).cast(); + let x = self.resize::<8>(Default::default()).cast::(); x.resize::(x[0]) } else if N < 16 { - let x = self.resize::<16>(Default::default()).cast(); + let x = self.resize::<16>(Default::default()).cast::(); x.resize::(x[0]) } else if N < 32 { - let x = self.resize::<32>(Default::default()).cast(); + let x = self.resize::<32>(Default::default()).cast::(); x.resize::(x[0]) } else { - let x = self.resize::<64>(Default::default()).cast(); + 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) -> Simd + unsafe fn to_int_unchecked(self: Simd) -> Simd where - $ty: 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 { - 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) -> Self { - assert_eq!(size_of::(), size_of::>()); + fn 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(<$ty>::to_degrees(1.)) + self * Simd::splat(<$ty>::to_degrees(1.)) } #[inline] - fn to_radians(self) -> Self { - self * Self::splat(<$ty>::to_radians(1.)) + fn to_radians(self: Simd) -> Simd { + self * Simd::splat(<$ty>::to_radians(1.)) } #[inline] - fn is_sign_positive(self) -> Mask<<$mask_ty as SimdElement>::Mask, N> { + fn is_sign_positive(self: Simd) -> Mask<::Mask, N> { !self.is_sign_negative() } #[inline] - fn is_sign_negative(self) -> Mask<<$mask_ty as SimdElement>::Mask, N> { + 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) -> Mask<<$mask_ty as SimdElement>::Mask, N> { + fn is_nan(self: Simd) -> Mask<::Mask, N> { self.simd_ne(self) } #[inline] - fn is_infinite(self) -> Mask<<$mask_ty as SimdElement>::Mask, N> { - self.abs().simd_eq(Self::splat(<$ty>::INFINITY)) + fn is_infinite(self: Simd) -> Mask<::Mask, N> { + self.abs().simd_eq(Simd::splat(<$ty>::INFINITY)) } #[inline] - fn is_finite(self) -> Mask<<$mask_ty as SimdElement>::Mask, N> { - self.abs().simd_lt(Self::splat(<$ty>::INFINITY)) + fn is_finite(self: Simd) -> Mask<::Mask, N> { + self.abs().simd_lt(Simd::splat(<$ty>::INFINITY)) } #[inline] - fn is_subnormal(self) -> Mask<<$mask_ty as SimdElement>::Mask, N> { + 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(<$ty>::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) -> Mask<<$mask_ty as SimdElement>::Mask, N> { - !(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(<$ty>::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(); + ::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`", @@ -394,7 +403,7 @@ macro_rules! impl_trait { } #[inline] - fn reduce_sum(self) -> $ty { + 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() @@ -405,7 +414,7 @@ macro_rules! impl_trait { } #[inline] - fn reduce_product(self) -> $ty { + 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() @@ -416,14 +425,14 @@ macro_rules! impl_trait { } #[inline] - fn reduce_max(self) -> $ty { + 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(<$ty>::NAN, <$ty>::max) } #[inline] - fn reduce_min(self) -> $ty { + 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 10f51ecf3ae..33552a9ba57 100644 --- a/crates/core_simd/src/simd/num/int.rs +++ b/crates/core_simd/src/simd/num/int.rs @@ -4,10 +4,7 @@ use crate::simd::{ }; /// Operations on SIMD vectors of signed integers. -pub trait SimdInt: Copy + Sealed -where - T: SimdElement, -{ +pub trait SimdInt: SimdElement + Copy + Sealed { /// Unsigned element type with the same width as `T`. type Unsigned: SimdElement; @@ -16,7 +13,7 @@ where /// 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) -> Simd; + fn cast(self: Simd) -> Simd; /// Lanewise saturating add. /// @@ -34,7 +31,7 @@ where /// 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. /// @@ -52,7 +49,7 @@ where /// 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. @@ -67,7 +64,7 @@ where /// 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`. @@ -83,7 +80,10 @@ where /// 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) -> Simd; + 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. @@ -101,7 +101,7 @@ where /// 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. @@ -119,19 +119,19 @@ where /// 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) -> Mask<::Mask, N>; + 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) -> Mask<::Mask, N>; + 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. /// @@ -149,7 +149,7 @@ where /// let v = i32x4::from_array([i32::MAX, 1, 0, 0]); /// assert_eq!(v.reduce_sum(), i32::MIN); /// ``` - fn reduce_sum(self) -> T; + fn reduce_sum(self: Simd) -> Self; /// Returns the product of the elements of the vector, with wrapping multiplication. /// @@ -167,7 +167,7 @@ where /// let v = i32x4::from_array([i32::MAX, 2, 1, 1]); /// assert!(v.reduce_product() < i32::MAX); /// ``` - fn reduce_product(self) -> T; + fn reduce_product(self: Simd) -> Self; /// Returns the maximum element in the vector. /// @@ -181,7 +181,7 @@ where /// let v = i32x4::from_array([1, 2, 3, 4]); /// assert_eq!(v.reduce_max(), 4); /// ``` - fn reduce_max(self) -> T; + fn reduce_max(self: Simd) -> Self; /// Returns the minimum element in the vector. /// @@ -195,85 +195,94 @@ where /// let v = i32x4::from_array([1, 2, 3, 4]); /// assert_eq!(v.reduce_min(), 1); /// ``` - fn reduce_min(self) -> T; + fn reduce_min(self: Simd) -> Self; /// Returns the cumulative bitwise "and" across the elements of the vector. - fn reduce_and(self) -> T; + fn reduce_and(self: Simd) -> Self; /// Returns the cumulative bitwise "or" across the elements of the vector. - fn reduce_or(self) -> T; + fn reduce_or(self: Simd) -> Self; /// Returns the cumulative bitwise "xor" across the elements of the vector. - fn reduce_xor(self) -> T; + 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) -> Simd; + fn count_ones(self: Simd) -> Simd; /// Returns the number of zeros in the binary representation of each element. - fn count_zeros(self) -> Simd; + fn count_zeros(self: Simd) -> Simd; /// Returns the number of leading zeros in the binary representation of each element. - fn leading_zeros(self) -> Simd; + fn leading_zeros(self: Simd) -> Simd; /// Returns the number of trailing zeros in the binary representation of each element. - fn trailing_zeros(self) -> Simd; + fn trailing_zeros(self: Simd) -> Simd; /// Returns the number of leading ones in the binary representation of each element. - fn leading_ones(self) -> Simd; + fn leading_ones(self: Simd) -> Simd; /// Returns the number of trailing ones in the binary representation of each element. - fn trailing_ones(self) -> Simd; + 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<$ty, N> for Simd<$ty, N> { + impl SimdInt for $ty { type Unsigned = $unsigned; #[inline] - fn cast(self) -> Simd { + 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) -> Simd { + 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); @@ -281,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) -> Mask<<$ty as SimdElement>::Mask, N> { - 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) -> Mask<<$ty as SimdElement>::Mask, N> { - 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) -> $ty { + 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) -> $ty { + 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) -> $ty { + 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) -> $ty { + 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) -> $ty { + 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) -> $ty { + 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) -> $ty { + 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) -> Simd { - self.cast::().count_ones() + fn count_ones(self: Simd) -> Simd { + self.cast::().count_ones() } #[inline] - fn count_zeros(self) -> Simd { - self.cast::().count_zeros() + fn count_zeros(self: Simd) -> Simd { + self.cast::().count_zeros() } #[inline] - fn leading_zeros(self) -> Simd { - self.cast::().leading_zeros() + fn leading_zeros(self: Simd) -> Simd { + self.cast::().leading_zeros() } #[inline] - fn trailing_zeros(self) -> Simd { - self.cast::().trailing_zeros() + fn trailing_zeros(self: Simd) -> Simd { + self.cast::().trailing_zeros() } #[inline] - fn leading_ones(self) -> Simd { - self.cast::().leading_ones() + fn leading_ones(self: Simd) -> Simd { + self.cast::().leading_ones() } #[inline] - fn trailing_ones(self) -> Simd { - self.cast::().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 ae4e98e469a..8b05b422b13 100644 --- a/crates/core_simd/src/simd/num/uint.rs +++ b/crates/core_simd/src/simd/num/uint.rs @@ -2,10 +2,7 @@ use super::sealed::Sealed; use crate::simd::{Simd, SimdCast, SimdElement, cmp::SimdOrd}; /// Operations on SIMD vectors of unsigned integers. -pub trait SimdUint: Copy + Sealed -where - T: SimdElement, -{ +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. @@ -13,13 +10,13 @@ where /// 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) -> Simd; + 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. /// @@ -37,7 +34,7 @@ where /// 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. /// @@ -55,7 +52,7 @@ where /// 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`. @@ -71,178 +68,187 @@ where /// 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) -> T; + fn reduce_sum(self: Simd) -> Self; /// Returns the product of the elements of the vector, with wrapping multiplication. - fn reduce_product(self) -> T; + fn reduce_product(self: Simd) -> Self; /// Returns the maximum element in the vector. - fn reduce_max(self) -> T; + fn reduce_max(self: Simd) -> Self; /// Returns the minimum element in the vector. - fn reduce_min(self) -> T; + fn reduce_min(self: Simd) -> Self; /// Returns the cumulative bitwise "and" across the elements of the vector. - fn reduce_and(self) -> T; + fn reduce_and(self: Simd) -> Self; /// Returns the cumulative bitwise "or" across the elements of the vector. - fn reduce_or(self) -> T; + fn reduce_or(self: Simd) -> Self; /// Returns the cumulative bitwise "xor" across the elements of the vector. - fn reduce_xor(self) -> T; + 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<$ty, N> for Simd<$ty, N> { + impl SimdUint for $ty { type Signed = $signed; #[inline] - fn cast(self) -> Simd { + 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::()).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) -> $ty { + 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) -> $ty { + 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) -> $ty { + 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) -> $ty { + 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) -> $ty { + 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) -> $ty { + 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) -> $ty { + 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 ad88488e0d1..b99f1fefe09 100644 --- a/crates/core_simd/src/simd/ptr/const_ptr.rs +++ b/crates/core_simd/src/simd/ptr/const_ptr.rs @@ -1,30 +1,35 @@ 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 { +pub trait SimdConstPtr: SimdElement + Copy + Sealed { + /// The pointee type referenced by these pointers. + type Pointee: core::ptr::Pointee; + /// Returns `true` for each element that is null. - fn is_null(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) -> Simd<*const U, N>; + fn cast(self: Simd) -> Simd<*const U, N> + where + U: core::ptr::Pointee; /// Changes constness without changing the type. /// /// Equivalent to calling [`pointer::cast_mut`] on each element. - fn cast_mut(self) -> Simd<*mut T, N>; + 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) -> Simd; + 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: Simd) -> 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. @@ -32,34 +37,43 @@ 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) -> Simd; + 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: Simd) -> 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: Simd) -> 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: Simd) -> Self; + fn wrapping_sub(self: Simd, count: Simd) -> Simd; } -impl Sealed for Simd<*const T, N> {} +impl SimdConstPtr for *const T +where + T: core::ptr::Pointee, +{ + type Pointee = T; -impl SimdConstPtr for Simd<*const T, N> { #[inline] - fn is_null(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) -> Simd<*const U, N> { + fn cast(self: Simd) -> Simd<*const U, N> + where + U: core::ptr::Pointee, + { // 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; @@ -71,13 +85,13 @@ impl SimdConstPtr for Simd<*const T, N> { } #[inline] - fn cast_mut(self) -> Simd<*mut T, N> { + 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) -> Simd { + 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). @@ -85,36 +99,39 @@ impl SimdConstPtr for Simd<*const T, N> { } #[inline] - fn with_addr(self, addr: Simd) -> 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) -> Simd { + 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: Simd) -> 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: Simd) -> Self { + fn wrapping_add(self: Simd, count: Simd) -> Simd { self.wrapping_offset(count.cast()) } #[inline] - fn wrapping_sub(self, count: Simd) -> 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 e5195b41b96..c95a4a7ed76 100644 --- a/crates/core_simd/src/simd/ptr/mut_ptr.rs +++ b/crates/core_simd/src/simd/ptr/mut_ptr.rs @@ -1,30 +1,35 @@ 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 { +pub trait SimdMutPtr: SimdElement + Copy + Sealed { + /// The pointee type referenced by these pointers. + type Pointee: core::ptr::Pointee; + /// Returns `true` for each element that is null. - fn is_null(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) -> Simd<*mut U, N>; + fn cast(self: Simd) -> Simd<*mut U, N> + where + U: core::ptr::Pointee; /// Changes constness without changing the type. /// /// Equivalent to calling [`pointer::cast_const`] on each element. - fn cast_const(self) -> Simd<*const T, N>; + 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) -> Simd; + 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: Simd) -> 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. @@ -32,34 +37,43 @@ 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) -> Simd; + 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: Simd) -> 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: Simd) -> 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: Simd) -> Self; + fn wrapping_sub(self: Simd, count: Simd) -> Simd; } -impl Sealed for Simd<*mut T, N> {} +impl SimdMutPtr for *mut T +where + T: core::ptr::Pointee, +{ + type Pointee = T; -impl SimdMutPtr for Simd<*mut T, N> { #[inline] - fn is_null(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) -> Simd<*mut U, N> { + fn cast(self: Simd) -> Simd<*mut U, N> + where + U: core::ptr::Pointee, + { // 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; @@ -71,13 +85,13 @@ impl SimdMutPtr for Simd<*mut T, N> { } #[inline] - fn cast_const(self) -> Simd<*const T, N> { + 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) -> Simd { + 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). @@ -85,36 +99,39 @@ impl SimdMutPtr for Simd<*mut T, N> { } #[inline] - fn with_addr(self, addr: Simd) -> 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) -> Simd { + 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: Simd) -> 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: Simd) -> Self { + fn wrapping_add(self: Simd, count: Simd) -> Simd { self.wrapping_offset(count.cast()) } #[inline] - fn wrapping_sub(self, count: Simd) -> 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 927c9c7c6c8..a2ecc643f56 100644 --- a/crates/core_simd/src/to_bytes.rs +++ b/crates/core_simd/src/to_bytes.rs @@ -39,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 } => { ::from_bits($x.to_bits().swap_bytes()) }; + { f64, $x:expr } => { ::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..b559ff7a887 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, 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()) { From 300d6bfffa257720005cac0f5c562c3085a2ae5d Mon Sep 17 00:00:00 2001 From: Caleb Zulawski Date: Sat, 9 May 2026 12:50:28 -0400 Subject: [PATCH 3/6] Rename from_bits to simd_from_bits to disambiguate from scalar function --- crates/core_simd/src/simd/num/float.rs | 6 +++--- crates/core_simd/src/to_bytes.rs | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/crates/core_simd/src/simd/num/float.rs b/crates/core_simd/src/simd/num/float.rs index 31802528a9f..38c39e8238c 100644 --- a/crates/core_simd/src/simd/num/float.rs +++ b/crates/core_simd/src/simd/num/float.rs @@ -60,7 +60,7 @@ pub trait SimdFloat: SimdElement + Copy + Sealed { /// 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: Simd) -> Simd; + fn simd_from_bits(bits: Simd) -> Simd; /// Produces a vector where every element has the absolute value of the /// equivalently-indexed element in `self`. @@ -295,7 +295,7 @@ macro_rules! impl_trait { } #[inline] - fn from_bits(bits: Simd) -> Simd { + 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) } @@ -371,7 +371,7 @@ macro_rules! impl_trait { 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(); - ::from_bits(sign_bit | magnitude) + ::simd_from_bits(sign_bit | magnitude) } #[inline] diff --git a/crates/core_simd/src/to_bytes.rs b/crates/core_simd/src/to_bytes.rs index a2ecc643f56..a645d83e145 100644 --- a/crates/core_simd/src/to_bytes.rs +++ b/crates/core_simd/src/to_bytes.rs @@ -39,8 +39,8 @@ pub trait ToBytes: Sealed { } macro_rules! swap_bytes { - { f32, $x:expr } => { ::from_bits($x.to_bits().swap_bytes()) }; - { f64, $x:expr } => { ::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() } } From 8fd81fe801590669a38341e452fb99422f755027 Mon Sep 17 00:00:00 2001 From: Caleb Zulawski Date: Sat, 9 May 2026 12:52:40 -0400 Subject: [PATCH 4/6] Remove workaround for LLVM <20 --- crates/core_simd/src/simd/num/float.rs | 28 -------------------------- 1 file changed, 28 deletions(-) diff --git a/crates/core_simd/src/simd/num/float.rs b/crates/core_simd/src/simd/num/float.rs index 38c39e8238c..01d1db4fd2d 100644 --- a/crates/core_simd/src/simd/num/float.rs +++ b/crates/core_simd/src/simd/num/float.rs @@ -243,40 +243,12 @@ macro_rules! impl_trait { impl SimdFloat for $ty { type Bits = $bits_ty; - #[cfg(not(target_arch = "aarch64"))] #[inline] 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: Simd) -> Simd { - 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: Simd) -> Simd From e9c3147ca83dff9570fc0ad593f9ad41be1f6696 Mon Sep 17 00:00:00 2001 From: Caleb Zulawski Date: Sat, 9 May 2026 13:04:33 -0400 Subject: [PATCH 5/6] Remove unnecessary Pointee bound implied by implicit Sized bound --- crates/core_simd/src/simd/ptr/const_ptr.rs | 16 ++++------------ crates/core_simd/src/simd/ptr/mut_ptr.rs | 16 ++++------------ crates/core_simd/src/vector.rs | 10 ++-------- 3 files changed, 10 insertions(+), 32 deletions(-) diff --git a/crates/core_simd/src/simd/ptr/const_ptr.rs b/crates/core_simd/src/simd/ptr/const_ptr.rs index b99f1fefe09..01e024eca7e 100644 --- a/crates/core_simd/src/simd/ptr/const_ptr.rs +++ b/crates/core_simd/src/simd/ptr/const_ptr.rs @@ -4,7 +4,7 @@ use crate::simd::{Mask, Simd, SimdElement, cmp::SimdPartialEq, num::SimdUint}; /// Operations on SIMD vectors of constant pointers. pub trait SimdConstPtr: SimdElement + Copy + Sealed { /// The pointee type referenced by these pointers. - type Pointee: core::ptr::Pointee; + type Pointee; /// Returns `true` for each element that is null. fn is_null(self: Simd) -> Mask; @@ -12,9 +12,7 @@ pub trait SimdConstPtr: SimdElement + Copy + Sealed { /// Casts to a pointer of another type. /// /// Equivalent to calling [`pointer::cast`] on each element. - fn cast(self: Simd) -> Simd<*const U, N> - where - U: core::ptr::Pointee; + fn cast(self: Simd) -> Simd<*const U, N>; /// Changes constness without changing the type. /// @@ -58,10 +56,7 @@ pub trait SimdConstPtr: SimdElement + Copy + Sealed { fn wrapping_sub(self: Simd, count: Simd) -> Simd; } -impl SimdConstPtr for *const T -where - T: core::ptr::Pointee, -{ +impl SimdConstPtr for *const T { type Pointee = T; #[inline] @@ -70,10 +65,7 @@ where } #[inline] - fn cast(self: Simd) -> Simd<*const U, N> - where - U: core::ptr::Pointee, - { + 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; diff --git a/crates/core_simd/src/simd/ptr/mut_ptr.rs b/crates/core_simd/src/simd/ptr/mut_ptr.rs index c95a4a7ed76..c2f93e88638 100644 --- a/crates/core_simd/src/simd/ptr/mut_ptr.rs +++ b/crates/core_simd/src/simd/ptr/mut_ptr.rs @@ -4,7 +4,7 @@ use crate::simd::{Mask, Simd, SimdElement, cmp::SimdPartialEq, num::SimdUint}; /// Operations on SIMD vectors of mutable pointers. pub trait SimdMutPtr: SimdElement + Copy + Sealed { /// The pointee type referenced by these pointers. - type Pointee: core::ptr::Pointee; + type Pointee; /// Returns `true` for each element that is null. fn is_null(self: Simd) -> Mask; @@ -12,9 +12,7 @@ pub trait SimdMutPtr: SimdElement + Copy + Sealed { /// Casts to a pointer of another type. /// /// Equivalent to calling [`pointer::cast`] on each element. - fn cast(self: Simd) -> Simd<*mut U, N> - where - U: core::ptr::Pointee; + fn cast(self: Simd) -> Simd<*mut U, N>; /// Changes constness without changing the type. /// @@ -58,10 +56,7 @@ pub trait SimdMutPtr: SimdElement + Copy + Sealed { fn wrapping_sub(self: Simd, count: Simd) -> Simd; } -impl SimdMutPtr for *mut T -where - T: core::ptr::Pointee, -{ +impl SimdMutPtr for *mut T { type Pointee = T; #[inline] @@ -70,10 +65,7 @@ where } #[inline] - fn cast(self: Simd) -> Simd<*mut U, N> - where - U: core::ptr::Pointee, - { + 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; diff --git a/crates/core_simd/src/vector.rs b/crates/core_simd/src/vector.rs index b559ff7a887..6c84847730e 100644 --- a/crates/core_simd/src/vector.rs +++ b/crates/core_simd/src/vector.rs @@ -1179,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; } @@ -1191,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; } From 71b9f6c90fe9450935440ab68a9fd35930069e1e Mon Sep 17 00:00:00 2001 From: Caleb Zulawski Date: Wed, 13 May 2026 21:00:42 -0400 Subject: [PATCH 6/6] Simplify simd_from_bits invocation now that it's not ambiguous Co-authored-by: Jacob Lifshay --- crates/core_simd/src/simd/num/float.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/core_simd/src/simd/num/float.rs b/crates/core_simd/src/simd/num/float.rs index 01d1db4fd2d..f1f62d4586e 100644 --- a/crates/core_simd/src/simd/num/float.rs +++ b/crates/core_simd/src/simd/num/float.rs @@ -343,7 +343,7 @@ macro_rules! impl_trait { 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(); - ::simd_from_bits(sign_bit | magnitude) + Self::simd_from_bits(sign_bit | magnitude) } #[inline]