about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJubilee Young <workingjubilee@gmail.com>2021-12-01 15:02:03 -0800
committerJubilee Young <workingjubilee@gmail.com>2021-12-01 15:45:01 -0800
commit8003b043233213c6f984837d7618f92a6181a875 (patch)
tree44c54874366877e578dfd9d6af27246272bcb8d9
parent257fa7aa6d03157476f0d6acd9a0b4c28a3877ec (diff)
downloadrust-8003b043233213c6f984837d7618f92a6181a875.tar.gz
rust-8003b043233213c6f984837d7618f92a6181a875.zip
impl Op<&'_ RHS> for &'_ LHS
-rw-r--r--crates/core_simd/src/ops/deref.rs114
-rw-r--r--crates/core_simd/tests/autoderef.rs22
2 files changed, 106 insertions, 30 deletions
diff --git a/crates/core_simd/src/ops/deref.rs b/crates/core_simd/src/ops/deref.rs
index 1138b9494f6..9883a74c92d 100644
--- a/crates/core_simd/src/ops/deref.rs
+++ b/crates/core_simd/src/ops/deref.rs
@@ -1,70 +1,124 @@
 //! This module hacks in "implicit deref" for Simd's operators.
 //! Ideally, Rust would take care of this itself,
 //! and method calls usually handle the LHS implicitly.
-//! So, we'll manually deref the RHS.
+//! But this is not the case with arithmetic ops.
 use super::*;
 
