about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--crates/core_simd/src/macros.rs45
-rw-r--r--crates/core_simd/src/vectors_f32.rs14
-rw-r--r--crates/core_simd/src/vectors_f64.rs9
-rw-r--r--crates/core_simd/tests/ops_impl/float_macros.rs49
4 files changed, 110 insertions, 7 deletions
diff --git a/crates/core_simd/src/macros.rs b/crates/core_simd/src/macros.rs
index 2f93db19035..f37d13c3ca3 100644
--- a/crates/core_simd/src/macros.rs
+++ b/crates/core_simd/src/macros.rs
@@ -270,6 +270,51 @@ macro_rules! define_vector {
     }
 }
 
+/// Implements inherent methods for a float vector `$name` containing multiple
+/// `$lanes` of float `$type`, which uses `$bits_ty` as its binary
+/// representation. Called from `define_float_vector!`.
+macro_rules! impl_float_vector {
+    { $name:path => [$type:ty; $lanes:literal]; bits $bits_ty:ty; } => {
+        impl $name {
+            /// Raw transmutation to an unsigned integer vector type with the
+            /// same size and number of lanes.
+            #[inline]
+            pub fn to_bits(self) -> $bits_ty {
+                unsafe { core::mem::transmute(self) }
+            }
+
+            /// Raw transmutation from an unsigned integer vector type with the
+            /// same size and number of lanes.
+            #[inline]
+            pub fn from_bits(bits: $bits_ty) -> Self {
+                unsafe { core::mem::transmute(bits) }
+            }
+
+            /// Produces a vector where every lane has the absolute value of the
+            /// equivalently-indexed lane in `self`.
+            #[inline]
+            pub fn abs(self) -> Self {
+                let no_sign = <$bits_ty>::splat(!0 >> 1);
+                Self::from_bits(self.to_bits() & no_sign)
+            }
+        }
+    };
+}
+
+/// Defines a float vector `$name` containing multiple `$lanes` of float
+/// `$type`, which uses `$bits_ty` as its binary representation.
+macro_rules! define_float_vector {
+    { $(#[$attr:meta])* struct $name:ident([$type:ty; $lanes:tt]); bits $bits_ty:ty; } => {
+        define_vector! {
+            $(#[$attr])*
+            struct $name([$type; $lanes]);
+        }
+
+        impl_float_vector! { $name => [$type; $lanes]; bits $bits_ty; }
+    }
+}
+
+
 /// Defines an integer vector `$name` containing multiple `$lanes` of integer `$type`.
 macro_rules! define_integer_vector {
     { $(#[$attr:meta])* struct $name:ident([$type:ty; $lanes:tt]); } => {
diff --git a/crates/core_simd/src/vectors_f32.rs b/crates/core_simd/src/vectors_f32.rs
index 9fcbd9d53f0..17b382ee739 100644
--- a/crates/core_simd/src/vectors_f32.rs
+++ b/crates/core_simd/src/vectors_f32.rs
@@ -1,23 +1,29 @@
-define_vector! {
+define_float_vector! {
     /// Vector of two `f32` values
     struct f32x2([f32; 2]);
+    bits crate::u32x2;
 }
 
-define_vector! {
+define_float_vector! {
     /// Vector of four `f32` values
     struct f32x4([f32; 4]);
+    bits crate::u32x4;
 }
 
-define_vector! {
+define_float_vector! {
     /// Vector of eight `f32` values
     struct f32x8([f32; 8]);
+    bits crate::u32x8;
 }
 
-define_vector! {
+define_float_vector! {
     /// Vector of 16 `f32` values
     struct f32x16([f32; 16]);
+    bits crate::u32x16;
 }
 
 from_transmute_x86! { unsafe f32x4 => __m128 }
 from_transmute_x86! { unsafe f32x8 => __m256 }
 //from_transmute_x86! { unsafe f32x16 => __m512 }
+
+
diff --git a/crates/core_simd/src/vectors_f64.rs b/crates/core_simd/src/vectors_f64.rs
index d741aabe88e..b41923ca6f1 100644
--- a/crates/core_simd/src/vectors_f64.rs
+++ b/crates/core_simd/src/vectors_f64.rs
@@ -1,16 +1,19 @@
-define_vector! {
+define_float_vector! {
     /// Vector of two `f64` values
     struct f64x2([f64; 2]);
+    bits crate::u64x2;
 }
 
-define_vector! {
+define_float_vector! {
     /// Vector of four `f64` values
     struct f64x4([f64; 4]);
+    bits crate::u64x4;
 }
 
-define_vector! {
+define_float_vector! {
     /// Vector of eight `f64` values
     struct f64x8([f64; 8]);
+    bits crate::u64x8;
 }
 
 from_transmute_x86! { unsafe f64x2 => __m128d }
diff --git a/crates/core_simd/tests/ops_impl/float_macros.rs b/crates/core_simd/tests/ops_impl/float_macros.rs
index 9bcb894b257..1c969a2e8af 100644
--- a/crates/core_simd/tests/ops_impl/float_macros.rs
+++ b/crates/core_simd/tests/ops_impl/float_macros.rs
@@ -19,8 +19,32 @@ macro_rules! float_tests {
                 value
             }
 
+            fn slice_chunks(slice: &[$scalar]) -> impl Iterator<Item = core_simd::$vector> + '_ {
+                let lanes = core::mem::size_of::<core_simd::$vector>() / core::mem::size_of::<$scalar>();
+                slice.chunks_exact(lanes).map(from_slice)
+            }
+
             const A: [$scalar; 16] = [0.,   1.,  2.,  3.,  4.,  5.,  6.,  7.,  8.,  9., 10., 11., 12., 13., 14., 15.];
             const B: [$scalar; 16] = [16., 17., 18., 19., 20., 21., 22., 23., 24., 25., 26., 27., 28., 29., 30., 31.];
+            const C: [$scalar; 16] = [
+                -0.0,
+                0.0,
+                -1.0,
+                1.0,
+                <$scalar>::MIN,
+                <$scalar>::MAX,
+                <$scalar>::INFINITY,
+                <$scalar>::NEG_INFINITY,
+                <$scalar>::MIN_POSITIVE,
+                -<$scalar>::MIN_POSITIVE,
+                <$scalar>::EPSILON,
+                -<$scalar>::EPSILON,
+                <$scalar>::NAN,
+                -<$scalar>::NAN,
+                // TODO: Would be nice to check sNaN...
+                100.0 / 3.0,
+                -100.0 / 3.0,
+            ];
 
             #[test]
             #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
@@ -264,6 +288,31 @@ macro_rules! float_tests {
                 let expected = apply_unary_lanewise(v, core::ops::Neg::neg);
                 assert_biteq!(-v, expected);
             }
+
+            #[test]
+            #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
+            fn abs_negative() {
+                let v = -from_slice(&A);
+                let expected = apply_unary_lanewise(v, <$scalar>::abs);
+                assert_biteq!(v.abs(), expected);
+            }
+
+            #[test]
+            #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
+            fn abs_positive() {
+                let v = from_slice(&B);
+                let expected = apply_unary_lanewise(v, <$scalar>::abs);
+                assert_biteq!(v.abs(), expected);
+            }
+
+            #[test]
+            #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
+            fn abs_odd_floats() {
+                for v in slice_chunks(&C) {
+                    let expected = apply_unary_lanewise(v, <$scalar>::abs);
+                    assert_biteq!(v.abs(), expected);
+                }
+            }
         }
     }
 }