about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJubilee Young <workingjubilee@gmail.com>2021-12-08 18:42:06 -0800
committerJubilee Young <workingjubilee@gmail.com>2021-12-09 13:23:45 -0800
commit5dcd397f47a17aec3b049af2d7541530b859e47b (patch)
tree57401164ef99af0566f2daed4c8c1e1a90010361
parent049e8ca7f7fc42501b98afcb9c32fd51080bd75a (diff)
downloadrust-5dcd397f47a17aec3b049af2d7541530b859e47b.tar.gz
rust-5dcd397f47a17aec3b049af2d7541530b859e47b.zip
Finish refactoring ints in ops.rs
This should perform a SIMD check for whether or not we can div/rem,
so that we can panic several times faster!
-rw-r--r--crates/core_simd/src/ops.rs271
1 files changed, 147 insertions, 124 deletions
diff --git a/crates/core_simd/src/ops.rs b/crates/core_simd/src/ops.rs
index 65b461d3981..e6d7e695391 100644
--- a/crates/core_simd/src/ops.rs
+++ b/crates/core_simd/src/ops.rs
@@ -1,5 +1,4 @@
-use crate::simd::intrinsics;
-use crate::simd::{LaneCount, Simd, SimdElement, SupportedLaneCount};
+use crate::simd::{LaneCount, Mask, Simd, SimdElement, SupportedLaneCount};
 use core::ops::{Add, Mul};
 use core::ops::{BitAnd, BitOr, BitXor};
 use core::ops::{Div, Rem, Sub};
@@ -284,145 +283,169 @@ float_arith! {
     }
 }
 
