about summary refs log tree commit diff
diff options
context:
space:
mode:
authorCaleb Zulawski <caleb.zulawski@gmail.com>2022-04-15 01:44:18 -0400
committerCaleb Zulawski <caleb.zulawski@gmail.com>2022-04-15 02:11:16 -0400
commit04be48ff97757a803e934ab8d2e90631b59557f8 (patch)
tree3098f69c514184433f2732d8ad4c44eb24012b82
parent376957ad8cac70a85c08a26a147eb534d5cee380 (diff)
downloadrust-04be48ff97757a803e934ab8d2e90631b59557f8.tar.gz
rust-04be48ff97757a803e934ab8d2e90631b59557f8.zip
Add float trait, and seal traits.
-rw-r--r--crates/core_simd/src/elements.rs6
-rw-r--r--crates/core_simd/src/elements/float.rs344
-rw-r--r--crates/core_simd/src/elements/int.rs9
-rw-r--r--crates/core_simd/src/elements/uint.rs9
-rw-r--r--crates/core_simd/src/mod.rs3
-rw-r--r--crates/core_simd/src/reduction.rs127
-rw-r--r--crates/core_simd/src/vector/float.rs211
-rw-r--r--crates/core_simd/tests/ops_macros.rs4
8 files changed, 368 insertions, 345 deletions
diff --git a/crates/core_simd/src/elements.rs b/crates/core_simd/src/elements.rs
index 0fb1f5b9fe9..701eb66b248 100644
--- a/crates/core_simd/src/elements.rs
+++ b/crates/core_simd/src/elements.rs
@@ -1,5 +1,11 @@
+mod float;
 mod int;
 mod uint;
 
+mod sealed {
+    pub trait Sealed {}
+}
+
+pub use float::*;
 pub use int::*;
 pub use uint::*;
