From 2a02c4d9cbee120915535f6fc8379849e10e8373 Mon Sep 17 00:00:00 2001 From: Caleb Zulawski Date: Sun, 13 Mar 2022 19:57:06 +0000 Subject: [PATCH] Create SimdFloat trait --- crates/core_simd/src/vector/float.rs | 106 ++++++++++++++++++--------- crates/core_simd/tests/ops_macros.rs | 3 + 2 files changed, 73 insertions(+), 36 deletions(-) diff --git a/crates/core_simd/src/vector/float.rs b/crates/core_simd/src/vector/float.rs index ebe4fbcb6fa8..f422d1611785 100644 --- a/crates/core_simd/src/vector/float.rs +++ b/crates/core_simd/src/vector/float.rs @@ -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 simd_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 simd_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 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 - } } }; } @@ -197,3 +161,73 @@ pub type f64x4 = Simd; /// Vector of eight `f64` values pub type f64x8 = Simd; + +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 Sealed for Simd<$float, LANES> + where + LaneCount: SupportedLaneCount, + { + } + + impl SimdFloat for Simd<$float, LANES> + where + LaneCount: 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 f8389c910c68..47fe49b09828 100644 --- a/crates/core_simd/tests/ops_macros.rs +++ b/crates/core_simd/tests/ops_macros.rs @@ -462,6 +462,7 @@ macro_rules! impl_float_tests { } fn simd_min() { + use core_simd::simd::SimdFloat; // Regular conditions (both values aren't zero) test_helpers::test_binary_elementwise( &Vector::::simd_min, @@ -485,6 +486,7 @@ macro_rules! impl_float_tests { } fn simd_max() { + use core_simd::simd::SimdFloat; // Regular conditions (both values aren't zero) test_helpers::test_binary_elementwise( &Vector::::simd_max, @@ -508,6 +510,7 @@ macro_rules! impl_float_tests { } fn simd_clamp() { + 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 {