]> git.lizzy.rs Git - rust.git/blob - crates/core_simd/src/macros.rs
6b5599f0170d667afc43fec8bd960749418d1291
[rust.git] / crates / core_simd / src / macros.rs
1 /// Provides implementations of `From<$a> for $b` and `From<$b> for $a` that transmutes the value.
2 macro_rules! from_transmute {
3     { unsafe $a:ty => $b:ty } => {
4         from_transmute!{ @impl $a => $b }
5         from_transmute!{ @impl $b => $a }
6     };
7     { @impl $from:ty => $to:ty } => {
8         impl core::convert::From<$from> for $to {
9             #[inline]
10             fn from(value: $from) -> $to {
11                 unsafe { core::mem::transmute(value) }
12             }
13         }
14     };
15 }
16
17 /// Provides implementations of `From<$generic> for core::arch::{x86, x86_64}::$intel` and
18 /// vice-versa that transmutes the value.
19 macro_rules! from_transmute_x86 {
20     { unsafe $generic:ty => $intel:ident } => {
21         #[cfg(target_arch = "x86")]
22         from_transmute! { unsafe $generic => core::arch::x86::$intel }
23
24         #[cfg(target_arch = "x86_64")]
25         from_transmute! { unsafe $generic => core::arch::x86_64::$intel }
26     }
27 }
28
29 /// Calls a the macro `$mac` with the provided `$args` followed by `$repeat` repeated the specified
30 /// number of times.
31 macro_rules! call_repeat {
32     { 1 => $mac:path [$($repeat:tt)*] $($args:tt)* } => {
33         $mac! {
34             $($args)*
35             $($repeat)*
36         }
37     };
38     { 2 => $mac:path [$($repeat:tt)*] $($args:tt)* } => {
39         $mac! {
40             $($args)*
41             $($repeat)* $($repeat)*
42         }
43     };
44     { 4 => $mac:path [$($repeat:tt)*] $($args:tt)* } => {
45         $mac! {
46             $($args)*
47             $($repeat)* $($repeat)* $($repeat)* $($repeat)*
48         }
49     };
50     { 8 => $mac:path [$($repeat:tt)*] $($args:tt)* } => {
51         $mac! {
52             $($args)*
53             $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)*
54         }
55     };
56     { 16 => $mac:path [$($repeat:tt)*] $($args:tt)* } => {
57         $mac! {
58             $($args)*
59             $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)*
60             $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)*
61         }
62     };
63     { 32 => $mac:path [$($repeat:tt)*] $($args:tt)* } => {
64         $mac! {
65             $($args)*
66             $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)*
67             $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)*
68             $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)*
69             $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)*
70         }
71     };
72     { 64 => $mac:path [$($repeat:tt)*] $($args:tt)* } => {
73         $mac! {
74             $($args)*
75             $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)*
76             $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)*
77             $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)*
78             $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)*
79             $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)*
80             $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)*
81             $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)*
82             $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)* $($repeat)*
83         }
84     };
85 }
86
87 /// Calls the macro `$mac` with the specified `$args` followed by the specified number of unique
88 /// identifiers.
89 macro_rules! call_counting_args {
90     { 1 => $mac:path => $($args:tt)* } => {
91         $mac! {
92             $($args)*
93             value
94         }
95     };
96     { 2 => $mac:path => $($args:tt)* } => {
97         $mac! {
98             $($args)*
99             v0 v1
100         }
101     };
102     { 4 => $mac:path => $($args:tt)* } => {
103         $mac! {
104             $($args)*
105             v0 v1 v2 v3
106         }
107     };
108     { 8 => $mac:path => $($args:tt)* } => {
109         $mac! {
110             $($args)*
111             v0 v1 v2 v3 v4 v5 v6 v7
112         }
113     };
114     { 16 => $mac:path => $($args:tt)* } => {
115         $mac! {
116             $($args)*
117             v0 v1 v2 v3 v4 v5 v6 v7 v8 v9 v10 v11 v12 v13 v14 v15
118         }
119     };
120     { 32 => $mac:path => $($args:tt)* } => {
121         $mac! {
122             $($args)*
123             v0  v1  v2  v3  v4  v5  v6  v7  v8  v9  v10 v11 v12 v13 v14 v15
124             v16 v17 v18 v19 v20 v21 v22 v23 v24 v25 v26 v27 v28 v29 v30 v31
125         }
126     };
127     { 64 => $mac:path => $($args:tt)* } => {
128         $mac! {
129             $($args)*
130             v0  v1  v2  v3  v4  v5  v6  v7  v8  v9  v10 v11 v12 v13 v14 v15
131             v16 v17 v18 v19 v20 v21 v22 v23 v24 v25 v26 v27 v28 v29 v30 v31
132             v32 v33 v34 v35 v36 v37 v38 v39 v40 v41 v42 v43 v44 v45 v46 v47
133             v48 v49 v50 v51 v52 v53 v54 v55 v56 v57 v58 v59 v60 v61 v62 v63
134         }
135     };
136 }
137
138 /// Calls the macro `$mac` with the specified `$args` followed by counting values from 0 to the
139 /// specified value.
140 macro_rules! call_counting_values {
141     { 1 => $mac:path => $($args:tt)* } => {
142         $mac! {
143             $($args)*
144             0
145         }
146     };
147     { 2 => $mac:path => $($args:tt)* } => {
148         $mac! {
149             $($args)*
150             0 1
151         }
152     };
153     { 4 => $mac:path => $($args:tt)* } => {
154         $mac! {
155             $($args)*
156             0 1 2 3
157         }
158     };
159     { 8 => $mac:path => $($args:tt)* } => {
160         $mac! {
161             $($args)*
162             0 1 2 3 4 5 6 7
163         }
164     };
165     { 16 => $mac:path => $($args:tt)* } => {
166         $mac! {
167             $($args)*
168             0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
169         }
170     };
171     { 32 => $mac:path => $($args:tt)* } => {
172         $mac! {
173             $($args)*
174             0  1  2  3  4  5  6  7  8  9  10 11 12 13 14 15
175             16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
176         }
177     };
178     { 64 => $mac:path => $($args:tt)* } => {
179         $mac! {
180             $($args)*
181             0  1  2  3  4  5  6  7  8  9  10 11 12 13 14 15
182             16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
183             32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
184             48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
185         }
186     };
187 }
188
189 /// Implements common traits on the specified vector `$name`, holding multiple `$lanes` of `$type`.
190 macro_rules! base_vector_traits {
191     { $name:path => [$type:ty; $lanes:literal] } => {
192         // array references
193         impl AsRef<[$type; $lanes]> for $name {
194             #[inline]
195             fn as_ref(&self) -> &[$type; $lanes] {
196                 unsafe { &*(self as *const _ as *const _) }
197             }
198         }
199
200         impl AsMut<[$type; $lanes]> for $name {
201             #[inline]
202             fn as_mut(&mut self) -> &mut [$type; $lanes] {
203                 unsafe { &mut *(self as *mut _ as *mut _) }
204             }
205         }
206
207         // slice references
208         impl AsRef<[$type]> for $name {
209             #[inline]
210             fn as_ref(&self) -> &[$type] {
211                 AsRef::<[$type; $lanes]>::as_ref(self)
212             }
213         }
214
215         impl AsMut<[$type]> for $name {
216             #[inline]
217             fn as_mut(&mut self) -> &mut [$type] {
218                 AsMut::<[$type; $lanes]>::as_mut(self)
219             }
220         }
221
222         // vector/array conversion
223         from_transmute! { unsafe $name => [$type; $lanes] }
224
225         // splat
226         impl From<$type> for $name {
227             #[inline]
228             fn from(value: $type) -> Self {
229                 Self::splat(value)
230             }
231         }
232     }
233 }
234
235 /// Defines a vector `$name` containing multiple `$lanes` of `$type`.
236 macro_rules! define_vector {
237     { $(#[$attr:meta])* struct $name:ident([$type:ty; $lanes:tt]); } => {
238         call_repeat! { $lanes => define_vector [$type] def $(#[$attr])* | $name | }
239
240         impl $name {
241             call_repeat! { $lanes => define_vector [$type] splat $type | }
242             call_counting_args! { $lanes => define_vector => new $type | }
243         }
244
245         base_vector_traits! { $name => [$type; $lanes] }
246     };
247     { def $(#[$attr:meta])* | $name:ident | $($itype:ty)* } => {
248         $(#[$attr])*
249         #[allow(non_camel_case_types)]
250         #[derive(Copy, Clone, Debug, Default, PartialEq, PartialOrd)]
251         #[repr(simd)]
252         pub struct $name($($itype),*);
253     };
254     { splat $type:ty | $($itype:ty)* } => {
255         /// Construct a vector by setting all lanes to the given value.
256         #[inline]
257         pub const fn splat(value: $type) -> Self {
258             Self($(value as $itype),*)
259         }
260     };
261     { new $type:ty | $($var:ident)* } => {
262         /// Construct a vector by setting each lane to the given values.
263         #[allow(clippy::too_many_arguments)]
264         #[inline]
265         pub const fn new($($var: $type),*) -> Self {
266             Self($($var),*)
267         }
268     }
269 }
270
271 /// Defines a mask vector `$name` containing multiple `$lanes` of `$type`, represented by the
272 /// underlying type `$impl_type`.
273 macro_rules! define_mask_vector {
274     { $(#[$attr:meta])* struct $name:ident([$impl_type:ty as $type:ty; $lanes:tt]); } => {
275         call_repeat! { $lanes => define_mask_vector [$impl_type] def $(#[$attr])* | $name | }
276
277         impl $name {
278             call_repeat! { $lanes => define_mask_vector [$impl_type] splat $type | }
279             call_counting_args! { $lanes => define_mask_vector => new $type | }
280         }
281
282         base_vector_traits! { $name => [$type; $lanes] }
283     };
284     { def $(#[$attr:meta])* | $name:ident | $($itype:ty)* } => {
285         $(#[$attr])*
286         #[allow(non_camel_case_types)]
287         #[derive(Copy, Clone, Debug, Default, PartialEq, PartialOrd, Eq, Ord)]
288         #[repr(simd)]
289         pub struct $name($($itype),*);
290     };
291     { splat $type:ty | $($itype:ty)* } => {
292         /// Construct a vector by setting all lanes to the given value.
293         #[inline]
294         pub const fn splat(value: $type) -> Self {
295             Self($(value.0 as $itype),*)
296         }
297     };
298     { new $type:ty | $($var:ident)* } => {
299         /// Construct a vector by setting each lane to the given values.
300         #[allow(clippy::too_many_arguments)]
301         #[inline]
302         pub const fn new($($var: $type),*) -> Self {
303             Self($($var.0),*)
304         }
305     }
306 }