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