]> git.lizzy.rs Git - rust.git/blobdiff - crates/core_simd/src/macros.rs
Manually implement some traits, instead of derive
[rust.git] / crates / core_simd / src / macros.rs
index 91c1071a2ee5fbea85bcb3b29936e35a2b60efec..ecf2b76ceb0d315a33cb4388f6cfb3c896f824f7 100644 (file)
-macro_rules! from_aligned {
-    { unsafe $from:ty => $to:ty } => {
+/// Provides implementations of `From<$a> for $b` and `From<$b> for $a` that transmutes the value.
+macro_rules! from_transmute {
+    { unsafe $a:ty => $b:ty } => {
+        from_transmute!{ @impl $a => $b }
+        from_transmute!{ @impl $b => $a }
+    };
+    { @impl $from:ty => $to:ty } => {
         impl core::convert::From<$from> for $to {
             #[inline]
             fn from(value: $from) -> $to {
-                assert_eq!(core::mem::size_of::<$from>(), core::mem::size_of::<$to>());
-                assert!(core::mem::align_of::<$from>() >= core::mem::align_of::<$to>());
                 unsafe { core::mem::transmute(value) }
             }
         }
     };
-    { unsafe $a:ty |bidirectional| $b:ty } => {
-        from_aligned!{ unsafe $a => $b }
-        from_aligned!{ unsafe $b => $a }
+}
+
+/// Provides implementations of `From<$generic> for core::arch::{x86, x86_64}::$intel` and
+/// vice-versa that transmutes the value.
+macro_rules! from_transmute_x86 {
+    { unsafe $generic:ty => $intel:ident } => {
+        #[cfg(target_arch = "x86")]
+        from_transmute! { unsafe $generic => core::arch::x86::$intel }
+
+        #[cfg(target_arch = "x86_64")]
+        from_transmute! { unsafe $generic => core::arch::x86_64::$intel }
     }
 }
 
-macro_rules! from_unaligned {
-    { unsafe $from:ty => $to:ty } => {
-        impl core::convert::From<$from> for $to {
-            #[inline]
-            fn from(value: $from) -> $to {
-                assert_eq!(core::mem::size_of::<$from>(), core::mem::size_of::<$to>());
-                unsafe { (&value as *const $from as *const $to).read_unaligned() }
-            }
+/// Calls a the macro `$mac` with the provided `$args` followed by `$repeat` repeated the specified
+/// number of times.
+macro_rules! call_repeat {
+    { 1 => $mac:path [$($repeat:tt)*] $($args:tt)* } => {
+        $mac! {
+            $($args)*
+            $($repeat)*
         }
-    }
+    };
+    { 2 => $mac:path [$($repeat:tt)*] $($args:tt)* } => {
+        $mac! {
+            $($args)*
+            $($repeat)* $($repeat)*
+        }
+    };
+    { 4 => $mac:path [$($repeat:tt)*] $($args:tt)* } => {
+        $mac! {
+            $($args)*
+            $($repeat)* $($repeat)* $($repeat)* $($repeat)*
+        }
+    };
+    { 8 => $mac:path [$($repeat:tt)*] $($args:tt)* } => {
+        $mac! {
+            $($args)*
+            $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)*
+        }
+    };
+    { 16 => $mac:path [$($repeat:tt)*] $($args:tt)* } => {
+        $mac! {
+            $($args)*
+            $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)*
+            $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)*
+        }
+    };
+    { 32 => $mac:path [$($repeat:tt)*] $($args:tt)* } => {
+        $mac! {
+            $($args)*
+            $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)*
+            $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)*
+            $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)*
+            $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)*
+        }
+    };
+    { 64 => $mac:path [$($repeat:tt)*] $($args:tt)* } => {
+        $mac! {
+            $($args)*
+            $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)*
+            $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)*
+            $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)*
+            $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)*
+            $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)*
+            $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)*
+            $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)*
+            $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)*
+        }
+    };
 }
 
