about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJubilee <46493976+workingjubilee@users.noreply.github.com>2022-04-04 10:19:20 -0700
committerGitHub <noreply@github.com>2022-04-04 10:19:20 -0700
commit1ec010db2abd34bfc6c33b5df75fa80b238f3b58 (patch)
tree478fec9329754ac57ef09b9c48037925bd0e32e8
parentc2fbead43a3c61eb22d8ad31bda4d9e1b6ff6ab2 (diff)
parent60486e08ed58698c7b6c2b5cd62a9fbd9080bc2f (diff)
downloadrust-1ec010db2abd34bfc6c33b5df75fa80b238f3b58.tar.gz
rust-1ec010db2abd34bfc6c33b5df75fa80b238f3b58.zip
rust-lang/portable-simd#265: Move comparisons to traits
A simpler variant of rust-lang/portable-simd#206.

* Comparisons are moved to `SimdPartialEq`, `SimdPartialOrd`, and `SimdOrd`.  The function names are prefixed with `simd_` to disambiguate from the regular `PartialEq` etc functions.  With the functions on traits instead of `Simd` directly, shadowing the function names doesn't work very well.
* Floating point `Ord`-like functions are put into a `SimdFloat` trait.  The intention is that eventually (some time after this PR) all floating point functions will be moved from `Simd` to `SimdFloat`, and the same goes for future `SimdInt`/`SimdUint` traits.
-rw-r--r--crates/core_simd/src/comparisons.rs120
-rw-r--r--crates/core_simd/src/eq.rs73
-rw-r--r--crates/core_simd/src/masks.rs4
-rw-r--r--crates/core_simd/src/mod.rs5
-rw-r--r--crates/core_simd/src/ops.rs10
-rw-r--r--crates/core_simd/src/ord.rs213
-rw-r--r--crates/core_simd/src/vector.rs16
-rw-r--r--crates/core_simd/src/vector/float.rs120
-rw-r--r--crates/core_simd/src/vector/int.rs6
-rw-r--r--crates/core_simd/tests/i16_ops.rs27
-rw-r--r--crates/core_simd/tests/ops_macros.rs48
11 files changed, 412 insertions, 230 deletions
diff --git a/crates/core_simd/src/comparisons.rs b/crates/core_simd/src/comparisons.rs
deleted file mode 100644
index 7b0d0a6864b..00000000000
--- a/crates/core_simd/src/comparisons.rs
+++ /dev/null
@@ -1,120 +0,0 @@
-use crate::simd::intrinsics;
-use crate::simd::{LaneCount, Mask, Simd, SimdElement, SupportedLaneCount};
-
-impl<T, const LANES: usize> Simd<T, LANES>
-where
-    T: SimdElement + PartialEq,
-    LaneCount<LANES>: SupportedLaneCount,
-{
-    /// Test if each lane is equal to the corresponding lane in `other`.
-    #[inline]
-    #[must_use = "method returns a new mask and does not mutate the original value"]
-    pub fn lanes_eq(self, other: Self) -> Mask<T::Mask, LANES> {
-        // Safety: `self` is a vector, and the result of the comparison
-        // is always a valid mask.
-        unsafe { Mask::from_int_unchecked(intrinsics::simd_eq(self, other)) }
-    }
-
-    /// Test if each lane is not equal to the corresponding lane in `other`.
-    #[inline]
-    #[must_use = "method returns a new mask and does not mutate the original value"]
-    pub fn lanes_ne(self, other: Self) -> Mask<T::Mask, LANES> {
-        // Safety: `self` is a vector, and the result of the comparison
-        // is always a valid mask.
-        unsafe { Mask::from_int_unchecked(intrinsics::simd_ne(self, other)) }
-    }
-}
-
-impl<T, const LANES: usize> Simd<T, LANES>
-where
-    T: SimdElement + PartialOrd,
-    LaneCount<LANES>: SupportedLaneCount,
-{
-    /// Test if each lane is less than the corresponding lane in `other`.
-    #[inline]
-    #[must_use = "method returns a new mask and does not mutate the original value"]
-    pub fn lanes_lt(self, other: Self) -> Mask<T::Mask, LANES> {
-        // Safety: `self` is a vector, and the result of the comparison
-        // is always a valid mask.
-        unsafe { Mask::from_int_unchecked(intrinsics::simd_lt(self, other)) }
-    }
-
-    /// Test if each lane is greater than the corresponding lane in `other`.
-    #[inline]
-    #[must_use = "method returns a new mask and does not mutate the original value"]
-    pub fn lanes_gt(self, other: Self) -> Mask<T::Mask, LANES> {
-        // Safety: `self` is a vector, and the result of the comparison
-        // is always a valid mask.
-        unsafe { Mask::from_int_unchecked(intrinsics::simd_gt(self, other)) }
-    }
-
-    /// Test if each lane is less than or equal to the corresponding lane in `other`.
-    #[inline]
-    #[must_use = "method returns a new mask and does not mutate the original value"]
-    pub fn lanes_le(self, other: Self) -> Mask<T::Mask, LANES> {
-        // Safety: `self` is a vector, and the result of the comparison
-        // is always a valid mask.
-        unsafe { Mask::from_int_unchecked(intrinsics::simd_le(self, other)) }
-    }
-
-    /// Test if each lane is greater than or equal to the corresponding lane in `other`.
-    #[inline]
-    #[must_use = "method returns a new mask and does not mutate the original value"]
-    pub fn lanes_ge(self, other: Self) -> Mask<T::Mask, LANES> {
-        // Safety: `self` is a vector, and the result of the comparison
-        // is always a valid mask.
-        unsafe { Mask::from_int_unchecked(intrinsics::simd_ge(self, other)) }
-    }
-}
-
-macro_rules! impl_ord_methods_vector {
-    { $type:ty } => {
-        impl<const LANES: usize> Simd<$type, LANES>
-        where
-            LaneCount<LANES>: SupportedLaneCount,
-        {
-            /// Returns the lane-wise minimum with `other`.
-            #[must_use = "method returns a new vector and does not mutate the original value"]
-            #[inline]
-            pub fn min(self, other: Self) -> Self {
-                self.lanes_gt(other).select(other, self)
-            }
-
-            /// Returns the lane-wise maximum with `other`.
-            #[must_use = "method returns a new vector and does not mutate the original value"]
-            #[inline]
-            pub fn max(self, other: Self) -> Self {
-                self.lanes_lt(other).select(other, self)
-            }
-
-            /// Restrict each lane to a certain interval.
-            ///
-            /// For each lane, returns `max` if `self` is greater than `max`, and `min` if `self` is
-            /// less than `min`. Otherwise returns `self`.
-            ///
-            /// # Panics
-            ///
-            /// Panics if `min > max` on any lane.
-            #[must_use = "method returns a new vector and does not mutate the original value"]
-            #[inline]
-            pub fn clamp(self, min: Self, max: Self) -> Self {
-                assert!(
-                    min.lanes_le(max).all(),
-                    "each lane in `min` must be less than or equal to the corresponding lane in `max`",
-                );
-                self.max(min).min(max)
-            }
-        }
-    }
-}
-
-impl_ord_methods_vector!(i8);
-impl_ord_methods_vector!(i16);
-impl_ord_methods_vector!(i32);
-impl_ord_methods_vector!(i64);
-impl_ord_methods_vector!(isize);
-impl_ord_methods_vector!(u8);
-impl_ord_methods_vector!(u16);
-impl_ord_methods_vector!(u32);
-impl_ord_methods_vector!(u64);
-impl_ord_methods_vector!(usize);
diff --git a/crates/core_simd/src/eq.rs b/crates/core_simd/src/eq.rs
new file mode 100644
index 00000000000..c7111f720a8
--- /dev/null
+++ b/crates/core_simd/src/eq.rs
@@ -0,0 +1,73 @@
+use crate::simd::{intrinsics, LaneCount, Mask, Simd, SimdElement, SupportedLaneCount};
+
+/// Parallel `PartialEq`.
+pub trait SimdPartialEq {
+    /// The mask type returned by each comparison.
+    type Mask;
+
+    /// Test if each lane is equal to the corresponding lane in `other`.
+    #[must_use = "method returns a new mask and does not mutate the original value"]
+    fn simd_eq(self, other: Self) -> Self::Mask;
+
+    /// Test if each lane is equal to the corresponding lane in `other`.
+    #[must_use = "method returns a new mask and does not mutate the original value"]
+    fn simd_ne(self, other: Self) -> Self::Mask;
+}
+
+macro_rules! impl_number {
+    { $($number:ty),* } => {
+        $(
+        impl<const LANES: usize> SimdPartialEq for Simd<$number, LANES>
+        where
+            LaneCount<LANES>: SupportedLaneCount,
+        {
+            type Mask = Mask<<$number as SimdElement>::Mask, LANES>;
+
+            #[inline]
+            fn simd_eq(self, other: Self) -> Self::Mask {
+                // Safety: `self` is a vector, and the result of the comparison
+                // is always a valid mask.
+                unsafe { Mask::from_int_unchecked(intrinsics::simd_eq(self, other)) }
+            }
+
+            #[inline]
+            fn simd_ne(self, other: Self) -> Self::Mask {
+                // Safety: `self` is a vector, and the result of the comparison
+                // is always a valid mask.
+                unsafe { Mask::from_int_unchecked(intrinsics::simd_ne(self, other)) }
+            }
+        }
+        )*
+    }
+}
+
+impl_number! { f32, f64, u8, u16, u32, u64, usize, i8, i16, i32, i64, isize }
+
+macro_rules! impl_mask {
+    { $($integer:ty),* } => {
+        $(
+        impl<const LANES: usize> SimdPartialEq for Mask<$integer, LANES>
+        where
+            LaneCount<LANES>: SupportedLaneCount,
+        {
+            type Mask = Self;
+
+            #[inline]
+            fn simd_eq(self, other: Self) -> Self::Mask {
+                // Safety: `self` is a vector, and the result of the comparison
+                // is always a valid mask.
+                unsafe { Self::from_int_unchecked(intrinsics::simd_eq(self.to_int(), other.to_int())) }
+            }
+
+            #[inline]
+            fn simd_ne(self, other: Self) -> Self::Mask {
+                // Safety: `self` is a vector, and the result of the comparison
+                // is always a valid mask.
+                unsafe { Self::from_int_unchecked(intrinsics::simd_ne(self.to_int(), other.to_int())) }
+            }
+        }
+        )*
+    }
+}
+
+impl_mask! { i8, i16, i32, i64, isize }
diff --git a/crates/core_simd/src/masks.rs b/crates/core_simd/src/masks.rs
index b97be97f7e6..e8962b86b11 100644
--- a/crates/core_simd/src/masks.rs
+++ b/crates/core_simd/src/masks.rs
@@ -15,7 +15,7 @@ mod mask_impl;
 mod to_bitmask;
 pub use to_bitmask::ToBitMask;
 
