From 866971adf50539f944d9d1e034fcaab9a1be9609 Mon Sep 17 00:00:00 2001 From: Thom Chiovoloni Date: Tue, 6 Oct 2020 11:21:54 -0700 Subject: [PATCH 1/3] Implement abs, to_bits, and from_bits for float vectors --- crates/core_simd/src/macros.rs | 46 +++++++++++++++++++ crates/core_simd/src/vectors_f32.rs | 14 ++++-- crates/core_simd/src/vectors_f64.rs | 9 ++-- .../core_simd/tests/ops_impl/float_macros.rs | 44 ++++++++++++++++++ 4 files changed, 106 insertions(+), 7 deletions(-) diff --git a/crates/core_simd/src/macros.rs b/crates/core_simd/src/macros.rs index 2f93db1903520..214867c5ddce3 100644 --- a/crates/core_simd/src/macros.rs +++ b/crates/core_simd/src/macros.rs @@ -270,6 +270,52 @@ 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); + let abs = unsafe { crate::intrinsics::simd_and(self.to_bits(), no_sign) }; + Self::from_bits(abs) + } + } + }; +} + +/// 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..708b4d14327c1 100644 --- a/crates/core_simd/tests/ops_impl/float_macros.rs +++ b/crates/core_simd/tests/ops_impl/float_macros.rs @@ -21,6 +21,26 @@ macro_rules! float_tests { 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>::INFINITY, + <$scalar>::MIN_POSITIVE, + -<$scalar>::MIN_POSITIVE, + <$scalar>::EPSILON, + -<$scalar>::EPSILON, + 0.0 / 0.0, + -0.0 / 0.0, + // Still not sure if wasm can have weird nans, or I'd check them + // too. Until then + 1.0 / 3.0, + -1.0 / 4.0 + ]; #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] @@ -264,6 +284,30 @@ 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() { + let v = from_slice(&C); + let expected = apply_unary_lanewise(v, <$scalar>::abs); + assert_biteq!(v.abs(), expected); + } } } } From 541369c38e6fac164198fd4298e043b34ccbef9f Mon Sep 17 00:00:00 2001 From: Thom Chiovoloni Date: Tue, 6 Oct 2020 12:30:19 -0700 Subject: [PATCH 2/3] use NEG_INFINITY and NAN constants instead computing them --- crates/core_simd/tests/ops_impl/float_macros.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/crates/core_simd/tests/ops_impl/float_macros.rs b/crates/core_simd/tests/ops_impl/float_macros.rs index 708b4d14327c1..141cb52207bee 100644 --- a/crates/core_simd/tests/ops_impl/float_macros.rs +++ b/crates/core_simd/tests/ops_impl/float_macros.rs @@ -29,17 +29,16 @@ macro_rules! float_tests { <$scalar>::MIN, <$scalar>::MAX, <$scalar>::INFINITY, - -<$scalar>::INFINITY, + <$scalar>::NEG_INFINITY, <$scalar>::MIN_POSITIVE, -<$scalar>::MIN_POSITIVE, <$scalar>::EPSILON, -<$scalar>::EPSILON, - 0.0 / 0.0, - -0.0 / 0.0, - // Still not sure if wasm can have weird nans, or I'd check them - // too. Until then - 1.0 / 3.0, - -1.0 / 4.0 + <$scalar>::NAN, + -<$scalar>::NAN, + // TODO: Would be nice to check sNaN... + 100.0 / 3.0, + -100.0 / 3.0, ]; #[test] From 8d3d616b130e65bcb926645597b69fb136cc03b5 Mon Sep 17 00:00:00 2001 From: Thom Chiovoloni Date: Tue, 6 Oct 2020 13:40:39 -0700 Subject: [PATCH 3/3] Apply review feedback --- crates/core_simd/src/macros.rs | 3 +-- crates/core_simd/tests/ops_impl/float_macros.rs | 12 +++++++++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/crates/core_simd/src/macros.rs b/crates/core_simd/src/macros.rs index 214867c5ddce3..f37d13c3ca32e 100644 --- a/crates/core_simd/src/macros.rs +++ b/crates/core_simd/src/macros.rs @@ -295,8 +295,7 @@ macro_rules! impl_float_vector { #[inline] pub fn abs(self) -> Self { let no_sign = <$bits_ty>::splat(!0 >> 1); - let abs = unsafe { crate::intrinsics::simd_and(self.to_bits(), no_sign) }; - Self::from_bits(abs) + Self::from_bits(self.to_bits() & no_sign) } } }; diff --git a/crates/core_simd/tests/ops_impl/float_macros.rs b/crates/core_simd/tests/ops_impl/float_macros.rs index 141cb52207bee..1c969a2e8af3b 100644 --- a/crates/core_simd/tests/ops_impl/float_macros.rs +++ b/crates/core_simd/tests/ops_impl/float_macros.rs @@ -19,6 +19,11 @@ 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] = [ @@ -303,9 +308,10 @@ macro_rules! float_tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn abs_odd_floats() { - let v = from_slice(&C); - let expected = apply_unary_lanewise(v, <$scalar>::abs); - assert_biteq!(v.abs(), expected); + for v in slice_chunks(&C) { + let expected = apply_unary_lanewise(v, <$scalar>::abs); + assert_biteq!(v.abs(), expected); + } } } }