-macro_rules! define_type {
-    { $(#[$attr:meta])* struct $name:ident([$type:ty; $lanes:tt]); } => {
-        define_type! { @impl $(#[$attr])* | $name [$type; $lanes] }
+/// Calls the macro `$mac` with the specified `$args` followed by the specified number of unique
+/// identifiers.
+macro_rules! call_counting_args {
+    { 1 => $mac:path => $($args:tt)* } => {
+        $mac! {
+            $($args)*
+            value
+        }
+    };
+    { 2 => $mac:path => $($args:tt)* } => {
+        $mac! {
+            $($args)*
+            v0 v1
+        }
+    };
+    { 4 => $mac:path => $($args:tt)* } => {
+        $mac! {
+            $($args)*
+            v0 v1 v2 v3
+        }
+    };
+    { 8 => $mac:path => $($args:tt)* } => {
+        $mac! {
+            $($args)*
+            v0 v1 v2 v3 v4 v5 v6 v7
+        }
+    };
+    { 16 => $mac:path => $($args:tt)* } => {
+        $mac! {
+            $($args)*
+            v0 v1 v2 v3 v4 v5 v6 v7 v8 v9 v10 v11 v12 v13 v14 v15
+        }
+    };
+    { 32 => $mac:path => $($args:tt)* } => {
+        $mac! {
+            $($args)*
+            v0  v1  v2  v3  v4  v5  v6  v7  v8  v9  v10 v11 v12 v13 v14 v15
+            v16 v17 v18 v19 v20 v21 v22 v23 v24 v25 v26 v27 v28 v29 v30 v31
+        }
+    };
+    { 64 => $mac:path => $($args:tt)* } => {
+        $mac! {
+            $($args)*
+            v0  v1  v2  v3  v4  v5  v6  v7  v8  v9  v10 v11 v12 v13 v14 v15
+            v16 v17 v18 v19 v20 v21 v22 v23 v24 v25 v26 v27 v28 v29 v30 v31
+            v32 v33 v34 v35 v36 v37 v38 v39 v40 v41 v42 v43 v44 v45 v46 v47
+            v48 v49 v50 v51 v52 v53 v54 v55 v56 v57 v58 v59 v60 v61 v62 v63
+        }
+    };
+}
+
+/// Implements common traits on the specified vector `$name`, holding multiple `$lanes` of `$type`.
+macro_rules! base_vector_traits {
+    { $name:path => [$type:ty; $lanes:literal] } => {
+        impl Copy for $name {}
+
+        impl Clone for $name {
+            fn clone(&self) -> Self {
+                *self
+            }
+        }
+
+        impl Default for $name {
+            fn default() -> Self {
+                Self::splat(<$type>::default())
+            }
+        }
+
+        impl PartialEq for $name {
+            fn eq(&self, other: &Self) -> bool {
+                AsRef::<[$type]>::as_ref(self) == AsRef::<[$type]>::as_ref(other)
+            }
+        }
+
+        impl PartialOrd for $name {
+            fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
+                AsRef::<[$type]>::as_ref(self).partial_cmp(AsRef::<[$type]>::as_ref(other))
+            }
+        }
 
         // array references
         impl AsRef<[$type; $lanes]> for $name {
@@ -61,11 +194,8 @@ fn as_mut(&mut self) -> &mut [$type] {
             }
         }
 
-        // vector to array
-        from_aligned! { unsafe $name => [$type; $lanes] }
-
-        // array to vector
-        from_unaligned! { unsafe [$type; $lanes] => $name }
+        // vector/array conversion
+        from_transmute! { unsafe $name => [$type; $lanes] }
 
         // splat
         impl From<$type> for $name {
@@ -74,71 +204,77 @@ fn from(value: $type) -> Self {
                 Self::splat(value)
             }
         }
-    };
-    { @impl $(#[$attr:meta])* | $name:ident [$type:ty; 1] } => {
-        define_type! { @def $(#[$attr])* | $name | $type | $type, | v0, }
-    };
-    { @impl $(#[$attr:meta])* | $name:ident [$type:ty; 2] } => {
-        define_type! { @def $(#[$attr])* | $name | $type | $type, $type, | v0, v1, }
-    };
-    { @impl $(#[$attr:meta])* | $name:ident [$type:ty; 4] } => {
-        define_type! { @def $(#[$attr])* | $name | $type |
-            $type, $type, $type, $type, |
-            v0, v1, v2, v3,
+    }
+}
+
+/// Defines a vector `$name` containing multiple `$lanes` of `$type`.
+macro_rules! define_vector {
+    { $(#[$attr:meta])* struct $name:ident([$type:ty; $lanes:tt]); } => {
+        call_repeat! { $lanes => define_vector [$type] def $(#[$attr])* | $name | }
+
+        impl $name {
+            call_repeat! { $lanes => define_vector [$type] splat $type | }
+            call_counting_args! { $lanes => define_vector => new $type | }
         }
+
+        base_vector_traits! { $name => [$type; $lanes] }
     };
-    { @impl $(#[$attr:meta])* | $name:ident [$type:ty; 8] } => {
-        define_type! { @def $(#[$attr])* | $name | $type |
-            $type, $type, $type, $type, $type, $type, $type, $type, |
-            v0, v1, v2, v3, v4, v5, v6, v7,
-        }
+    { def $(#[$attr:meta])* | $name:ident | $($itype:ty)* } => {
+        $(#[$attr])*
+        #[allow(non_camel_case_types)]
+        #[repr(simd)]
+        pub struct $name($($itype),*);
     };
-    { @impl $(#[$attr:meta])* | $name:ident [$type:ty; 16] } => {
-        define_type! { @def $(#[$attr])* | $name | $type |
-            $type, $type, $type, $type, $type, $type, $type, $type, $type, $type, $type, $type, $type, $type, $type, $type, |
-            v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15,
+    { splat $type:ty | $($itype:ty)* } => {
+        /// Construct a vector by setting all lanes to the given value.
+        #[inline]
+        pub const fn splat(value: $type) -> Self {
+            Self($(value as $itype),*)
         }
     };
-    { @impl $(#[$attr:meta])* | $name:ident [$type:ty; 32] } => {
-        define_type! { @def $(#[$attr])* | $name | $type |
-            $type, $type, $type, $type, $type, $type, $type, $type, $type, $type, $type, $type, $type, $type, $type, $type,
-            $type, $type, $type, $type, $type, $type, $type, $type, $type, $type, $type, $type, $type, $type, $type, $type, |
-            v0,  v1,  v2,  v3,  v4,  v5,  v6,  v7,  v8,  v9,  v10, v11, v12, v13, v14, v15,
-            v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31,
+    { new $type:ty | $($var:ident)* } => {
+        /// Construct a vector by setting each lane to the given values.
+        #[allow(clippy::too_many_arguments)]
+        #[inline]
+        pub const fn new($($var: $type),*) -> Self {
+            Self($($var),*)
         }
-    };
-    { @impl $(#[$attr:meta])* | $name:ident [$type:ty; 64] } => {
-        define_type! { @def $(#[$attr])* | $name | $type |
-            $type, $type, $type, $type, $type, $type, $type, $type, $type, $type, $type, $type, $type, $type, $type, $type,
-            $type, $type, $type, $type, $type, $type, $type, $type, $type, $type, $type, $type, $type, $type, $type, $type,
-            $type, $type, $type, $type, $type, $type, $type, $type, $type, $type, $type, $type, $type, $type, $type, $type,
-            $type, $type, $type, $type, $type, $type, $type, $type, $type, $type, $type, $type, $type, $type, $type, $type, |
-            v0,  v1,  v2,  v3,  v4,  v5,  v6,  v7,  v8,  v9,  v10, v11, v12, v13, v14, v15,
-            v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31,
-            v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47,
-            v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62, v63,
+    }
+}
+
+/// Defines a mask vector `$name` containing multiple `$lanes` of `$type`, represented by the
+/// underlying type `$impl_type`.
+macro_rules! define_mask_vector {
+    { $(#[$attr:meta])* struct $name:ident([$impl_type:ty as $type:ty; $lanes:tt]); } => {
+        call_repeat! { $lanes => define_mask_vector [$impl_type] def $(#[$attr])* | $name | }
+
+        impl $name {
+            call_repeat! { $lanes => define_mask_vector [$impl_type] splat $type | }
+            call_counting_args! { $lanes => define_mask_vector => new $type | }
         }
+
+        base_vector_traits! { $name => [$type; $lanes] }
     };
-    { @def $(#[$attr:meta])* | $name:ident | $type:ty | $($itype:ty,)* | $($ivar:ident,)* } => {
+    { def $(#[$attr:meta])* | $name:ident | $($itype:ty)* } => {
         $(#[$attr])*
         #[allow(non_camel_case_types)]
-        #[derive(Copy, Clone, Debug, Default, PartialEq, PartialOrd)]
+        #[derive(Eq, Ord)]
         #[repr(simd)]
         pub struct $name($($itype),*);
-
-        impl $name {
-            /// Construct a vector by setting all lanes to the given value.
-            #[inline]
-            pub const fn splat(value: $type) -> Self {
-                Self($(value as $itype),*)
-            }
-
-            /// Construct a vector by setting each lane to the given values.
-            #[allow(clippy::too_many_arguments)]
-            #[inline]
-            pub const fn new($($ivar: $itype),*) -> Self {
-                Self($($ivar),*)
-            }
+    };
+    { splat $type:ty | $($itype:ty)* } => {
+        /// Construct a vector by setting all lanes to the given value.
+        #[inline]
+        pub const fn splat(value: $type) -> Self {
+            Self($(value.0 as $itype),*)
+        }
+    };
+    { new $type:ty | $($var:ident)* } => {
+        /// Construct a vector by setting each lane to the given values.
+        #[allow(clippy::too_many_arguments)]
+        #[inline]
+        pub const fn new($($var: $type),*) -> Self {
+            Self($($var.0),*)
         }
     }
 }