-use crate::simd::{intrinsics, LaneCount, Simd, SimdElement, SupportedLaneCount};
+use crate::simd::{intrinsics, LaneCount, Simd, SimdElement, SimdPartialEq, SupportedLaneCount};
 use core::cmp::Ordering;
 use core::{fmt, mem};
 
@@ -56,7 +56,7 @@ macro_rules! impl_element {
             where
                 LaneCount<LANES>: SupportedLaneCount,
             {
-                (value.lanes_eq(Simd::splat(0)) | value.lanes_eq(Simd::splat(-1))).all()
+                (value.simd_eq(Simd::splat(0 as _)) | value.simd_eq(Simd::splat(-1 as _))).all()
             }
 
             fn eq(self, other: Self) -> bool { self == other }
diff --git a/crates/core_simd/src/mod.rs b/crates/core_simd/src/mod.rs
index 85026265956..42257f4e119 100644
--- a/crates/core_simd/src/mod.rs
+++ b/crates/core_simd/src/mod.rs
@@ -9,13 +9,14 @@ pub(crate) mod intrinsics;
 #[cfg(feature = "generic_const_exprs")]
 mod to_bytes;
 
-mod comparisons;
+mod eq;
 mod fmt;
 mod iter;
 mod lane_count;
 mod masks;
 mod math;
 mod ops;
+mod ord;
 mod round;
 mod select;
 mod vector;
@@ -25,8 +26,10 @@ mod vendor;
 pub mod simd {
     pub(crate) use crate::core_simd::intrinsics;
 
+    pub use crate::core_simd::eq::*;
     pub use crate::core_simd::lane_count::{LaneCount, SupportedLaneCount};
     pub use crate::core_simd::masks::*;
+    pub use crate::core_simd::ord::*;
     pub use crate::core_simd::swizzle::*;
     pub use crate::core_simd::vector::*;
 }
diff --git a/crates/core_simd/src/ops.rs b/crates/core_simd/src/ops.rs
index 1b35b3e717a..d39b4091df9 100644
--- a/crates/core_simd/src/ops.rs
+++ b/crates/core_simd/src/ops.rs
@@ -1,4 +1,4 @@
-use crate::simd::{LaneCount, Simd, SimdElement, SupportedLaneCount};
+use crate::simd::{LaneCount, Simd, SimdElement, SimdPartialEq, SupportedLaneCount};
 use core::ops::{Add, Mul};
 use core::ops::{BitAnd, BitOr, BitXor};
 use core::ops::{Div, Rem, Sub};
@@ -74,7 +74,7 @@ macro_rules! int_divrem_guard {
             $simd_call:ident
         },
         $int:ident ) => {
-        if $rhs.lanes_eq(Simd::splat(0)).any() {
+        if $rhs.simd_eq(Simd::splat(0 as _)).any() {
             panic!($zero);
         } else {
             // Prevent otherwise-UB overflow on the MIN / -1 case.
@@ -82,10 +82,10 @@ macro_rules! int_divrem_guard {
                 // This should, at worst, optimize to a few branchless logical ops
                 // Ideally, this entire conditional should evaporate
                 // Fire LLVM and implement those manually if it doesn't get the hint
-                ($lhs.lanes_eq(Simd::splat(<$int>::MIN))
+                ($lhs.simd_eq(Simd::splat(<$int>::MIN))
                 // type inference can break here, so cut an SInt to size
-                & $rhs.lanes_eq(Simd::splat(-1i64 as _)))
-                .select(Simd::splat(1), $rhs)
+                & $rhs.simd_eq(Simd::splat(-1i64 as _)))
+                .select(Simd::splat(1 as _), $rhs)
             } else {
                 // Nice base case to make it easy to const-fold away the other branch.
                 $rhs
diff --git a/crates/core_simd/src/ord.rs b/crates/core_simd/src/ord.rs
new file mode 100644
index 00000000000..9a87bc2e344
--- /dev/null
+++ b/crates/core_simd/src/ord.rs
@@ -0,0 +1,213 @@
+use crate::simd::{intrinsics, LaneCount, Mask, Simd, SimdPartialEq, SupportedLaneCount};
+
+/// Parallel `PartialOrd`.
+pub trait SimdPartialOrd: SimdPartialEq {
+    /// Test if each lane is less than the corresponding lane in `other`.
+    #[must_use = "method returns a new mask and does not mutate the original value"]
+    fn simd_lt(self, other: Self) -> Self::Mask;
+
+    /// Test if each lane is less than or equal to the corresponding lane in `other`.
+    #[must_use = "method returns a new mask and does not mutate the original value"]
+    fn simd_le(self, other: Self) -> Self::Mask;
+
+    /// Test if each lane is greater than the corresponding lane in `other`.
+    #[must_use = "method returns a new mask and does not mutate the original value"]
+    fn simd_gt(self, other: Self) -> Self::Mask;
+
+    /// Test if each lane is greater than or equal to the corresponding lane in `other`.
+    #[must_use = "method returns a new mask and does not mutate the original value"]
+    fn simd_ge(self, other: Self) -> Self::Mask;
+}
+
+/// Parallel `Ord`.
+pub trait SimdOrd: SimdPartialOrd {
+    /// Returns the lane-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;
+
+    /// Returns the lane-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;
+
+    /// Restrict each lane to a certain interval.
+    ///
+    /// For each lane, returns `max` if `self` is greater than `max`, and `min` if `self` is
+    /// less than `min`. Otherwise returns `self`.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `min > max` on any lane.
+    #[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_integer {
+    { $($integer:ty),* } => {
+        $(
+        impl<const LANES: usize> SimdPartialOrd for Simd<$integer, LANES>
+        where
+            LaneCount<LANES>: SupportedLaneCount,
+        {
+            #[inline]
+            fn simd_lt(self, other: Self) -> Self::Mask {
+                // Safety: `self` is a vector, and the result of the comparison
+                // is always a valid mask.
+                unsafe { Mask::from_int_unchecked(intrinsics::simd_lt(self, other)) }
+            }
+
+            #[inline]
+            fn simd_le(self, other: Self) -> Self::Mask {
+                // Safety: `self` is a vector, and the result of the comparison
+                // is always a valid mask.
+                unsafe { Mask::from_int_unchecked(intrinsics::simd_le(self, other)) }
+            }
+
+            #[inline]
+            fn simd_gt(self, other: Self) -> Self::Mask {
+                // Safety: `self` is a vector, and the result of the comparison
+                // is always a valid mask.
+                unsafe { Mask::from_int_unchecked(intrinsics::simd_gt(self, other)) }
+            }
+
+            #[inline]
+            fn simd_ge(self, other: Self) -> Self::Mask {
+                // Safety: `self` is a vector, and the result of the comparison
+                // is always a valid mask.
+                unsafe { Mask::from_int_unchecked(intrinsics::simd_ge(self, other)) }
+            }
+        }
+
+        impl<const LANES: usize> SimdOrd for Simd<$integer, LANES>
+        where
+            LaneCount<LANES>: SupportedLaneCount,
+        {
+            #[inline]
+            fn simd_max(self, other: Self) -> Self {
+                self.simd_lt(other).select(other, self)
+            }
+
+            #[inline]
+            fn simd_min(self, other: Self) -> Self {
+                self.simd_gt(other).select(other, self)
+            }
+
+            #[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`",
+                );
+                self.simd_max(min).simd_min(max)
+            }
+        }
+        )*
+    }
+}
+
+impl_integer! { u8, u16, u32, u64, usize, i8, i16, i32, i64, isize }
+
+macro_rules! impl_float {
+    { $($float:ty),* } => {
+        $(
+        impl<const LANES: usize> SimdPartialOrd for Simd<$float, LANES>
+        where
+            LaneCount<LANES>: SupportedLaneCount,
+        {
+            #[inline]
+            fn simd_lt(self, other: Self) -> Self::Mask {
+                // Safety: `self` is a vector, and the result of the comparison
+                // is always a valid mask.
+                unsafe { Mask::from_int_unchecked(intrinsics::simd_lt(self, other)) }
+            }
+
+            #[inline]
+            fn simd_le(self, other: Self) -> Self::Mask {
+                // Safety: `self` is a vector, and the result of the comparison
+                // is always a valid mask.
+                unsafe { Mask::from_int_unchecked(intrinsics::simd_le(self, other)) }
+            }
+
+            #[inline]
+            fn simd_gt(self, other: Self) -> Self::Mask {
+                // Safety: `self` is a vector, and the result of the comparison
+                // is always a valid mask.
+                unsafe { Mask::from_int_unchecked(intrinsics::simd_gt(self, other)) }
+            }
+
+            #[inline]
+            fn simd_ge(self, other: Self) -> Self::Mask {
+                // Safety: `self` is a vector, and the result of the comparison
+                // is always a valid mask.
+                unsafe { Mask::from_int_unchecked(intrinsics::simd_ge(self, other)) }
+            }
+        }
+        )*
+    }
+}
+
+impl_float! { f32, f64 }
+
+macro_rules! impl_mask {
+    { $($integer:ty),* } => {
+        $(
+        impl<const LANES: usize> SimdPartialOrd for Mask<$integer, LANES>
+        where
+            LaneCount<LANES>: SupportedLaneCount,
+        {
+            #[inline]
+            fn simd_lt(self, other: Self) -> Self::Mask {
+                // Safety: `self` is a vector, and the result of the comparison
+                // is always a valid mask.
+                unsafe { Self::from_int_unchecked(intrinsics::simd_lt(self.to_int(), other.to_int())) }
+            }
+
+            #[inline]
+            fn simd_le(self, other: Self) -> Self::Mask {
+                // Safety: `self` is a vector, and the result of the comparison
+                // is always a valid mask.
+                unsafe { Self::from_int_unchecked(intrinsics::simd_le(self.to_int(), other.to_int())) }
+            }
+
+            #[inline]
+            fn simd_gt(self, other: Self) -> Self::Mask {
+                // Safety: `self` is a vector, and the result of the comparison
+                // is always a valid mask.
+                unsafe { Self::from_int_unchecked(intrinsics::simd_gt(self.to_int(), other.to_int())) }
+            }
+
+            #[inline]
+            fn simd_ge(self, other: Self) -> Self::Mask {
+                // Safety: `self` is a vector, and the result of the comparison
+                // is always a valid mask.
+                unsafe { Self::from_int_unchecked(intrinsics::simd_ge(self.to_int(), other.to_int())) }
+            }
+        }
+
+        impl<const LANES: usize> SimdOrd for Mask<$integer, LANES>
+        where
+            LaneCount<LANES>: SupportedLaneCount,
+        {
+            #[inline]
+            fn simd_max(self, other: Self) -> Self {
+                self.simd_gt(other).select_mask(other, self)
+            }
+
+            #[inline]
+            fn simd_min(self, other: Self) -> Self {
+                self.simd_lt(other).select_mask(other, self)
+            }
+
+            #[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`",
+                );
+                self.simd_max(min).simd_min(max)
+            }
+        }
+        )*
+    }
+}
+
+impl_mask! { i8, i16, i32, i64, isize }
diff --git a/crates/core_simd/src/vector.rs b/crates/core_simd/src/vector.rs
index 2405c1429b3..13e35ecfa49 100644
--- a/crates/core_simd/src/vector.rs
+++ b/crates/core_simd/src/vector.rs
@@ -10,7 +10,7 @@ pub use uint::*;
 pub(crate) mod ptr;
 
 use crate::simd::intrinsics;