diff --git a/crates/core_simd/src/elements/float.rs b/crates/core_simd/src/elements/float.rs
new file mode 100644
index 00000000000..fafbd2a4d21
--- /dev/null
+++ b/crates/core_simd/src/elements/float.rs
@@ -0,0 +1,344 @@
+use super::sealed::Sealed;
+use crate::simd::{
+    intrinsics, LaneCount, Mask, Simd, SimdElement, SimdPartialEq, SimdPartialOrd,
+    SupportedLaneCount,
+};
+
+/// Operations on SIMD vectors of floats.
+pub trait SimdFloat: Sized + Sealed {
+    /// Mask type used for manipulating this SIMD vector type.
+    type Mask;
+
+    /// Scalar type contained by this SIMD vector type.
+    type Scalar;
+
+    /// Bit representation of this SIMD vector type.
+    type Bits;
+
+    /// Raw transmutation to an unsigned integer vector type with the
+    /// same size and number of lanes.
+    #[must_use = "method returns a new vector and does not mutate the original value"]
+    fn to_bits(self) -> Self::Bits;
+
+    /// Raw transmutation from an unsigned integer vector type with the
+    /// same size and number of lanes.
+    #[must_use = "method returns a new vector and does not mutate the original value"]
+    fn from_bits(bits: Self::Bits) -> Self;
+
+    /// Produces a vector where every lane has the absolute value of the
+    /// equivalently-indexed lane in `self`.
+    #[must_use = "method returns a new vector and does not mutate the original value"]
+    fn abs(self) -> Self;
+
+    /// Takes the reciprocal (inverse) of each lane, `1/x`.
+    #[must_use = "method returns a new vector and does not mutate the original value"]
+    fn recip(self) -> Self;
+
+    /// Converts each lane from radians to degrees.
+    #[must_use = "method returns a new vector and does not mutate the original value"]
+    fn to_degrees(self) -> Self;
+
+    /// Converts each lane from degrees to radians.
+    #[must_use = "method returns a new vector and does not mutate the original value"]
+    fn to_radians(self) -> Self;
+
+    /// Returns true for each lane 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;
+
+    /// Returns true for each lane 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;
+
+    /// Returns true for each lane 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;
+
+    /// Returns true for each lane 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;
+
+    /// Returns true for each lane 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;
+
+    /// Returns true for each lane 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;
+
+    /// Returns true for each lane 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;
+
+    /// Replaces each lane with a number that represents its sign.
+    ///
+    /// * `1.0` if the number is positive, `+0.0`, or `INFINITY`
+    /// * `-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;
+
+    /// Returns each lane with the magnitude of `self` and the sign of `sign`.
+    ///
+    /// If any lane is a `NAN`, then 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;
+
+    /// Returns the minimum of each lane.
+    ///
+    /// 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;
+
+    /// Returns the maximum of each lane.
+    ///
+    /// 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;
+
+    /// Restrict each lane to a certain interval unless it is NaN.
+    ///
+    /// For each lane in `self`, returns the corresponding lane in `max` if the lane is
+    /// greater than `max`, and the corresponding lane in `min` if the lane is less
+    /// than `min`.  Otherwise returns the lane 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;
+
+    /// Returns the sum of the lanes of the vector.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # #![feature(portable_simd)]
+    /// # use core::simd::f32x2;
+    /// let v = f32x2::from_array([1., 2.]);
+    /// assert_eq!(v.reduce_sum(), 3.);
+    /// ```
+    fn reduce_sum(self) -> Self::Scalar;
+
+    /// Reducing multiply.  Returns the product of the lanes of the vector.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # #![feature(portable_simd)]
+    /// # use core::simd::f32x2;
+    /// let v = f32x2::from_array([3., 4.]);
+    /// assert_eq!(v.reduce_product(), 12.);
+    /// ```
+    fn reduce_product(self) -> Self::Scalar;
+
+    /// Returns the maximum lane in the vector.
+    ///
+    /// Returns values based on equality, so a vector containing both `0.` and `-0.` may
+    /// return either.
+    ///
+    /// This function will not return `NaN` unless all lanes are `NaN`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # #![feature(portable_simd)]
+    /// # use core::simd::f32x2;
+    /// let v = f32x2::from_array([1., 2.]);
+    /// assert_eq!(v.reduce_max(), 2.);
+    ///
+    /// // NaN values are skipped...
+    /// let v = f32x2::from_array([1., f32::NAN]);
+    /// assert_eq!(v.reduce_max(), 1.);
+    ///
+    /// // ...unless all values are NaN
+    /// let v = f32x2::from_array([f32::NAN, f32::NAN]);
+    /// assert!(v.reduce_max().is_nan());
+    /// ```
+    fn reduce_max(self) -> Self::Scalar;
+
+    /// Returns the minimum lane in the vector.
+    ///
+    /// Returns values based on equality, so a vector containing both `0.` and `-0.` may
+    /// return either.
+    ///
+    /// This function will not return `NaN` unless all lanes are `NaN`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # #![feature(portable_simd)]
+    /// # use core::simd::f32x2;
+    /// let v = f32x2::from_array([3., 7.]);
+    /// assert_eq!(v.reduce_min(), 3.);
+    ///
+    /// // NaN values are skipped...
+    /// let v = f32x2::from_array([1., f32::NAN]);
+    /// assert_eq!(v.reduce_min(), 1.);
+    ///
+    /// // ...unless all values are NaN
+    /// let v = f32x2::from_array([f32::NAN, f32::NAN]);
+    /// assert!(v.reduce_min().is_nan());
+    /// ```
+    fn reduce_min(self) -> Self::Scalar;
+}
+
+macro_rules! impl_trait {
+    { $($ty:ty { bits: $bits_ty:ty, mask: $mask_ty:ty }),* } => {
+        $(
+        impl<const LANES: usize> Sealed for Simd<$ty, LANES>
+        where
+            LaneCount<LANES>: SupportedLaneCount,
+        {
+        }
+
+        impl<const LANES: usize> SimdFloat for Simd<$ty, LANES>
+        where
+            LaneCount<LANES>: SupportedLaneCount,
+        {
+            type Mask = Mask<<$mask_ty as SimdElement>::Mask, LANES>;
+            type Scalar = $ty;
+            type Bits = Simd<$bits_ty, LANES>;
+
+            #[inline]
+            fn to_bits(self) -> Simd<$bits_ty, LANES> {
+                assert_eq!(core::mem::size_of::<Self>(), core::mem::size_of::<Self::Bits>());
+                unsafe { core::mem::transmute_copy(&self) }
+            }
+
+            #[inline]
+            fn from_bits(bits: Simd<$bits_ty, LANES>) -> Self {
+                assert_eq!(core::mem::size_of::<Self>(), core::mem::size_of::<Self::Bits>());
+                unsafe { core::mem::transmute_copy(&bits) }
+            }
+
+            #[inline]
+            fn abs(self) -> Self {
+                unsafe { intrinsics::simd_fabs(self) }
+            }
+
+            #[inline]
+            fn recip(self) -> Self {
+                Self::splat(1.0) / self
+            }
+
+            #[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.))
+            }
+
+            #[inline]
+            fn to_radians(self) -> Self {
+                self * Self::splat(Self::Scalar::to_radians(1.))
+            }
+
+            #[inline]
+            fn is_sign_positive(self) -> Self::Mask {
+                !self.is_sign_negative()
+            }
+
+            #[inline]
+            fn is_sign_negative(self) -> Self::Mask {
+                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 {
+                self.simd_ne(self)
+            }
+
+            #[inline]
+            fn is_infinite(self) -> Self::Mask {
+                self.abs().simd_eq(Self::splat(Self::Scalar::INFINITY))
+            }
+
+            #[inline]
+            fn is_finite(self) -> Self::Mask {
+                self.abs().simd_lt(Self::splat(Self::Scalar::INFINITY))
+            }
+
+            #[inline]
+            fn is_subnormal(self) -> Self::Mask {
+                self.abs().simd_ne(Self::splat(0.0)) & (self.to_bits() & Self::splat(Self::Scalar::INFINITY).to_bits()).simd_eq(Simd::splat(0))
+            }
+
+            #[inline]
+            #[must_use = "method returns a new mask and does not mutate the original value"]
+            fn is_normal(self) -> Self::Mask {
+                !(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))
+            }
+
+            #[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)
+            }
+
+            #[inline]
+            fn simd_min(self, other: Self) -> Self {
+                unsafe { intrinsics::simd_fmin(self, other) }
+            }
+
+            #[inline]
+            fn simd_max(self, other: Self) -> Self {
+                unsafe { intrinsics::simd_fmax(self, other) }
+            }
+
+            #[inline]
+            fn simd_clamp(self, min: Self, max: Self) -> Self {
+                assert!(
+                    min.simd_le(max).all(),
+                    "each lane in `min` must be less than or equal to the corresponding lane in `max`",
+                );
+                let mut x = self;
+                x = x.simd_lt(min).select(min, x);
+                x = x.simd_gt(max).select(max, x);
+                x
+            }
+
+            #[inline]
+            fn reduce_sum(self) -> Self::Scalar {
+                // LLVM sum is inaccurate on i586
+                if cfg!(all(target_arch = "x86", not(target_feature = "sse2"))) {
+                    self.as_array().iter().sum()
+                } else {
+                    // Safety: `self` is a float vector
+                    unsafe { intrinsics::simd_reduce_add_ordered(self, 0.) }
+                }
+            }
+
+            #[inline]
+            fn reduce_product(self) -> Self::Scalar {
+                // LLVM product is inaccurate on i586
+                if cfg!(all(target_arch = "x86", not(target_feature = "sse2"))) {
+                    self.as_array().iter().product()
+                } else {
+                    // Safety: `self` is a float vector
+                    unsafe { intrinsics::simd_reduce_mul_ordered(self, 1.) }
+                }
+            }
+
+            #[inline]
+            fn reduce_max(self) -> Self::Scalar {
+                // Safety: `self` is a float vector
+                unsafe { intrinsics::simd_reduce_max(self) }
+            }
+
+            #[inline]
+            fn reduce_min(self) -> Self::Scalar {
+                // Safety: `self` is a float vector
+                unsafe { intrinsics::simd_reduce_min(self) }
+            }
+        }
+        )*
+    }
+}
+
+impl_trait! { f32 { bits: u32, mask: i32 }, f64 { bits: u64, mask: i64 } }
diff --git a/crates/core_simd/src/elements/int.rs b/crates/core_simd/src/elements/int.rs
index 61135427456..c3139b4ba3e 100644
--- a/crates/core_simd/src/elements/int.rs
+++ b/crates/core_simd/src/elements/int.rs
@@ -1,9 +1,10 @@
+use super::sealed::Sealed;
 use crate::simd::{
     intrinsics, LaneCount, Mask, Simd, SimdElement, SimdPartialOrd, SupportedLaneCount,
 };
 
 /// Operations on SIMD vectors of signed integers.
