]> git.lizzy.rs Git - rust.git/blob - crates/core_simd/src/macros.rs
Add opaque masks
[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 /// Implements common traits on the specified vector `$name`, holding multiple `$lanes` of `$type`.
139 macro_rules! base_vector_traits {
140     { $name:path => [$type:ty; $lanes:literal] } => {
141         impl Copy for $name {}
142
143         impl Clone for $name {
144             #[inline]
145             fn clone(&self) -> Self {
146                 *self
147             }
148         }
149
150         impl Default for $name {
151             #[inline]
152             fn default() -> Self {
153                 Self::splat(<$type>::default())
154             }
155         }
156
157         impl PartialEq for $name {
158             #[inline]
159             fn eq(&self, other: &Self) -> bool {
160                 AsRef::<[$type]>::as_ref(self) == AsRef::<[$type]>::as_ref(other)
161             }
162         }
163
164         impl PartialOrd for $name {
165             #[inline]
166             fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
167                 AsRef::<[$type]>::as_ref(self).partial_cmp(AsRef::<[$type]>::as_ref(other))
168             }
169         }
170
171         // array references
172         impl AsRef<[$type; $lanes]> for $name {
173             #[inline]
174             fn as_ref(&self) -> &[$type; $lanes] {
175                 unsafe { &*(self as *const _ as *const _) }
176             }
177         }
178
179         impl AsMut<[$type; $lanes]> for $name {
180             #[inline]
181             fn as_mut(&mut self) -> &mut [$type; $lanes] {
182                 unsafe { &mut *(self as *mut _ as *mut _) }
183             }
184         }
185
186         // slice references
187         impl AsRef<[$type]> for $name {
188             #[inline]
189             fn as_ref(&self) -> &[$type] {
190                 AsRef::<[$type; $lanes]>::as_ref(self)
191             }
192         }
193
194         impl AsMut<[$type]> for $name {
195             #[inline]
196             fn as_mut(&mut self) -> &mut [$type] {
197                 AsMut::<[$type; $lanes]>::as_mut(self)
198             }
199         }
200
201         // vector/array conversion
202         from_transmute! { unsafe $name => [$type; $lanes] }
203
204         // splat
205         impl From<$type> for $name {
206             #[inline]
207             fn from(value: $type) -> Self {
208                 Self::splat(value)
209             }
210         }
211     }
212 }
213
214 /// Implements additional integer traits (Eq, Ord, Hash) on the specified vector `$name`, holding multiple `$lanes` of `$type`.
215 macro_rules! integer_vector_traits {
216     { $name:path => [$type:ty; $lanes:literal] } => {
217         impl Eq for $name {}
218
219         impl Ord for $name {
220             #[inline]
221             fn cmp(&self, other: &Self) -> core::cmp::Ordering {
222                 AsRef::<[$type]>::as_ref(self).cmp(AsRef::<[$type]>::as_ref(other))
223             }
224         }
225
226         impl core::hash::Hash for $name {
227             #[inline]
228             fn hash<H>(&self, state: &mut H)
229             where
230                 H: core::hash::Hasher
231             {
232                 AsRef::<[$type]>::as_ref(self).hash(state)
233             }
234         }
235     }
236 }
237
238 /// Defines a vector `$name` containing multiple `$lanes` of `$type`.
239 macro_rules! define_vector {
240     { $(#[$attr:meta])* struct $name:ident([$type:ty; $lanes:tt]); } => {
241         call_repeat! { $lanes => define_vector [$type] def $(#[$attr])* | $name | }
242
243         impl $name {
244             call_repeat! { $lanes => define_vector [$type] splat $type | }
245             call_counting_args! { $lanes => define_vector => new $type | }
246         }
247
248         base_vector_traits! { $name => [$type; $lanes] }
249     };
250     { def $(#[$attr:meta])* | $name:ident | $($itype:ty)* } => {
251         $(#[$attr])*
252         #[allow(non_camel_case_types)]
253         #[repr(simd)]
254         pub struct $name($($itype),*);
255     };
256     { splat $type:ty | $($itype:ty)* } => {
257         /// Construct a vector by setting all lanes to the given value.
258         #[inline]
259         pub const fn splat(value: $type) -> Self {
260             Self($(value as $itype),*)
261         }
262     };
263     { new $type:ty | $($var:ident)* } => {
264         /// Construct a vector by setting each lane to the given values.
265         #[allow(clippy::too_many_arguments)]
266         #[inline]
267         pub const fn new($($var: $type),*) -> Self {
268             Self($($var),*)
269         }
270     }
271 }
272
273 /// Implements inherent methods for a float vector `$name` containing multiple
274 /// `$lanes` of float `$type`, which uses `$bits_ty` as its binary
275 /// representation. Called from `define_float_vector!`.
276 macro_rules! impl_float_vector {
277     { $name:path => [$type:ty; $lanes:literal]; bits $bits_ty:ty; } => {
278         impl $name {
279             /// Raw transmutation to an unsigned integer vector type with the
280             /// same size and number of lanes.
281             #[inline]
282             pub fn to_bits(self) -> $bits_ty {
283                 unsafe { core::mem::transmute(self) }
284             }
285
286             /// Raw transmutation from an unsigned integer vector type with the
287             /// same size and number of lanes.
288             #[inline]
289             pub fn from_bits(bits: $bits_ty) -> Self {
290                 unsafe { core::mem::transmute(bits) }
291             }
292
293             /// Produces a vector where every lane has the absolute value of the
294             /// equivalently-indexed lane in `self`.
295             #[inline]
296             pub fn abs(self) -> Self {
297                 let no_sign = <$bits_ty>::splat(!0 >> 1);
298                 Self::from_bits(self.to_bits() & no_sign)
299             }
300         }
301     };
302 }
303
304 /// Defines a float vector `$name` containing multiple `$lanes` of float
305 /// `$type`, which uses `$bits_ty` as its binary representation.
306 macro_rules! define_float_vector {
307     { $(#[$attr:meta])* struct $name:ident([$type:ty; $lanes:tt]); bits $bits_ty:ty; } => {
308         define_vector! {
309             $(#[$attr])*
310             struct $name([$type; $lanes]);
311         }
312
313         impl_float_vector! { $name => [$type; $lanes]; bits $bits_ty; }
314     }
315 }
316
317 /// Defines an integer vector `$name` containing multiple `$lanes` of integer `$type`.
318 macro_rules! define_integer_vector {
319     { $(#[$attr:meta])* struct $name:ident([$type:ty; $lanes:tt]); } => {
320         define_vector! {
321             $(#[$attr])*
322             struct $name([$type; $lanes]);
323         }
324
325         integer_vector_traits! { $name => [$type; $lanes] }
326     }
327 }
328
329 /// Defines a mask vector `$name` containing multiple `$lanes` of `$type`, represented by the
330 /// underlying type `$impl_type`.
331 macro_rules! define_mask_vector {
332     { $(#[$attr:meta])* struct $name:ident([$impl_type:ty as $type:ty; $lanes:tt]); } => {
333         call_repeat! { $lanes => define_mask_vector [$impl_type] def $(#[$attr])* | $name | }
334
335         impl $name {
336             call_repeat! { $lanes => define_mask_vector [$impl_type] splat $type | }
337             call_counting_args! { $lanes => define_mask_vector => new $type | }
338             call_counting_args! { $lanes => define_mask_vector => new_from_bool $type | }
339         }
340
341         base_vector_traits! { $name => [$type; $lanes] }
342         integer_vector_traits! { $name => [$type; $lanes] }
343     };
344     { def $(#[$attr:meta])* | $name:ident | $($itype:ty)* } => {
345         $(#[$attr])*
346         #[allow(non_camel_case_types)]
347         #[repr(simd)]
348         pub struct $name($($itype),*);
349     };
350     { splat $type:ty | $($itype:ty)* } => {
351         /// Construct a vector by setting all lanes to the given value.
352         #[inline]
353         pub const fn splat(value: $type) -> Self {
354             Self($(value.0 as $itype),*)
355         }
356     };
357     { new $type:ty | $($var:ident)* } => {
358         /// Construct a vector by setting each lane to the given values.
359         #[allow(clippy::too_many_arguments)]
360         #[inline]
361         pub const fn new($($var: $type),*) -> Self {
362             Self($($var.0),*)
363         }
364     };
365     { new_from_bool $type:ty | $($var:ident)* } => {
366         /// Used internally (since we can't use the Into trait in `const fn`s)
367         #[allow(clippy::too_many_arguments)]
368         #[allow(unused)]
369         #[inline]
370         pub(crate) const fn new_from_bool($($var: bool),*) -> Self {
371             Self($(<$type>::new($var).0),*)
372         }
373     }
374 }