-use crate::simd::{LaneCount, Mask, MaskElement, SupportedLaneCount};
+use crate::simd::{LaneCount, Mask, MaskElement, SimdPartialOrd, SupportedLaneCount};
 
 /// A SIMD vector of `LANES` elements of type `T`. `Simd<T, N>` has the same shape as [`[T; N]`](array), but operates like `T`.
 ///
@@ -243,7 +243,7 @@ where
         idxs: Simd<usize, LANES>,
         or: Self,
     ) -> Self {
-        let enable: Mask<isize, LANES> = enable & idxs.lanes_lt(Simd::splat(slice.len()));
+        let enable: Mask<isize, LANES> = enable & idxs.simd_lt(Simd::splat(slice.len()));
         // Safety: We have masked-off out-of-bounds lanes.
         unsafe { Self::gather_select_unchecked(slice, enable, idxs, or) }
     }
@@ -260,13 +260,13 @@ where
     /// # Examples
     /// ```
     /// # #![feature(portable_simd)]
-    /// # use core::simd::{Simd, Mask};
+    /// # use core_simd::simd::{Simd, SimdPartialOrd, Mask};
     /// let vec: Vec<i32> = vec![10, 11, 12, 13, 14, 15, 16, 17, 18];
     /// let idxs = Simd::from_array([9, 3, 0, 5]);
     /// let alt = Simd::from_array([-5, -4, -3, -2]);
     /// let enable = Mask::from_array([true, true, true, false]); // Note the final mask lane.
     /// // If this mask was used to gather, it would be unsound. Let's fix that.