-pub trait SimdInt: Sized {
+pub trait SimdInt: Sized + Sealed {
     /// Mask type used for manipulating this SIMD vector type.
     type Mask;
 
@@ -167,6 +168,12 @@ pub trait SimdInt: Sized {
 macro_rules! impl_trait {
     { $($ty:ty),* } => {
         $(
+        impl<const LANES: usize> Sealed for Simd<$ty, LANES>
+        where
+            LaneCount<LANES>: SupportedLaneCount,
+        {
+        }
+
         impl<const LANES: usize> SimdInt for Simd<$ty, LANES>
         where
             LaneCount<LANES>: SupportedLaneCount,
diff --git a/crates/core_simd/src/elements/uint.rs b/crates/core_simd/src/elements/uint.rs
index da3213535a3..cba1a9b0ce0 100644
--- a/crates/core_simd/src/elements/uint.rs
+++ b/crates/core_simd/src/elements/uint.rs
@@ -1,7 +1,8 @@
+use super::sealed::Sealed;
 use crate::simd::{intrinsics, LaneCount, Simd, SupportedLaneCount};
 
 /// Operations on SIMD vectors of unsigned integers.
-pub trait SimdUint: Sized {
+pub trait SimdUint: Sized + Sealed {
     /// Scalar type contained by this SIMD vector type.
     type Scalar;
 
@@ -61,6 +62,12 @@ pub trait SimdUint: Sized {
 macro_rules! impl_trait {
     { $($ty:ty),* } => {
         $(
+        impl<const LANES: usize> Sealed for Simd<$ty, LANES>
+        where
+            LaneCount<LANES>: SupportedLaneCount,
+        {
+        }
+
         impl<const LANES: usize> SimdUint for Simd<$ty, LANES>
         where
             LaneCount<LANES>: SupportedLaneCount,
diff --git a/crates/core_simd/src/mod.rs b/crates/core_simd/src/mod.rs
index 2d4fe2b7fde..590b2e4a153 100644
--- a/crates/core_simd/src/mod.rs
+++ b/crates/core_simd/src/mod.rs
@@ -1,7 +1,4 @@
 #[macro_use]
-mod reduction;
-
-#[macro_use]
 mod swizzle;
 
 pub(crate) mod intrinsics;
diff --git a/crates/core_simd/src/reduction.rs b/crates/core_simd/src/reduction.rs
deleted file mode 100644
index 9d8639feeee..00000000000
--- a/crates/core_simd/src/reduction.rs
+++ /dev/null
@@ -1,127 +0,0 @@
-use crate::simd::intrinsics::{
-    simd_reduce_add_ordered, simd_reduce_max, simd_reduce_min, simd_reduce_mul_ordered,
-};
-use crate::simd::{LaneCount, Simd, SupportedLaneCount};
-
-macro_rules! impl_float_reductions {
-    { $scalar:ty } => {
-        impl<const LANES: usize> Simd<$scalar, LANES>
-        where
-            LaneCount<LANES>: SupportedLaneCount,
-        {
-
-            /// Reducing add.  Returns the sum of the lanes of the vector.
-            ///
-            /// # Examples
-            ///
-            /// ```
-            /// # #![feature(portable_simd)]
-            /// # use core::simd::Simd;
-            #[doc = concat!("# use core::simd::", stringify!($scalar), "x2;")]
-            #[doc = concat!("let v = ", stringify!($scalar), "x2::from_array([1., 2.]);")]
-            /// assert_eq!(v.reduce_sum(), 3.);
-            /// ```
-            #[inline]
-            pub fn reduce_sum(self) -> $scalar {
-                // LLVM sum is inaccurate on i586
-                if cfg!(all(target_arch = "x86", not(target_feature = "sse2"))) {
-                    self.as_array().iter().sum()
-                } else {
-                    // Safety: `self` is a float vector
-                    unsafe { simd_reduce_add_ordered(self, 0.) }
-                }
-            }
-
-            /// Reducing multiply.  Returns the product of the lanes of the vector.
-            ///
-            /// # Examples
-            ///
-            /// ```
-            /// # #![feature(portable_simd)]
-            /// # use core::simd::Simd;
-            #[doc = concat!("# use core::simd::", stringify!($scalar), "x2;")]
-            #[doc = concat!("let v = ", stringify!($scalar), "x2::from_array([3., 4.]);")]
-            /// assert_eq!(v.reduce_product(), 12.);
-            /// ```
-            #[inline]
-            pub fn reduce_product(self) -> $scalar {
-                // LLVM product is inaccurate on i586
-                if cfg!(all(target_arch = "x86", not(target_feature = "sse2"))) {
-                    self.as_array().iter().product()
-                } else {
-                    // Safety: `self` is a float vector
-                    unsafe { simd_reduce_mul_ordered(self, 1.) }
-                }
-            }
-
-            /// Reducing maximum.  Returns the maximum lane in the vector.
-            ///
-            /// Returns values based on equality, so a vector containing both `0.` and `-0.` may
-            /// return either.
-            ///
-            /// This function will not return `NaN` unless all lanes are `NaN`.
-            ///
-            /// # Examples
-            ///
-            /// ```
-            /// # #![feature(portable_simd)]
-            /// # use core::simd::Simd;
-            #[doc = concat!("# use core::simd::", stringify!($scalar), "x2;")]
-            #[doc = concat!("let v = ", stringify!($scalar), "x2::from_array([1., 2.]);")]
-            /// assert_eq!(v.reduce_max(), 2.);
-            ///
-            /// // NaN values are skipped...
-            #[doc = concat!("let v = ", stringify!($scalar), "x2::from_array([1., ", stringify!($scalar), "::NAN]);")]
-            /// assert_eq!(v.reduce_max(), 1.);
-            ///
-            /// // ...unless all values are NaN
-            #[doc = concat!("let v = ", stringify!($scalar), "x2::from_array([",
-                stringify!($scalar), "::NAN, ",
-                stringify!($scalar), "::NAN]);"
-            )]
-            /// assert!(v.reduce_max().is_nan());
-            /// ```
-            #[inline]
-            pub fn reduce_max(self) -> $scalar {
-                // Safety: `self` is a float vector
-                unsafe { simd_reduce_max(self) }
-            }
-
-            /// Reducing minimum.  Returns the minimum lane in the vector.
-            ///
-            /// Returns values based on equality, so a vector containing both `0.` and `-0.` may
-            /// return either.
-            ///
-            /// This function will not return `NaN` unless all lanes are `NaN`.
-            ///
-            /// # Examples
-            ///
-            /// ```
-            /// # #![feature(portable_simd)]
-            /// # use core::simd::Simd;
-            #[doc = concat!("# use core::simd::", stringify!($scalar), "x2;")]
-            #[doc = concat!("let v = ", stringify!($scalar), "x2::from_array([3., 7.]);")]
-            /// assert_eq!(v.reduce_min(), 3.);
-            ///
-            /// // NaN values are skipped...
-            #[doc = concat!("let v = ", stringify!($scalar), "x2::from_array([1., ", stringify!($scalar), "::NAN]);")]
-            /// assert_eq!(v.reduce_min(), 1.);
-            ///
-            /// // ...unless all values are NaN
-            #[doc = concat!("let v = ", stringify!($scalar), "x2::from_array([",
-                stringify!($scalar), "::NAN, ",
-                stringify!($scalar), "::NAN]);"
-            )]
-            /// assert!(v.reduce_min().is_nan());
-            /// ```
-            #[inline]
-            pub fn reduce_min(self) -> $scalar {
-                // Safety: `self` is a float vector
-                unsafe { simd_reduce_min(self) }
-            }
-        }
-    }
-}
-
-impl_float_reductions! { f32 }
-impl_float_reductions! { f64 }
diff --git a/crates/core_simd/src/vector/float.rs b/crates/core_simd/src/vector/float.rs
index 13b1d3995a1..f836c99b1e2 100644
--- a/crates/core_simd/src/vector/float.rs
+++ b/crates/core_simd/src/vector/float.rs
@@ -1,145 +1,6 @@
 #![allow(non_camel_case_types)]
 
-use crate::simd::intrinsics;
-use crate::simd::{LaneCount, Mask, Simd, SimdPartialEq, SimdPartialOrd, SupportedLaneCount};
-
-/// Implements inherent methods for a float vector containing multiple
-/// `$lanes` of float `$type`, which uses `$bits_ty` as its binary
-/// representation.
-macro_rules! impl_float_vector {
-    { $type:ty, $bits_ty:ty, $mask_ty:ty } => {
-        impl<const LANES: usize> Simd<$type, LANES>
-        where
-            LaneCount<LANES>: SupportedLaneCount,
-        {
-            /// Raw transmutation to an unsigned integer vector type with the
-            /// same size and number of lanes.
-            #[inline]
-            #[must_use = "method returns a new vector and does not mutate the original value"]
-            pub fn to_bits(self) -> Simd<$bits_ty, LANES> {
-                assert_eq!(core::mem::size_of::<Self>(), core::mem::size_of::<Simd<$bits_ty, LANES>>());
-                unsafe { core::mem::transmute_copy(&self) }
-            }
-
-            /// Raw transmutation from an unsigned integer vector type with the
-            /// same size and number of lanes.
-            #[inline]
-            #[must_use = "method returns a new vector and does not mutate the original value"]
-            pub fn from_bits(bits: Simd<$bits_ty, LANES>) -> Self {
-                assert_eq!(core::mem::size_of::<Self>(), core::mem::size_of::<Simd<$bits_ty, LANES>>());
-                unsafe { core::mem::transmute_copy(&bits) }
-            }
-
-            /// Produces a vector where every lane has the absolute value of the
-            /// equivalently-indexed lane in `self`.
-            #[inline]
-            #[must_use = "method returns a new vector and does not mutate the original value"]
-            pub fn abs(self) -> Self {
-                unsafe { intrinsics::simd_fabs(self) }
-            }
-
-            /// Takes the reciprocal (inverse) of each lane, `1/x`.
-            #[inline]
-            #[must_use = "method returns a new vector and does not mutate the original value"]
-            pub fn recip(self) -> Self {
-                Self::splat(1.0) / self
-            }
-
-            /// Converts each lane from radians to degrees.
-            #[inline]
-            #[must_use = "method returns a new vector and does not mutate the original value"]
-            pub fn to_degrees(self) -> Self {
-                // to_degrees uses a special constant for better precision, so extract that constant
-                self * Self::splat(<$type>::to_degrees(1.))
-            }
-
-            /// Converts each lane from degrees to radians.
-            #[inline]
-            #[must_use = "method returns a new vector and does not mutate the original value"]
-            pub fn to_radians(self) -> Self {
-                self * Self::splat(<$type>::to_radians(1.))
-            }
-
-            /// Returns true for each lane if it has a positive sign, including
-            /// `+0.0`, `NaN`s with positive sign bit and positive infinity.
-            #[inline]
-            #[must_use = "method returns a new mask and does not mutate the original value"]
-            pub fn is_sign_positive(self) -> Mask<$mask_ty, LANES> {
-                !self.is_sign_negative()
-            }
-
-            /// Returns true for each lane if it has a negative sign, including
-            /// `-0.0`, `NaN`s with negative sign bit and negative infinity.
-            #[inline]
-            #[must_use = "method returns a new mask and does not mutate the original value"]
-            pub fn is_sign_negative(self) -> Mask<$mask_ty, LANES> {
-                let sign_bits = self.to_bits() & Simd::splat((!0 >> 1) + 1);
-                sign_bits.simd_gt(Simd::splat(0))
-            }
-
-            /// Returns true for each lane if its value is `NaN`.
-            #[inline]
-            #[must_use = "method returns a new mask and does not mutate the original value"]
-            pub fn is_nan(self) -> Mask<$mask_ty, LANES> {
-                self.simd_ne(self)
-            }
-
-            /// Returns true for each lane if its value is positive infinity or negative infinity.
-            #[inline]
-            #[must_use = "method returns a new mask and does not mutate the original value"]
-            pub fn is_infinite(self) -> Mask<$mask_ty, LANES> {
-                self.abs().simd_eq(Self::splat(<$type>::INFINITY))
-            }
-
-            /// Returns true for each lane if its value is neither infinite nor `NaN`.
-            #[inline]
-            #[must_use = "method returns a new mask and does not mutate the original value"]
-            pub fn is_finite(self) -> Mask<$mask_ty, LANES> {
-                self.abs().simd_lt(Self::splat(<$type>::INFINITY))
-            }
-
-            /// Returns true for each lane if its value is subnormal.
-            #[inline]
-            #[must_use = "method returns a new mask and does not mutate the original value"]
-            pub fn is_subnormal(self) -> Mask<$mask_ty, LANES> {
-                self.abs().simd_ne(Self::splat(0.0)) & (self.to_bits() & Self::splat(<$type>::INFINITY).to_bits()).simd_eq(Simd::splat(0))
-            }
-
-            /// Returns true for each lane if its value is neither zero, infinite,
-            /// subnormal, nor `NaN`.
-            #[inline]
-            #[must_use = "method returns a new mask and does not mutate the original value"]
-            pub fn is_normal(self) -> Mask<$mask_ty, LANES> {
-                !(self.abs().simd_eq(Self::splat(0.0)) | self.is_nan() | self.is_subnormal() | self.is_infinite())
-            }
-
-            /// Replaces each lane with a number that represents its sign.
-            ///
-            /// * `1.0` if the number is positive, `+0.0`, or `INFINITY`
-            /// * `-1.0` if the number is negative, `-0.0`, or `NEG_INFINITY`
-            /// * `NAN` if the number is `NAN`
-            #[inline]
-            #[must_use = "method returns a new vector and does not mutate the original value"]
-            pub fn signum(self) -> Self {
-                self.is_nan().select(Self::splat(<$type>::NAN), Self::splat(1.0).copysign(self))
-            }
-
-            /// Returns each lane with the magnitude of `self` and the sign of `sign`.
-            ///
-            /// If any lane is a `NAN`, then a `NAN` with the sign of `sign` is returned.
-            #[inline]
-            #[must_use = "method returns a new vector and does not mutate the original value"]
-            pub 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)
-            }
-        }
-    };
-}
-
-impl_float_vector! { f32, u32, i32 }
-impl_float_vector! { f64, u64, i64 }
+use crate::simd::Simd;
 
 /// A 64-bit SIMD vector with two elements of type `f32`.
 pub type f32x2 = Simd<f32, 2>;
@@ -161,73 +22,3 @@ pub type f64x4 = Simd<f64, 4>;
 
 /// A 512-bit SIMD vector with eight elements of type `f64`.
 pub type f64x8 = Simd<f64, 8>;
-
-mod sealed {
-    pub trait Sealed {}
-}
-use sealed::Sealed;
-
-/// SIMD operations on vectors of floating point numbers.
-pub trait SimdFloat: Sized + Sealed {
-    /// Returns the minimum of each lane.
-    ///
-    /// 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;
-
-    /// Returns the maximum of each lane.
-    ///
-    /// 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;
-
-    /// Restrict each lane to a certain interval unless it is NaN.
-    ///
-    /// For each lane in `self`, returns the corresponding lane in `max` if the lane is
-    /// greater than `max`, and the corresponding lane in `min` if the lane is less
-    /// than `min`.  Otherwise returns the lane 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;
-}
-
-macro_rules! impl_simd_float {
-    { $($float:ty),* } => {
-        $(
-        impl <const LANES: usize> Sealed for Simd<$float, LANES>
-        where
-            LaneCount<LANES>: SupportedLaneCount,
-        {
-        }
-
-        impl <const LANES: usize> SimdFloat for Simd<$float, LANES>
-        where
-            LaneCount<LANES>: SupportedLaneCount,
-        {
-            #[inline]
-            #[must_use = "method returns a new vector and does not mutate the original value"]
-            fn simd_min(self, other: Self) -> Self {
-                unsafe { intrinsics::simd_fmin(self, other) }
-            }
-
-            #[inline]
-            fn simd_max(self, other: Self) -> Self {
-                unsafe { intrinsics::simd_fmax(self, other) }
-            }
-
-            #[inline]
-            fn simd_clamp(self, min: Self, max: Self) -> Self {
-                assert!(
-                    min.simd_le(max).all(),
-                    "each lane in `min` must be less than or equal to the corresponding lane in `max`",
-                );
-                let mut x = self;
-                x = x.simd_lt(min).select(min, x);
-                x = x.simd_gt(max).select(max, x);
-                x
-            }
-        }
-        )*
-    }
-}
-
-impl_simd_float! { f32, f64 }
diff --git a/crates/core_simd/tests/ops_macros.rs b/crates/core_simd/tests/ops_macros.rs
index 48c512be7d0..f759394d075 100644
--- a/crates/core_simd/tests/ops_macros.rs
+++ b/crates/core_simd/tests/ops_macros.rs
@@ -348,6 +348,7 @@ macro_rules! impl_unsigned_tests {
 macro_rules! impl_float_tests {
     { $scalar:tt, $int_scalar:tt } => {
         mod $scalar {
+            use core_simd::SimdFloat;
             type Vector<const LANES: usize> = core_simd::Simd<Scalar, LANES>;
             type Scalar = $scalar;
 
@@ -464,7 +465,6 @@ macro_rules! impl_float_tests {
                 }
 
                 fn simd_min<const LANES: usize>() {
-                    use core_simd::simd::SimdFloat;
                     // Regular conditions (both values aren't zero)
                     test_helpers::test_binary_elementwise(
                         &Vector::<LANES>::simd_min,
@@ -488,7 +488,6 @@ macro_rules! impl_float_tests {
                 }
 
                 fn simd_max<const LANES: usize>() {
-                    use core_simd::simd::SimdFloat;
                     // Regular conditions (both values aren't zero)
                     test_helpers::test_binary_elementwise(
                         &Vector::<LANES>::simd_max,
@@ -512,7 +511,6 @@ macro_rules! impl_float_tests {
                 }
 
                 fn simd_clamp<const LANES: usize>() {
-                    use core_simd::simd::SimdFloat;
                     test_helpers::test_3(&|value: [Scalar; LANES], mut min: [Scalar; LANES], mut max: [Scalar; LANES]| {
                         for (min, max) in min.iter_mut().zip(max.iter_mut()) {
                             if max < min {