]> git.lizzy.rs Git - rust.git/blob - crates/core_simd/src/masks/full_masks.rs
Merge pull request #83 from rust-lang/feature/reductions
[rust.git] / crates / core_simd / src / masks / full_masks.rs
1 //! Masks that take up full SIMD vector registers.
2
3 /// The error type returned when converting an integer to a mask fails.
4 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
5 pub struct TryFromMaskError(());
6
7 impl core::fmt::Display for TryFromMaskError {
8     fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
9         write!(
10             f,
11             "mask vector must have all bits set or unset in each lane"
12         )
13     }
14 }
15
16 macro_rules! define_mask {
17     {
18         $(#[$attr:meta])*
19         struct $name:ident<const $lanes:ident: usize>(
20             crate::$type:ident<$lanes2:ident>
21         );
22     } => {
23         $(#[$attr])*
24         #[derive(Default, PartialEq, PartialOrd, Eq, Ord, Hash)]
25         #[repr(transparent)]
26         pub struct $name<const $lanes: usize>(crate::$type<$lanes2>)
27         where
28             crate::$type<LANES>: crate::LanesAtMost32;
29
30         impl<const LANES: usize> Copy for $name<LANES>
31         where
32             crate::$type<LANES>: crate::LanesAtMost32,
33         {}
34
35         impl<const LANES: usize> Clone for $name<LANES>
36         where
37             crate::$type<LANES>: crate::LanesAtMost32,
38         {
39             #[inline]
40             fn clone(&self) -> Self {
41                 *self
42             }
43         }
44
45         impl<const LANES: usize> $name<LANES>
46         where
47             crate::$type<LANES>: crate::LanesAtMost32,
48         {
49             /// Construct a mask by setting all lanes to the given value.
50             pub fn splat(value: bool) -> Self {
51                 Self(<crate::$type<LANES>>::splat(
52                     if value {
53                         -1
54                     } else {
55                         0
56                     }
57                 ))
58             }
59
60             /// Tests the value of the specified lane.
61             ///
62             /// # Panics
63             /// Panics if `lane` is greater than or equal to the number of lanes in the vector.
64             #[inline]
65             pub fn test(&self, lane: usize) -> bool {
66                 assert!(lane < LANES, "lane index out of range");
67                 self.0[lane] == -1
68             }
69
70             /// Sets the value of the specified lane.
71             ///
72             /// # Panics
73             /// Panics if `lane` is greater than or equal to the number of lanes in the vector.
74             #[inline]
75             pub fn set(&mut self, lane: usize, value: bool) {
76                 assert!(lane < LANES, "lane index out of range");
77                 self.0[lane] = if value {
78                     -1
79                 } else {
80                     0
81                 }
82             }
83
84             /// Converts the mask to the equivalent integer representation, where -1 represents
85             /// "set" and 0 represents "unset".
86             #[inline]
87             pub fn to_int(self) -> crate::$type<LANES> {
88                 self.0
89             }
90
91             /// Creates a  mask from the equivalent integer representation, where -1 represents
92             /// "set" and 0 represents "unset".
93             ///
94             /// Each provided lane must be either 0 or -1.
95             #[inline]
96             pub unsafe fn from_int_unchecked(value: crate::$type<LANES>) -> Self {
97                 Self(value)
98             }
99
100             /// Creates a mask from the equivalent integer representation, where -1 represents
101             /// "set" and 0 represents "unset".
102             ///
103             /// # Panics
104             /// Panics if any lane is not 0 or -1.
105             #[inline]
106             pub fn from_int(value: crate::$type<LANES>) -> Self {
107                 use core::convert::TryInto;
108                 value.try_into().unwrap()
109             }
110         }
111
112         impl<const LANES: usize> core::convert::From<bool> for $name<LANES>
113         where
114             crate::$type<LANES>: crate::LanesAtMost32,
115         {
116             fn from(value: bool) -> Self {
117                 Self::splat(value)
118             }
119         }
120
121         impl<const LANES: usize> core::convert::TryFrom<crate::$type<LANES>> for $name<LANES>
122         where
123             crate::$type<LANES>: crate::LanesAtMost32,
124         {
125             type Error = TryFromMaskError;
126             fn try_from(value: crate::$type<LANES>) -> Result<Self, Self::Error> {
127                 let valid = (value.lanes_eq(crate::$type::<LANES>::splat(0)) | value.lanes_eq(crate::$type::<LANES>::splat(-1))).all();
128                 if valid {
129                     Ok(Self(value))
130                 } else {
131                     Err(TryFromMaskError(()))
132                 }
133             }
134         }
135
136         impl<const LANES: usize> core::convert::From<$name<LANES>> for crate::$type<LANES>
137         where
138             crate::$type<LANES>: crate::LanesAtMost32,
139         {
140             fn from(value: $name<LANES>) -> Self {
141                 value.0
142             }
143         }
144
145         impl<const LANES: usize> core::convert::From<crate::BitMask<LANES>> for $name<LANES>
146         where
147             crate::$type<LANES>: crate::LanesAtMost32,
148             crate::BitMask<LANES>: crate::LanesAtMost32,
149         {
150             fn from(value: crate::BitMask<LANES>) -> Self {
151                 // TODO use an intrinsic to do this efficiently (with LLVM's sext instruction)
152                 let mut mask = Self::splat(false);
153                 for lane in 0..LANES {
154                     mask.set(lane, value.test(lane));
155                 }
156                 mask
157             }
158         }
159
160         impl<const LANES: usize> core::convert::From<$name<LANES>> for crate::BitMask<LANES>
161         where
162             crate::$type<LANES>: crate::LanesAtMost32,
163             crate::BitMask<LANES>: crate::LanesAtMost32,
164         {
165             fn from(value: $name<$lanes>) -> Self {
166                 // TODO use an intrinsic to do this efficiently (with LLVM's trunc instruction)
167                 let mut mask = Self::splat(false);
168                 for lane in 0..LANES {
169                     mask.set(lane, value.test(lane));
170                 }
171                 mask
172             }
173         }
174
175         impl<const LANES: usize> core::fmt::Debug for $name<LANES>
176         where
177             crate::$type<LANES>: crate::LanesAtMost32,
178         {
179             fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
180                 f.debug_list()
181                     .entries((0..LANES).map(|lane| self.test(lane)))
182                     .finish()
183             }
184         }
185
186         impl<const LANES: usize> core::fmt::Binary for $name<LANES>
187         where
188             crate::$type<LANES>: crate::LanesAtMost32,
189         {
190             fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
191                 core::fmt::Binary::fmt(&self.0, f)
192             }
193         }
194
195         impl<const LANES: usize> core::fmt::Octal for $name<LANES>
196         where
197             crate::$type<LANES>: crate::LanesAtMost32,
198         {
199             fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
200                 core::fmt::Octal::fmt(&self.0, f)
201             }
202         }
203
204         impl<const LANES: usize> core::fmt::LowerHex for $name<LANES>
205         where
206             crate::$type<LANES>: crate::LanesAtMost32,
207         {
208             fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
209                 core::fmt::LowerHex::fmt(&self.0, f)
210             }
211         }
212
213         impl<const LANES: usize> core::fmt::UpperHex for $name<LANES>
214         where
215             crate::$type<LANES>: crate::LanesAtMost32,
216         {
217             fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
218                 core::fmt::UpperHex::fmt(&self.0, f)
219             }
220         }
221
222         impl<const LANES: usize> core::ops::BitAnd for $name<LANES>
223         where
224             crate::$type<LANES>: crate::LanesAtMost32,
225         {
226             type Output = Self;
227             #[inline]
228             fn bitand(self, rhs: Self) -> Self {
229                 Self(self.0 & rhs.0)
230             }
231         }
232
233         impl<const LANES: usize> core::ops::BitAnd<bool> for $name<LANES>
234         where
235             crate::$type<LANES>: crate::LanesAtMost32,
236         {
237             type Output = Self;
238             #[inline]
239             fn bitand(self, rhs: bool) -> Self {
240                 self & Self::splat(rhs)
241             }
242         }
243
244         impl<const LANES: usize> core::ops::BitAnd<$name<LANES>> for bool
245         where
246             crate::$type<LANES>: crate::LanesAtMost32,
247         {
248             type Output = $name<LANES>;
249             #[inline]
250             fn bitand(self, rhs: $name<LANES>) -> $name<LANES> {
251                 $name::<LANES>::splat(self) & rhs
252             }
253         }
254
255         impl<const LANES: usize> core::ops::BitOr for $name<LANES>
256         where
257             crate::$type<LANES>: crate::LanesAtMost32,
258         {
259             type Output = Self;
260             #[inline]
261             fn bitor(self, rhs: Self) -> Self {
262                 Self(self.0 | rhs.0)
263             }
264         }
265
266         impl<const LANES: usize> core::ops::BitOr<bool> for $name<LANES>
267         where
268             crate::$type<LANES>: crate::LanesAtMost32,
269         {
270             type Output = Self;
271             #[inline]
272             fn bitor(self, rhs: bool) -> Self {
273                 self | Self::splat(rhs)
274             }
275         }
276
277         impl<const LANES: usize> core::ops::BitOr<$name<LANES>> for bool
278         where
279             crate::$type<LANES>: crate::LanesAtMost32,
280         {
281             type Output = $name<LANES>;
282             #[inline]
283             fn bitor(self, rhs: $name<LANES>) -> $name<LANES> {
284                 $name::<LANES>::splat(self) | rhs
285             }
286         }
287
288         impl<const LANES: usize> core::ops::BitXor for $name<LANES>
289         where
290             crate::$type<LANES>: crate::LanesAtMost32,
291         {
292             type Output = Self;
293             #[inline]
294             fn bitxor(self, rhs: Self) -> Self::Output {
295                 Self(self.0 ^ rhs.0)
296             }
297         }
298
299         impl<const LANES: usize> core::ops::BitXor<bool> for $name<LANES>
300         where
301             crate::$type<LANES>: crate::LanesAtMost32,
302         {
303             type Output = Self;
304             #[inline]
305             fn bitxor(self, rhs: bool) -> Self::Output {
306                 self ^ Self::splat(rhs)
307             }
308         }
309
310         impl<const LANES: usize> core::ops::BitXor<$name<LANES>> for bool
311         where
312             crate::$type<LANES>: crate::LanesAtMost32,
313         {
314             type Output = $name<LANES>;
315             #[inline]
316             fn bitxor(self, rhs: $name<LANES>) -> Self::Output {
317                 $name::<LANES>::splat(self) ^ rhs
318             }
319         }
320
321         impl<const LANES: usize> core::ops::Not for $name<LANES>
322         where
323             crate::$type<LANES>: crate::LanesAtMost32,
324         {
325             type Output = $name<LANES>;
326             #[inline]
327             fn not(self) -> Self::Output {
328                 Self(!self.0)
329             }
330         }
331
332         impl<const LANES: usize> core::ops::BitAndAssign for $name<LANES>
333         where
334             crate::$type<LANES>: crate::LanesAtMost32,
335         {
336             #[inline]
337             fn bitand_assign(&mut self, rhs: Self) {
338                 self.0 &= rhs.0;
339             }
340         }
341
342         impl<const LANES: usize> core::ops::BitAndAssign<bool> for $name<LANES>
343         where
344             crate::$type<LANES>: crate::LanesAtMost32,
345         {
346             #[inline]
347             fn bitand_assign(&mut self, rhs: bool) {
348                 *self &= Self::splat(rhs);
349             }
350         }
351
352         impl<const LANES: usize> core::ops::BitOrAssign for $name<LANES>
353         where
354             crate::$type<LANES>: crate::LanesAtMost32,
355         {
356             #[inline]
357             fn bitor_assign(&mut self, rhs: Self) {
358                 self.0 |= rhs.0;
359             }
360         }
361
362         impl<const LANES: usize> core::ops::BitOrAssign<bool> for $name<LANES>
363         where
364             crate::$type<LANES>: crate::LanesAtMost32,
365         {
366             #[inline]
367             fn bitor_assign(&mut self, rhs: bool) {
368                 *self |= Self::splat(rhs);
369             }
370         }
371
372         impl<const LANES: usize> core::ops::BitXorAssign for $name<LANES>
373         where
374             crate::$type<LANES>: crate::LanesAtMost32,
375         {
376             #[inline]
377             fn bitxor_assign(&mut self, rhs: Self) {
378                 self.0 ^= rhs.0;
379             }
380         }
381
382         impl<const LANES: usize> core::ops::BitXorAssign<bool> for $name<LANES>
383         where
384             crate::$type<LANES>: crate::LanesAtMost32,
385         {
386             #[inline]
387             fn bitxor_assign(&mut self, rhs: bool) {
388                 *self ^= Self::splat(rhs);
389             }
390         }
391
392         impl_full_mask_reductions! { $name, $type }
393     }
394 }
395
396 define_mask! {
397     /// A mask equivalent to [SimdI8](crate::SimdI8), where all bits in the lane must be either set
398     /// or unset.
399     struct SimdMask8<const LANES: usize>(crate::SimdI8<LANES>);
400 }
401
402 define_mask! {
403     /// A mask equivalent to [SimdI16](crate::SimdI16), where all bits in the lane must be either set
404     /// or unset.
405     struct SimdMask16<const LANES: usize>(crate::SimdI16<LANES>);
406 }
407
408 define_mask! {
409     /// A mask equivalent to [SimdI32](crate::SimdI32), where all bits in the lane must be either set
410     /// or unset.
411     struct SimdMask32<const LANES: usize>(crate::SimdI32<LANES>);
412 }
413
414 define_mask! {
415     /// A mask equivalent to [SimdI64](crate::SimdI64), where all bits in the lane must be either set
416     /// or unset.
417     struct SimdMask64<const LANES: usize>(crate::SimdI64<LANES>);
418 }
419
420 define_mask! {
421     /// A mask equivalent to [SimdI128](crate::SimdI128), where all bits in the lane must be either set
422     /// or unset.
423     struct SimdMask128<const LANES: usize>(crate::SimdI128<LANES>);
424 }
425
426 define_mask! {
427     /// A mask equivalent to [SimdIsize](crate::SimdIsize), where all bits in the lane must be either set
428     /// or unset.
429     struct SimdMaskSize<const LANES: usize>(crate::SimdIsize<LANES>);
430 }