-    /// let enable = enable & idxs.lanes_lt(Simd::splat(vec.len()));
+    /// let enable = enable & idxs.simd_lt(Simd::splat(vec.len()));
     ///
     /// // We have masked the OOB lane, so it's safe to gather now.
     /// let result = unsafe { Simd::gather_select_unchecked(&vec, enable, idxs, alt) };
@@ -317,7 +317,7 @@ where
     /// # Examples
     /// ```
     /// # #![feature(portable_simd)]
-    /// # use core::simd::{Simd, Mask};
+    /// # use core_simd::simd::{Simd, Mask};
     /// let mut vec: Vec<i32> = vec![10, 11, 12, 13, 14, 15, 16, 17, 18];
     /// let idxs = Simd::from_array([9, 3, 0, 0]);
     /// let vals = Simd::from_array([-27, 82, -41, 124]);
@@ -333,7 +333,7 @@ where
         enable: Mask<isize, LANES>,
         idxs: Simd<usize, LANES>,
     ) {
-        let enable: Mask<isize, LANES> = enable & idxs.lanes_lt(Simd::splat(slice.len()));
+        let enable: Mask<isize, LANES> = enable & idxs.simd_lt(Simd::splat(slice.len()));
         // Safety: We have masked-off out-of-bounds lanes.
         unsafe { self.scatter_select_unchecked(slice, enable, idxs) }
     }