-macro_rules! deref_ops {
-    ($(impl<T, const LANES: usize> $trait:ident<&Self> for Simd<T, LANES> {
-            fn $call:ident(rhs: &Self)
-        })*) => {
-        $(impl<T, const LANES: usize> $trait<&Self> for Simd<T, LANES>
+macro_rules! deref_lhs {
+    (impl<T, const LANES: usize> $trait:ident for $simd:ty {
+            fn $call:ident
+        }) => {
+        impl<T, const LANES: usize> $trait<$simd> for &$simd
+        where
+            T: SimdElement,
+            $simd: $trait<$simd, Output = $simd>,
+            LaneCount<LANES>: SupportedLaneCount,
+        {
+            type Output = Simd<T, LANES>;
+
+            #[inline]
+            #[must_use = "operator returns a new vector without mutating the inputs"]
+            fn $call(self, rhs: $simd) -> Self::Output {
+                (*self).$call(rhs)
+            }
+        }
+    };
+}
+
+macro_rules! deref_rhs {
+    (impl<T, const LANES: usize> $trait:ident for $simd:ty {
+            fn $call:ident
+        }) => {
+        impl<T, const LANES: usize> $trait<&$simd> for $simd
         where
-            Self: $trait<Self, Output = Self>,
             T: SimdElement,
+            $simd: $trait<$simd, Output = $simd>,
             LaneCount<LANES>: SupportedLaneCount,
         {
-            type Output = Self;
+            type Output = Simd<T, LANES>;
 
             #[inline]
             #[must_use = "operator returns a new vector without mutating the inputs"]
-            fn $call(self, rhs: &Self) -> Self::Output {
+            fn $call(self, rhs: &$simd) -> Self::Output {
                 self.$call(*rhs)
             }
-        })*
+        }
+    };
+}
+
+macro_rules! deref_ops {
+    ($(impl<T, const LANES: usize> $trait:ident for $simd:ty {
+            fn $call:ident
+        })*) => {
+        $(
+            deref_rhs! {
+                impl<T, const LANES: usize> $trait for $simd {
+                    fn $call
+                }
+            }
+            deref_lhs! {
+                impl<T, const LANES: usize> $trait for $simd {
+                    fn $call
+                }
+            }
+            impl<'lhs, 'rhs, T, const LANES: usize> $trait<&'rhs $simd> for &'lhs $simd
+            where
+                T: SimdElement,
+                $simd: $trait<$simd, Output = $simd>,
+                LaneCount<LANES>: SupportedLaneCount,
+            {
+                type Output = $simd;
+
+                #[inline]
+                #[must_use = "operator returns a new vector without mutating the inputs"]
+                fn $call(self, rhs: &$simd) -> Self::Output {
+                    (*self).$call(*rhs)
+                }
+            }
+        )*
     }
 }
 
 deref_ops! {
     // Arithmetic
-    impl<T, const LANES: usize> Add<&Self> for Simd<T, LANES> {
-        fn add(rhs: &Self)
+    impl<T, const LANES: usize> Add for Simd<T, LANES> {
+        fn add
     }
 
-    impl<T, const LANES: usize> Mul<&Self> for Simd<T, LANES> {
-        fn mul(rhs: &Self)
+    impl<T, const LANES: usize> Mul for Simd<T, LANES> {
+        fn mul
     }
 
-    impl<T, const LANES: usize> Sub<&Self> for Simd<T, LANES> {
-        fn sub(rhs: &Self)
+    impl<T, const LANES: usize> Sub for Simd<T, LANES> {
+        fn sub
     }
 
-    impl<T, const LANES: usize> Div<&Self> for Simd<T, LANES> {
-        fn div(rhs: &Self)
+    impl<T, const LANES: usize> Div for Simd<T, LANES> {
+        fn div
     }
 
-    impl<T, const LANES: usize> Rem<&Self> for Simd<T, LANES> {
-        fn rem(rhs: &Self)
+    impl<T, const LANES: usize> Rem for Simd<T, LANES> {
+        fn rem
     }
 
     // Bitops
-    impl<T, const LANES: usize> BitAnd<&Self> for Simd<T, LANES> {
-        fn bitand(rhs: &Self)
+    impl<T, const LANES: usize> BitAnd for Simd<T, LANES> {
+        fn bitand
     }
 
-    impl<T, const LANES: usize> BitOr<&Self> for Simd<T, LANES> {
-        fn bitor(rhs: &Self)
+    impl<T, const LANES: usize> BitOr for Simd<T, LANES> {
+        fn bitor
     }
 
-    impl<T, const LANES: usize> BitXor<&Self> for Simd<T, LANES> {
-        fn bitxor(rhs: &Self)
+    impl<T, const LANES: usize> BitXor for Simd<T, LANES> {
+        fn bitxor
     }
 
-    impl<T, const LANES: usize> Shl<&Self> for Simd<T, LANES> {
-        fn shl(rhs: &Self)
+    impl<T, const LANES: usize> Shl for Simd<T, LANES> {
+        fn shl
     }
 
-    impl<T, const LANES: usize> Shr<&Self> for Simd<T, LANES> {
-        fn shr(rhs: &Self)
+    impl<T, const LANES: usize> Shr for Simd<T, LANES> {
+        fn shr
     }
 }
diff --git a/crates/core_simd/tests/autoderef.rs b/crates/core_simd/tests/autoderef.rs
new file mode 100644
index 00000000000..9359da16ee5
--- /dev/null
+++ b/crates/core_simd/tests/autoderef.rs
@@ -0,0 +1,22 @@
+// Test that we handle all our "auto-deref" cases correctly.
+#![feature(portable_simd)]
+use core_simd::f32x4;
+
+#[cfg(target_arch = "wasm32")]
+use wasm_bindgen_test::*;
+
+#[cfg(target_arch = "wasm32")]
+wasm_bindgen_test_configure!(run_in_browser);
+
+#[test]
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
+fn deref() {
+    let x = f32x4::splat(1.0);
+    let y = f32x4::splat(2.0);
+    let a = &x;
+    let b = &y;
+    assert_eq!(f32x4::splat(3.0), x + y);
+    assert_eq!(f32x4::splat(3.0), x + b);
+    assert_eq!(f32x4::splat(3.0), a + y);
+    assert_eq!(f32x4::splat(3.0), a + b);
+}