diff --git a/crates/core_simd/src/macros.rs b/crates/core_simd/src/macros.rs index 2f93db1903520..f37d13c3ca32e 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 9fcbd9d53f0f8..17b382ee739e5 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 d741aabe88e0f..b41923ca6f10d 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 9bcb894b2572a..1c969a2e8af3b 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 + '_ { + let lanes = core::mem::size_of::() / 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); + } + } } } }