@@ -351,13 +351,13 @@ where
     /// # Examples
     /// ```
     /// # #![feature(portable_simd)]
-    /// # use core::simd::{Simd, Mask};
+    /// # use core_simd::simd::{Simd, SimdPartialOrd, Mask};
     /// let mut vec: Vec<i32> = vec![10, 11, 12, 13, 14, 15, 16, 17, 18];
     /// let idxs = Simd::from_array([9, 3, 0, 0]);
     /// let vals = Simd::from_array([-27, 82, -41, 124]);
     /// let enable = Mask::from_array([true, true, true, false]); // Note the mask of the last lane.
     /// // If this mask was used to scatter, it would be unsound. Let's fix that.
-    /// let enable = enable & idxs.lanes_lt(Simd::splat(vec.len()));
+    /// let enable = enable & idxs.simd_lt(Simd::splat(vec.len()));
     ///
     /// // We have masked the OOB lane, so it's safe to scatter now.
     /// unsafe { vals.scatter_select_unchecked(&mut vec, enable, idxs); }
diff --git a/crates/core_simd/src/vector/float.rs b/crates/core_simd/src/vector/float.rs
index f7985b64710..13b1d3995a1 100644
--- a/crates/core_simd/src/vector/float.rs
+++ b/crates/core_simd/src/vector/float.rs
@@ -1,7 +1,7 @@
 #![allow(non_camel_case_types)]
 
 use crate::simd::intrinsics;