-/// Automatically implements operators over references in addition to the provided operator.
-macro_rules! impl_ref_ops {
-    // binary op
-    {
-        impl<const $lanes:ident: usize> core::ops::$trait:ident<$rhs:ty> for $type:ty
-        where
-            LaneCount<$lanes2:ident>: SupportedLaneCount,
-        {
-            type Output = $output:ty;
-
-            $(#[$attrs:meta])*
-            fn $fn:ident($self_tok:ident, $rhs_arg:ident: $rhs_arg_ty:ty) -> Self::Output $body:tt
+// Division by zero is poison, according to LLVM.
+// So is dividing the MIN value of a signed integer by -1,
+// since that would return MAX + 1.
+// FIXME: Rust allows <SInt>::MIN / -1,
+// so we should probably figure out how to make that safe.
+macro_rules! int_divrem_guard {
+    ($(impl<const LANES: usize> $op:ident for Simd<$sint:ty, LANES> {
+        const PANIC_ZERO: &'static str = $zero:literal;
+        const PANIC_OVERFLOW: &'static str = $overflow:literal;
+        fn $call:ident {
+            unsafe { $simd_call:ident }
         }
-    } => {
-        impl<const $lanes: usize> core::ops::$trait<$rhs> for $type
+    })*) => {
+        $(impl<const LANES: usize> $op for Simd<$sint, LANES>
         where
-            LaneCount<$lanes2>: SupportedLaneCount,
+            $sint: SimdElement,
+            LaneCount<LANES>: SupportedLaneCount,
         {
-            type Output = $output;
-
-            $(#[$attrs])*
-            fn $fn($self_tok, $rhs_arg: $rhs_arg_ty) -> Self::Output $body
-        }
+            type Output = Self;
+            #[inline]
+            #[must_use = "operator returns a new vector without mutating the inputs"]
+            fn $call(self, rhs: Self) -> Self::Output {
+                if rhs.lanes_eq(Simd::splat(0)).any() {
+                    panic!("attempt to calculate the remainder with a divisor of zero");
+                } else if <$sint>::MIN != 0 && self.lanes_eq(Simd::splat(<$sint>::MIN)) & rhs.lanes_eq(Simd::splat(-1 as _))
+                    != Mask::splat(false)
+                 {
+                    panic!("attempt to calculate the remainder with overflow");
+                } else {
+                    unsafe { $crate::intrinsics::$simd_call(self, rhs) }
+                 }
+             }
+        })*
     };
 }
 
-/// Automatically implements operators over vectors and scalars for a particular vector.
-macro_rules! impl_op {
-    { impl Add for $scalar:ty } => {
-        impl_op! { @binary $scalar, Add::add, simd_add }
-    };
-    { impl Sub for $scalar:ty } => {
-        impl_op! { @binary $scalar, Sub::sub, simd_sub }
-    };
-    { impl Mul for $scalar:ty } => {
-        impl_op! { @binary $scalar, Mul::mul, simd_mul }
-    };
-    { impl Div for $scalar:ty } => {
-        impl_op! { @binary $scalar, Div::div, simd_div }
-    };
-    { impl Rem for $scalar:ty } => {
-        impl_op! { @binary $scalar, Rem::rem, simd_rem }
-    };
+macro_rules! int_arith {
+    ($(impl<const LANES: usize> IntArith for Simd<$sint:ty, LANES> {
+        fn add(self, rhs: Self) -> Self::Output;
+        fn mul(self, rhs: Self) -> Self::Output;
+        fn sub(self, rhs: Self) -> Self::Output;
+        fn div(self, rhs: Self) -> Self::Output;
+        fn rem(self, rhs: Self) -> Self::Output;
+    })*) => {
+        $(
+        unsafe_base_op!{
+            impl<const LANES: usize> Add for Simd<$sint, LANES> {
+                fn add(self, rhs: Self) -> Self::Output {
+                    unsafe { simd_add }
+                }
+            }
 
-    // generic binary op with assignment when output is `Self`
-    { @binary $scalar:ty, $trait:ident :: $trait_fn:ident, $intrinsic:ident } => {
-        impl_ref_ops! {
-            impl<const LANES: usize> core::ops::$trait<Self> for Simd<$scalar, LANES>
-            where
-                LaneCount<LANES>: SupportedLaneCount,
-            {
-                type Output = Self;
+            impl<const LANES: usize> Mul for Simd<$sint, LANES> {
+                fn mul(self, rhs: Self) -> Self::Output {
+                    unsafe { simd_mul }
+                }
+            }
 
-                #[inline]
-                fn $trait_fn(self, rhs: Self) -> Self::Output {
-                    unsafe {
-                        intrinsics::$intrinsic(self, rhs)
-                    }
+            impl<const LANES: usize> Sub for Simd<$sint, LANES> {
+                fn sub(self, rhs: Self) -> Self::Output {
+                    unsafe { simd_sub }
                 }
             }
         }
-    };
-}
 
-/// Implements unsigned integer operators for the provided types.
-macro_rules! impl_unsigned_int_ops {
-    { $($scalar:ty),* } => {
-        $(
-            impl_op! { impl Add for $scalar }
-            impl_op! { impl Sub for $scalar }
-            impl_op! { impl Mul for $scalar }
-
-            // Integers panic on divide by 0
-            impl_ref_ops! {
-                impl<const LANES: usize> core::ops::Div<Self> for Simd<$scalar, LANES>
-                where
-                    LaneCount<LANES>: SupportedLaneCount,
-                {
-                    type Output = Self;
-
-                    #[inline]
-                    fn div(self, rhs: Self) -> Self::Output {
-                        if rhs.as_array()
-                            .iter()
-                            .any(|x| *x == 0)
-                        {
-                            panic!("attempt to divide by zero");
-                        }
-
-                        // Guards for div(MIN, -1),
-                        // this check only applies to signed ints
-                        if <$scalar>::MIN != 0 && self.as_array().iter()
-                                .zip(rhs.as_array().iter())
-                                .any(|(x,y)| *x == <$scalar>::MIN && *y == -1 as _) {
-                            panic!("attempt to divide with overflow");
-                        }
-                        unsafe { intrinsics::simd_div(self, rhs) }
-                    }
+        int_divrem_guard!{
+            impl<const LANES: usize> Div for Simd<$sint, LANES> {
+                const PANIC_ZERO: &'static str = "attempt to divide by zero";
+                const PANIC_OVERFLOW: &'static str = "attempt to divide with overflow";
+                fn div {
+                    unsafe { simd_div }
                 }
             }
 
-            // remainder panics on zero divisor
-            impl_ref_ops! {
-                impl<const LANES: usize> core::ops::Rem<Self> for Simd<$scalar, LANES>
-                where
-                    LaneCount<LANES>: SupportedLaneCount,
-                {
-                    type Output = Self;
-
-                    #[inline]
-                    fn rem(self, rhs: Self) -> Self::Output {
-                        if rhs.as_array()
-                            .iter()
-                            .any(|x| *x == 0)
-                        {
-                            panic!("attempt to calculate the remainder with a divisor of zero");
-                        }
-
-                        // Guards for rem(MIN, -1)
-                        // this branch applies the check only to signed ints
-                        if <$scalar>::MIN != 0 && self.as_array().iter()
-                                .zip(rhs.as_array().iter())
-                                .any(|(x,y)| *x == <$scalar>::MIN && *y == -1 as _) {
-                            panic!("attempt to calculate the remainder with overflow");
-                        }
-                        unsafe { intrinsics::simd_rem(self, rhs) }
-                    }
+            impl<const LANES: usize> Rem for Simd<$sint, LANES> {
+                const PANIC_ZERO: &'static str = "attempt to calculate the remainder with a divisor of zero";
+                const PANIC_OVERFLOW: &'static str = "attempt to calculate the remainder with overflow";
+                fn rem {
+                    unsafe { simd_rem }
                 }
             }
-        )*
-    };
+        })*
+    }
 }
 
-/// Implements unsigned integer operators for the provided types.
-macro_rules! impl_signed_int_ops {
-    { $($scalar:ty),* } => {
-        impl_unsigned_int_ops! { $($scalar),* }
-    };
-}
+int_arith! {
+    impl<const LANES: usize> IntArith for Simd<i8, LANES> {
+        fn add(self, rhs: Self) -> Self::Output;
+        fn mul(self, rhs: Self) -> Self::Output;
+        fn sub(self, rhs: Self) -> Self::Output;
+        fn div(self, rhs: Self) -> Self::Output;
+        fn rem(self, rhs: Self) -> Self::Output;
+    }
 
-impl_unsigned_int_ops! { u8, u16, u32, u64, usize }
-impl_signed_int_ops! { i8, i16, i32, i64, isize }
+    impl<const LANES: usize> IntArith for Simd<i16, LANES> {
+        fn add(self, rhs: Self) -> Self::Output;
+        fn mul(self, rhs: Self) -> Self::Output;
+        fn sub(self, rhs: Self) -> Self::Output;
+        fn div(self, rhs: Self) -> Self::Output;
+        fn rem(self, rhs: Self) -> Self::Output;
+    }
+
+    impl<const LANES: usize> IntArith for Simd<i32, LANES> {
+        fn add(self, rhs: Self) -> Self::Output;
+        fn mul(self, rhs: Self) -> Self::Output;
+        fn sub(self, rhs: Self) -> Self::Output;
+        fn div(self, rhs: Self) -> Self::Output;
+        fn rem(self, rhs: Self) -> Self::Output;
+    }
+
+    impl<const LANES: usize> IntArith for Simd<i64, LANES> {
+        fn add(self, rhs: Self) -> Self::Output;
+        fn mul(self, rhs: Self) -> Self::Output;
+        fn sub(self, rhs: Self) -> Self::Output;
+        fn div(self, rhs: Self) -> Self::Output;
+        fn rem(self, rhs: Self) -> Self::Output;
+    }
+
+    impl<const LANES: usize> IntArith for Simd<isize, LANES> {
+        fn add(self, rhs: Self) -> Self::Output;
+        fn mul(self, rhs: Self) -> Self::Output;
+        fn sub(self, rhs: Self) -> Self::Output;
+        fn div(self, rhs: Self) -> Self::Output;
+        fn rem(self, rhs: Self) -> Self::Output;
+    }
+
+    impl<const LANES: usize> IntArith for Simd<u8, LANES> {
+        fn add(self, rhs: Self) -> Self::Output;
+        fn mul(self, rhs: Self) -> Self::Output;
+        fn sub(self, rhs: Self) -> Self::Output;
+        fn div(self, rhs: Self) -> Self::Output;
+        fn rem(self, rhs: Self) -> Self::Output;
+    }
+
+    impl<const LANES: usize> IntArith for Simd<u16, LANES> {
+        fn add(self, rhs: Self) -> Self::Output;
+        fn mul(self, rhs: Self) -> Self::Output;
+        fn sub(self, rhs: Self) -> Self::Output;
+        fn div(self, rhs: Self) -> Self::Output;
+        fn rem(self, rhs: Self) -> Self::Output;
+    }
+
+    impl<const LANES: usize> IntArith for Simd<u32, LANES> {
+        fn add(self, rhs: Self) -> Self::Output;
+        fn mul(self, rhs: Self) -> Self::Output;
+        fn sub(self, rhs: Self) -> Self::Output;
+        fn div(self, rhs: Self) -> Self::Output;
+        fn rem(self, rhs: Self) -> Self::Output;
+    }
+
+    impl<const LANES: usize> IntArith for Simd<u64, LANES> {
+        fn add(self, rhs: Self) -> Self::Output;
+        fn mul(self, rhs: Self) -> Self::Output;
+        fn sub(self, rhs: Self) -> Self::Output;
+        fn div(self, rhs: Self) -> Self::Output;
+        fn rem(self, rhs: Self) -> Self::Output;
+    }
+
+    impl<const LANES: usize> IntArith for Simd<usize, LANES> {
+        fn add(self, rhs: Self) -> Self::Output;
+        fn mul(self, rhs: Self) -> Self::Output;
+        fn sub(self, rhs: Self) -> Self::Output;
+        fn div(self, rhs: Self) -> Self::Output;
+        fn rem(self, rhs: Self) -> Self::Output;
+    }
+}