-use crate::simd::{LaneCount, Mask, Simd, SupportedLaneCount};
+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
@@ -74,35 +74,35 @@ macro_rules! impl_float_vector {
             #[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.lanes_gt(Simd::splat(0))
+                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.lanes_ne(self)
+                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().lanes_eq(Self::splat(<$type>::INFINITY))
+                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().lanes_lt(Self::splat(<$type>::INFINITY))
+                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().lanes_ne(Self::splat(0.0)) & (self.to_bits() & Self::splat(<$type>::INFINITY).to_bits()).lanes_eq(Simd::splat(0))
+                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,
@@ -110,7 +110,7 @@ macro_rules! impl_float_vector {
             #[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().lanes_eq(Self::splat(0.0)) | self.is_nan() | self.is_subnormal() | self.is_infinite())
+                !(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.
@@ -134,42 +134,6 @@ macro_rules! impl_float_vector {
                 let magnitude = self.to_bits() & !Self::splat(-0.).to_bits();
                 Self::from_bits(sign_bit | magnitude)
             }
-
-            /// Returns the minimum of each lane.
-            ///
-            /// If one of the values is `NAN`, then the other value is returned.
-            #[inline]
-            #[must_use = "method returns a new vector and does not mutate the original value"]
-            pub fn min(self, other: Self) -> Self {
-                unsafe { intrinsics::simd_fmin(self, other) }
-            }
-
-            /// Returns the maximum of each lane.
-            ///
-            /// If one of the values is `NAN`, then the other value is returned.
-            #[inline]
-            #[must_use = "method returns a new vector and does not mutate the original value"]
-            pub fn max(self, other: Self) -> Self {
-                unsafe { intrinsics::simd_fmax(self, other) }
-            }
-
-            /// 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`.
-            #[inline]
-            #[must_use = "method returns a new vector and does not mutate the original value"]
-            pub fn clamp(self, min: Self, max: Self) -> Self {
-                assert!(
-                    min.lanes_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.lanes_lt(min).select(min, x);
-                x = x.lanes_gt(max).select(max, x);
-                x
-            }
         }
     };
 }
@@ -197,3 +161,73 @@ 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/src/vector/int.rs b/crates/core_simd/src/vector/int.rs
index eec483212b3..384f01d822a 100644
--- a/crates/core_simd/src/vector/int.rs
+++ b/crates/core_simd/src/vector/int.rs
@@ -1,6 +1,6 @@
 #![allow(non_camel_case_types)]
 
-use crate::simd::{LaneCount, Mask, Simd, SupportedLaneCount};
+use crate::simd::{LaneCount, Mask, Simd, SimdPartialOrd, SupportedLaneCount};
 
 /// Implements additional integer traits (Eq, Ord, Hash) on the specified vector `$name`, holding multiple `$lanes` of `$type`.
 macro_rules! impl_integer_vector {
@@ -12,13 +12,13 @@ macro_rules! impl_integer_vector {
             /// Returns true for each positive lane and false if it is zero or negative.
             #[inline]
             pub fn is_positive(self) -> Mask<$type, LANES> {
-                self.lanes_gt(Self::splat(0))
+                self.simd_gt(Self::splat(0))
             }
 
             /// Returns true for each negative lane and false if it is zero or positive.
             #[inline]
             pub fn is_negative(self) -> Mask<$type, LANES> {
-                self.lanes_lt(Self::splat(0))
+                self.simd_lt(Self::splat(0))
             }
 
             /// Returns numbers representing the sign of each lane.
diff --git a/crates/core_simd/tests/i16_ops.rs b/crates/core_simd/tests/i16_ops.rs
index 171e5b472fa..f6c5d74fbbc 100644
--- a/crates/core_simd/tests/i16_ops.rs
+++ b/crates/core_simd/tests/i16_ops.rs
@@ -1,32 +1,5 @@
 #![feature(portable_simd)]
-use core_simd::i16x2;
 
 #[macro_use]
 mod ops_macros;
 impl_signed_tests! { i16 }
-
-#[test]
-fn max_is_not_lexicographic() {
-    let a = i16x2::splat(10);
-    let b = i16x2::from_array([-4, 12]);
-    assert_eq!(a.max(b), i16x2::from_array([10, 12]));
-}
-
-#[test]
-fn min_is_not_lexicographic() {
-    let a = i16x2::splat(10);
-    let b = i16x2::from_array([12, -4]);
-    assert_eq!(a.min(b), i16x2::from_array([10, -4]));
-}
-
-#[test]
-fn clamp_is_not_lexicographic() {
-    let a = i16x2::splat(10);
-    let lo = i16x2::from_array([-12, -4]);
-    let up = i16x2::from_array([-4, 12]);
-    assert_eq!(a.clamp(lo, up), i16x2::from_array([-4, 10]));
-
-    let x = i16x2::from_array([1, 10]);
-    let y = x.clamp(i16x2::splat(0), i16x2::splat(9));
-    assert_eq!(y, i16x2::from_array([1, 9]));
-}
diff --git a/crates/core_simd/tests/ops_macros.rs b/crates/core_simd/tests/ops_macros.rs
index 7c9b17673ef..47fe49b0982 100644
--- a/crates/core_simd/tests/ops_macros.rs
+++ b/crates/core_simd/tests/ops_macros.rs
@@ -222,34 +222,37 @@ macro_rules! impl_signed_tests {
                     assert_eq!(a % b, Vector::<LANES>::splat(0));
                 }
 
-                fn min<const LANES: usize>() {
+                fn simd_min<const LANES: usize>() {
+                    use core_simd::simd::SimdOrd;
                     let a = Vector::<LANES>::splat(Scalar::MIN);
                     let b = Vector::<LANES>::splat(0);
-                    assert_eq!(a.min(b), a);
+                    assert_eq!(a.simd_min(b), a);
                     let a = Vector::<LANES>::splat(Scalar::MAX);
                     let b = Vector::<LANES>::splat(0);
-                    assert_eq!(a.min(b), b);
+                    assert_eq!(a.simd_min(b), b);
                 }
 
-                fn max<const LANES: usize>() {
+                fn simd_max<const LANES: usize>() {
+                    use core_simd::simd::SimdOrd;
                     let a = Vector::<LANES>::splat(Scalar::MIN);
                     let b = Vector::<LANES>::splat(0);
-                    assert_eq!(a.max(b), b);
+                    assert_eq!(a.simd_max(b), b);
                     let a = Vector::<LANES>::splat(Scalar::MAX);
                     let b = Vector::<LANES>::splat(0);
-                    assert_eq!(a.max(b), a);
+                    assert_eq!(a.simd_max(b), a);
                 }
 
-                fn clamp<const LANES: usize>() {
+                fn simd_clamp<const LANES: usize>() {
+                    use core_simd::simd::SimdOrd;
                     let min = Vector::<LANES>::splat(Scalar::MIN);
                     let max = Vector::<LANES>::splat(Scalar::MAX);
                     let zero = Vector::<LANES>::splat(0);
                     let one = Vector::<LANES>::splat(1);
                     let negone = Vector::<LANES>::splat(-1);
-                    assert_eq!(zero.clamp(min, max), zero);
-                    assert_eq!(zero.clamp(min, one), zero);
-                    assert_eq!(zero.clamp(one, max), one);
-                    assert_eq!(zero.clamp(min, negone), negone);
+                    assert_eq!(zero.simd_clamp(min, max), zero);
+                    assert_eq!(zero.simd_clamp(min, one), zero);
+                    assert_eq!(zero.simd_clamp(one, max), one);
+                    assert_eq!(zero.simd_clamp(min, negone), negone);
                 }
             }
 
@@ -458,10 +461,11 @@ macro_rules! impl_float_tests {
                     )
                 }
 
-                fn min<const LANES: usize>() {
+                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>::min,
+                        &Vector::<LANES>::simd_min,
                         &Scalar::min,
                         // Reject the case where both values are zero with different signs
                         &|a, b| {
@@ -477,14 +481,15 @@ macro_rules! impl_float_tests {
                     // Special case where both values are zero
                     let p_zero = Vector::<LANES>::splat(0.);
                     let n_zero = Vector::<LANES>::splat(-0.);
-                    assert!(p_zero.min(n_zero).to_array().iter().all(|x| *x == 0.));
-                    assert!(n_zero.min(p_zero).to_array().iter().all(|x| *x == 0.));
+                    assert!(p_zero.simd_min(n_zero).to_array().iter().all(|x| *x == 0.));
+                    assert!(n_zero.simd_min(p_zero).to_array().iter().all(|x| *x == 0.));
                 }
 
-                fn max<const LANES: usize>() {
+                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>::max,
+                        &Vector::<LANES>::simd_max,
                         &Scalar::max,
                         // Reject the case where both values are zero with different signs
                         &|a, b| {
@@ -500,11 +505,12 @@ macro_rules! impl_float_tests {
                     // Special case where both values are zero
                     let p_zero = Vector::<LANES>::splat(0.);
                     let n_zero = Vector::<LANES>::splat(-0.);
-                    assert!(p_zero.max(n_zero).to_array().iter().all(|x| *x == 0.));
-                    assert!(n_zero.max(p_zero).to_array().iter().all(|x| *x == 0.));
+                    assert!(p_zero.simd_max(n_zero).to_array().iter().all(|x| *x == 0.));
+                    assert!(n_zero.simd_max(p_zero).to_array().iter().all(|x| *x == 0.));
                 }
 
-                fn clamp<const LANES: usize>() {
+                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 {
@@ -522,7 +528,7 @@ macro_rules! impl_float_tests {
                         for i in 0..LANES {
                             result_scalar[i] = value[i].clamp(min[i], max[i]);
                         }
-                        let result_vector = Vector::from_array(value).clamp(min.into(), max.into()).to_array();
+                        let result_vector = Vector::from_array(value).simd_clamp(min.into(), max.into()).to_array();
                         test_helpers::prop_assert_biteq!(result_scalar, result_vector);
                         Ok(())
                     })