]>
Commit | Line | Data |
---|---|---|
3c0e092e XL |
1 | //! Types and traits associated with masking lanes of vectors. |
2 | //! Types representing | |
3 | #![allow(non_camel_case_types)] | |
4 | ||
5 | #[cfg_attr( | |
6 | not(all(target_arch = "x86_64", target_feature = "avx512f")), | |
7 | path = "masks/full_masks.rs" | |
8 | )] | |
9 | #[cfg_attr( | |
10 | all(target_arch = "x86_64", target_feature = "avx512f"), | |
11 | path = "masks/bitmask.rs" | |
12 | )] | |
13 | mod mask_impl; | |
14 | ||
ee023bcb FG |
15 | mod to_bitmask; |
16 | pub use to_bitmask::ToBitMask; | |
17 | ||
18 | use crate::simd::{intrinsics, LaneCount, Simd, SimdElement, SupportedLaneCount}; | |
3c0e092e | 19 | use core::cmp::Ordering; |
5099ac24 | 20 | use core::{fmt, mem}; |
3c0e092e XL |
21 | |
22 | mod sealed { | |
23 | use super::*; | |
24 | ||
25 | /// Not only does this seal the `MaskElement` trait, but these functions prevent other traits | |
26 | /// from bleeding into the parent bounds. | |
27 | /// | |
28 | /// For example, `eq` could be provided by requiring `MaskElement: PartialEq`, but that would | |
29 | /// prevent us from ever removing that bound, or from implementing `MaskElement` on | |
30 | /// non-`PartialEq` types in the future. | |
31 | pub trait Sealed { | |
32 | fn valid<const LANES: usize>(values: Simd<Self, LANES>) -> bool | |
33 | where | |
34 | LaneCount<LANES>: SupportedLaneCount, | |
35 | Self: SimdElement; | |
36 | ||
37 | fn eq(self, other: Self) -> bool; | |
38 | ||
39 | const TRUE: Self; | |
40 | ||
41 | const FALSE: Self; | |
42 | } | |
43 | } | |
44 | use sealed::Sealed; | |
45 | ||
46 | /// Marker trait for types that may be used as SIMD mask elements. | |
ee023bcb FG |
47 | /// |
48 | /// # Safety | |
49 | /// Type must be a signed integer. | |
3c0e092e XL |
50 | pub unsafe trait MaskElement: SimdElement + Sealed {} |
51 | ||
52 | macro_rules! impl_element { | |
53 | { $ty:ty } => { | |
54 | impl Sealed for $ty { | |
55 | fn valid<const LANES: usize>(value: Simd<Self, LANES>) -> bool | |
56 | where | |
57 | LaneCount<LANES>: SupportedLaneCount, | |
58 | { | |
59 | (value.lanes_eq(Simd::splat(0)) | value.lanes_eq(Simd::splat(-1))).all() | |
60 | } | |
61 | ||
62 | fn eq(self, other: Self) -> bool { self == other } | |
63 | ||
64 | const TRUE: Self = -1; | |
65 | const FALSE: Self = 0; | |
66 | } | |
67 | ||
68 | unsafe impl MaskElement for $ty {} | |
69 | } | |
70 | } | |
71 | ||
72 | impl_element! { i8 } | |
73 | impl_element! { i16 } | |
74 | impl_element! { i32 } | |
75 | impl_element! { i64 } | |
76 | impl_element! { isize } | |
77 | ||
78 | /// A SIMD vector mask for `LANES` elements of width specified by `Element`. | |
79 | /// | |
80 | /// The layout of this type is unspecified. | |
81 | #[repr(transparent)] | |
82 | pub struct Mask<T, const LANES: usize>(mask_impl::Mask<T, LANES>) | |
83 | where | |
84 | T: MaskElement, | |
85 | LaneCount<LANES>: SupportedLaneCount; | |
86 | ||
87 | impl<T, const LANES: usize> Copy for Mask<T, LANES> | |
88 | where | |
89 | T: MaskElement, | |
90 | LaneCount<LANES>: SupportedLaneCount, | |
91 | { | |
92 | } | |
93 | ||
94 | impl<T, const LANES: usize> Clone for Mask<T, LANES> | |
95 | where | |
96 | T: MaskElement, | |
97 | LaneCount<LANES>: SupportedLaneCount, | |
98 | { | |
99 | fn clone(&self) -> Self { | |
100 | *self | |
101 | } | |
102 | } | |
103 | ||
104 | impl<T, const LANES: usize> Mask<T, LANES> | |
105 | where | |
106 | T: MaskElement, | |
107 | LaneCount<LANES>: SupportedLaneCount, | |
108 | { | |
109 | /// Construct a mask by setting all lanes to the given value. | |
110 | pub fn splat(value: bool) -> Self { | |
111 | Self(mask_impl::Mask::splat(value)) | |
112 | } | |
113 | ||
5099ac24 | 114 | /// Converts an array of bools to a SIMD mask. |
3c0e092e | 115 | pub fn from_array(array: [bool; LANES]) -> Self { |
5099ac24 FG |
116 | // SAFETY: Rust's bool has a layout of 1 byte (u8) with a value of |
117 | // true: 0b_0000_0001 | |
118 | // false: 0b_0000_0000 | |
119 | // Thus, an array of bools is also a valid array of bytes: [u8; N] | |
120 | // This would be hypothetically valid as an "in-place" transmute, | |
121 | // but these are "dependently-sized" types, so copy elision it is! | |
122 | unsafe { | |
123 | let bytes: [u8; LANES] = mem::transmute_copy(&array); | |
124 | let bools: Simd<i8, LANES> = | |
125 | intrinsics::simd_ne(Simd::from_array(bytes), Simd::splat(0u8)); | |
126 | Mask::from_int_unchecked(intrinsics::simd_cast(bools)) | |
3c0e092e | 127 | } |
3c0e092e XL |
128 | } |
129 | ||
5099ac24 | 130 | /// Converts a SIMD mask to an array of bools. |
3c0e092e | 131 | pub fn to_array(self) -> [bool; LANES] { |
5099ac24 FG |
132 | // This follows mostly the same logic as from_array. |
133 | // SAFETY: Rust's bool has a layout of 1 byte (u8) with a value of | |
134 | // true: 0b_0000_0001 | |
135 | // false: 0b_0000_0000 | |
136 | // Thus, an array of bools is also a valid array of bytes: [u8; N] | |
137 | // Since our masks are equal to integers where all bits are set, | |
138 | // we can simply convert them to i8s, and then bitand them by the | |
139 | // bitpattern for Rust's "true" bool. | |
140 | // This would be hypothetically valid as an "in-place" transmute, | |
141 | // but these are "dependently-sized" types, so copy elision it is! | |
142 | unsafe { | |
143 | let mut bytes: Simd<i8, LANES> = intrinsics::simd_cast(self.to_int()); | |
144 | bytes &= Simd::splat(1i8); | |
145 | mem::transmute_copy(&bytes) | |
3c0e092e | 146 | } |
3c0e092e XL |
147 | } |
148 | ||
149 | /// Converts a vector of integers to a mask, where 0 represents `false` and -1 | |
150 | /// represents `true`. | |
151 | /// | |
152 | /// # Safety | |
153 | /// All lanes must be either 0 or -1. | |
154 | #[inline] | |
a2a8927a | 155 | #[must_use = "method returns a new mask and does not mutate the original value"] |
3c0e092e | 156 | pub unsafe fn from_int_unchecked(value: Simd<T, LANES>) -> Self { |
ee023bcb | 157 | // Safety: the caller must confirm this invariant |
3c0e092e XL |
158 | unsafe { Self(mask_impl::Mask::from_int_unchecked(value)) } |
159 | } | |
160 | ||
161 | /// Converts a vector of integers to a mask, where 0 represents `false` and -1 | |
162 | /// represents `true`. | |
163 | /// | |
164 | /// # Panics | |
165 | /// Panics if any lane is not 0 or -1. | |
166 | #[inline] | |
a2a8927a | 167 | #[must_use = "method returns a new mask and does not mutate the original value"] |
3c0e092e XL |
168 | pub fn from_int(value: Simd<T, LANES>) -> Self { |
169 | assert!(T::valid(value), "all values must be either 0 or -1",); | |
ee023bcb | 170 | // Safety: the validity has been checked |
3c0e092e XL |
171 | unsafe { Self::from_int_unchecked(value) } |
172 | } | |
173 | ||
174 | /// Converts the mask to a vector of integers, where 0 represents `false` and -1 | |
175 | /// represents `true`. | |
176 | #[inline] | |
a2a8927a | 177 | #[must_use = "method returns a new vector and does not mutate the original value"] |
3c0e092e XL |
178 | pub fn to_int(self) -> Simd<T, LANES> { |
179 | self.0.to_int() | |
180 | } | |
181 | ||
182 | /// Tests the value of the specified lane. | |
183 | /// | |
184 | /// # Safety | |
185 | /// `lane` must be less than `LANES`. | |
186 | #[inline] | |
a2a8927a | 187 | #[must_use = "method returns a new bool and does not mutate the original value"] |
3c0e092e | 188 | pub unsafe fn test_unchecked(&self, lane: usize) -> bool { |
ee023bcb | 189 | // Safety: the caller must confirm this invariant |
3c0e092e XL |
190 | unsafe { self.0.test_unchecked(lane) } |
191 | } | |
192 | ||
193 | /// Tests the value of the specified lane. | |
194 | /// | |
195 | /// # Panics | |
196 | /// Panics if `lane` is greater than or equal to the number of lanes in the vector. | |
197 | #[inline] | |
a2a8927a | 198 | #[must_use = "method returns a new bool and does not mutate the original value"] |
3c0e092e XL |
199 | pub fn test(&self, lane: usize) -> bool { |
200 | assert!(lane < LANES, "lane index out of range"); | |
ee023bcb | 201 | // Safety: the lane index has been checked |
3c0e092e XL |
202 | unsafe { self.test_unchecked(lane) } |
203 | } | |
204 | ||
205 | /// Sets the value of the specified lane. | |
206 | /// | |
207 | /// # Safety | |
208 | /// `lane` must be less than `LANES`. | |
209 | #[inline] | |
210 | pub unsafe fn set_unchecked(&mut self, lane: usize, value: bool) { | |
ee023bcb | 211 | // Safety: the caller must confirm this invariant |
3c0e092e XL |
212 | unsafe { |
213 | self.0.set_unchecked(lane, value); | |
214 | } | |
215 | } | |
216 | ||
217 | /// Sets the value of the specified lane. | |
218 | /// | |
219 | /// # Panics | |
220 | /// Panics if `lane` is greater than or equal to the number of lanes in the vector. | |
221 | #[inline] | |
222 | pub fn set(&mut self, lane: usize, value: bool) { | |
223 | assert!(lane < LANES, "lane index out of range"); | |
ee023bcb | 224 | // Safety: the lane index has been checked |
3c0e092e XL |
225 | unsafe { |
226 | self.set_unchecked(lane, value); | |
227 | } | |
228 | } | |
229 | ||
3c0e092e XL |
230 | /// Returns true if any lane is set, or false otherwise. |
231 | #[inline] | |
a2a8927a | 232 | #[must_use = "method returns a new bool and does not mutate the original value"] |
3c0e092e XL |
233 | pub fn any(self) -> bool { |
234 | self.0.any() | |
235 | } | |
236 | ||
237 | /// Returns true if all lanes are set, or false otherwise. | |
238 | #[inline] | |
a2a8927a | 239 | #[must_use = "method returns a new bool and does not mutate the original value"] |
3c0e092e XL |
240 | pub fn all(self) -> bool { |
241 | self.0.all() | |
242 | } | |
243 | } | |
244 | ||
245 | // vector/array conversion | |
246 | impl<T, const LANES: usize> From<[bool; LANES]> for Mask<T, LANES> | |
247 | where | |
248 | T: MaskElement, | |
249 | LaneCount<LANES>: SupportedLaneCount, | |
250 | { | |
251 | fn from(array: [bool; LANES]) -> Self { | |
252 | Self::from_array(array) | |
253 | } | |
254 | } | |
255 | ||
256 | impl<T, const LANES: usize> From<Mask<T, LANES>> for [bool; LANES] | |
257 | where | |
258 | T: MaskElement, | |
259 | LaneCount<LANES>: SupportedLaneCount, | |
260 | { | |
261 | fn from(vector: Mask<T, LANES>) -> Self { | |
262 | vector.to_array() | |
263 | } | |
264 | } | |
265 | ||
266 | impl<T, const LANES: usize> Default for Mask<T, LANES> | |
267 | where | |
268 | T: MaskElement, | |
269 | LaneCount<LANES>: SupportedLaneCount, | |
270 | { | |
271 | #[inline] | |
a2a8927a | 272 | #[must_use = "method returns a defaulted mask with all lanes set to false (0)"] |
3c0e092e XL |
273 | fn default() -> Self { |
274 | Self::splat(false) | |
275 | } | |
276 | } | |
277 | ||
278 | impl<T, const LANES: usize> PartialEq for Mask<T, LANES> | |
279 | where | |
280 | T: MaskElement + PartialEq, | |
281 | LaneCount<LANES>: SupportedLaneCount, | |
282 | { | |
283 | #[inline] | |
a2a8927a | 284 | #[must_use = "method returns a new bool and does not mutate the original value"] |
3c0e092e XL |
285 | fn eq(&self, other: &Self) -> bool { |
286 | self.0 == other.0 | |
287 | } | |
288 | } | |
289 | ||
290 | impl<T, const LANES: usize> PartialOrd for Mask<T, LANES> | |
291 | where | |
292 | T: MaskElement + PartialOrd, | |
293 | LaneCount<LANES>: SupportedLaneCount, | |
294 | { | |
295 | #[inline] | |
a2a8927a | 296 | #[must_use = "method returns a new Ordering and does not mutate the original value"] |
3c0e092e XL |
297 | fn partial_cmp(&self, other: &Self) -> Option<Ordering> { |
298 | self.0.partial_cmp(&other.0) | |
299 | } | |
300 | } | |
301 | ||
302 | impl<T, const LANES: usize> fmt::Debug for Mask<T, LANES> | |
303 | where | |
304 | T: MaskElement + fmt::Debug, | |
305 | LaneCount<LANES>: SupportedLaneCount, | |
306 | { | |
307 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
308 | f.debug_list() | |
309 | .entries((0..LANES).map(|lane| self.test(lane))) | |
310 | .finish() | |
311 | } | |
312 | } | |
313 | ||
314 | impl<T, const LANES: usize> core::ops::BitAnd for Mask<T, LANES> | |
315 | where | |
316 | T: MaskElement, | |
317 | LaneCount<LANES>: SupportedLaneCount, | |
318 | { | |
319 | type Output = Self; | |
320 | #[inline] | |
a2a8927a | 321 | #[must_use = "method returns a new mask and does not mutate the original value"] |
3c0e092e XL |
322 | fn bitand(self, rhs: Self) -> Self { |
323 | Self(self.0 & rhs.0) | |
324 | } | |
325 | } | |
326 | ||
327 | impl<T, const LANES: usize> core::ops::BitAnd<bool> for Mask<T, LANES> | |
328 | where | |
329 | T: MaskElement, | |
330 | LaneCount<LANES>: SupportedLaneCount, | |
331 | { | |
332 | type Output = Self; | |
333 | #[inline] | |
a2a8927a | 334 | #[must_use = "method returns a new mask and does not mutate the original value"] |
3c0e092e XL |
335 | fn bitand(self, rhs: bool) -> Self { |
336 | self & Self::splat(rhs) | |
337 | } | |
338 | } | |
339 | ||
340 | impl<T, const LANES: usize> core::ops::BitAnd<Mask<T, LANES>> for bool | |
341 | where | |
342 | T: MaskElement, | |
343 | LaneCount<LANES>: SupportedLaneCount, | |
344 | { | |
345 | type Output = Mask<T, LANES>; | |
346 | #[inline] | |
a2a8927a | 347 | #[must_use = "method returns a new mask and does not mutate the original value"] |
3c0e092e XL |
348 | fn bitand(self, rhs: Mask<T, LANES>) -> Mask<T, LANES> { |
349 | Mask::splat(self) & rhs | |
350 | } | |
351 | } | |
352 | ||
353 | impl<T, const LANES: usize> core::ops::BitOr for Mask<T, LANES> | |
354 | where | |
355 | T: MaskElement, | |
356 | LaneCount<LANES>: SupportedLaneCount, | |
357 | { | |
358 | type Output = Self; | |
359 | #[inline] | |
a2a8927a | 360 | #[must_use = "method returns a new mask and does not mutate the original value"] |
3c0e092e XL |
361 | fn bitor(self, rhs: Self) -> Self { |
362 | Self(self.0 | rhs.0) | |
363 | } | |
364 | } | |
365 | ||
366 | impl<T, const LANES: usize> core::ops::BitOr<bool> for Mask<T, LANES> | |
367 | where | |
368 | T: MaskElement, | |
369 | LaneCount<LANES>: SupportedLaneCount, | |
370 | { | |
371 | type Output = Self; | |
372 | #[inline] | |
a2a8927a | 373 | #[must_use = "method returns a new mask and does not mutate the original value"] |
3c0e092e XL |
374 | fn bitor(self, rhs: bool) -> Self { |
375 | self | Self::splat(rhs) | |
376 | } | |
377 | } | |
378 | ||
379 | impl<T, const LANES: usize> core::ops::BitOr<Mask<T, LANES>> for bool | |
380 | where | |
381 | T: MaskElement, | |
382 | LaneCount<LANES>: SupportedLaneCount, | |
383 | { | |
384 | type Output = Mask<T, LANES>; | |
385 | #[inline] | |
a2a8927a | 386 | #[must_use = "method returns a new mask and does not mutate the original value"] |
3c0e092e XL |
387 | fn bitor(self, rhs: Mask<T, LANES>) -> Mask<T, LANES> { |
388 | Mask::splat(self) | rhs | |
389 | } | |
390 | } | |
391 | ||
392 | impl<T, const LANES: usize> core::ops::BitXor for Mask<T, LANES> | |
393 | where | |
394 | T: MaskElement, | |
395 | LaneCount<LANES>: SupportedLaneCount, | |
396 | { | |
397 | type Output = Self; | |
398 | #[inline] | |
a2a8927a | 399 | #[must_use = "method returns a new mask and does not mutate the original value"] |
3c0e092e XL |
400 | fn bitxor(self, rhs: Self) -> Self::Output { |
401 | Self(self.0 ^ rhs.0) | |
402 | } | |
403 | } | |
404 | ||
405 | impl<T, const LANES: usize> core::ops::BitXor<bool> for Mask<T, LANES> | |
406 | where | |
407 | T: MaskElement, | |
408 | LaneCount<LANES>: SupportedLaneCount, | |
409 | { | |
410 | type Output = Self; | |
411 | #[inline] | |
a2a8927a | 412 | #[must_use = "method returns a new mask and does not mutate the original value"] |
3c0e092e XL |
413 | fn bitxor(self, rhs: bool) -> Self::Output { |
414 | self ^ Self::splat(rhs) | |
415 | } | |
416 | } | |
417 | ||
418 | impl<T, const LANES: usize> core::ops::BitXor<Mask<T, LANES>> for bool | |
419 | where | |
420 | T: MaskElement, | |
421 | LaneCount<LANES>: SupportedLaneCount, | |
422 | { | |
423 | type Output = Mask<T, LANES>; | |
424 | #[inline] | |
a2a8927a | 425 | #[must_use = "method returns a new mask and does not mutate the original value"] |
3c0e092e XL |
426 | fn bitxor(self, rhs: Mask<T, LANES>) -> Self::Output { |
427 | Mask::splat(self) ^ rhs | |
428 | } | |
429 | } | |
430 | ||
431 | impl<T, const LANES: usize> core::ops::Not for Mask<T, LANES> | |
432 | where | |
433 | T: MaskElement, | |
434 | LaneCount<LANES>: SupportedLaneCount, | |
435 | { | |
436 | type Output = Mask<T, LANES>; | |
437 | #[inline] | |
a2a8927a | 438 | #[must_use = "method returns a new mask and does not mutate the original value"] |
3c0e092e XL |
439 | fn not(self) -> Self::Output { |
440 | Self(!self.0) | |
441 | } | |
442 | } | |
443 | ||
444 | impl<T, const LANES: usize> core::ops::BitAndAssign for Mask<T, LANES> | |
445 | where | |
446 | T: MaskElement, | |
447 | LaneCount<LANES>: SupportedLaneCount, | |
448 | { | |
449 | #[inline] | |
450 | fn bitand_assign(&mut self, rhs: Self) { | |
451 | self.0 = self.0 & rhs.0; | |
452 | } | |
453 | } | |
454 | ||
455 | impl<T, const LANES: usize> core::ops::BitAndAssign<bool> for Mask<T, LANES> | |
456 | where | |
457 | T: MaskElement, | |
458 | LaneCount<LANES>: SupportedLaneCount, | |
459 | { | |
460 | #[inline] | |
461 | fn bitand_assign(&mut self, rhs: bool) { | |
462 | *self &= Self::splat(rhs); | |
463 | } | |
464 | } | |
465 | ||
466 | impl<T, const LANES: usize> core::ops::BitOrAssign for Mask<T, LANES> | |
467 | where | |
468 | T: MaskElement, | |
469 | LaneCount<LANES>: SupportedLaneCount, | |
470 | { | |
471 | #[inline] | |
472 | fn bitor_assign(&mut self, rhs: Self) { | |
473 | self.0 = self.0 | rhs.0; | |
474 | } | |
475 | } | |
476 | ||
477 | impl<T, const LANES: usize> core::ops::BitOrAssign<bool> for Mask<T, LANES> | |
478 | where | |
479 | T: MaskElement, | |
480 | LaneCount<LANES>: SupportedLaneCount, | |
481 | { | |
482 | #[inline] | |
483 | fn bitor_assign(&mut self, rhs: bool) { | |
484 | *self |= Self::splat(rhs); | |
485 | } | |
486 | } | |
487 | ||
488 | impl<T, const LANES: usize> core::ops::BitXorAssign for Mask<T, LANES> | |
489 | where | |
490 | T: MaskElement, | |
491 | LaneCount<LANES>: SupportedLaneCount, | |
492 | { | |
493 | #[inline] | |
494 | fn bitxor_assign(&mut self, rhs: Self) { | |
495 | self.0 = self.0 ^ rhs.0; | |
496 | } | |
497 | } | |
498 | ||
499 | impl<T, const LANES: usize> core::ops::BitXorAssign<bool> for Mask<T, LANES> | |
500 | where | |
501 | T: MaskElement, | |
502 | LaneCount<LANES>: SupportedLaneCount, | |
503 | { | |
504 | #[inline] | |
505 | fn bitxor_assign(&mut self, rhs: bool) { | |
506 | *self ^= Self::splat(rhs); | |
507 | } | |
508 | } | |
509 | ||
510 | /// Vector of eight 8-bit masks | |
511 | pub type mask8x8 = Mask<i8, 8>; | |
512 | ||
513 | /// Vector of 16 8-bit masks | |
514 | pub type mask8x16 = Mask<i8, 16>; | |
515 | ||
516 | /// Vector of 32 8-bit masks | |
517 | pub type mask8x32 = Mask<i8, 32>; | |
518 | ||
519 | /// Vector of 16 8-bit masks | |
520 | pub type mask8x64 = Mask<i8, 64>; | |
521 | ||
522 | /// Vector of four 16-bit masks | |
523 | pub type mask16x4 = Mask<i16, 4>; | |
524 | ||
525 | /// Vector of eight 16-bit masks | |
526 | pub type mask16x8 = Mask<i16, 8>; | |
527 | ||
528 | /// Vector of 16 16-bit masks | |
529 | pub type mask16x16 = Mask<i16, 16>; | |
530 | ||
531 | /// Vector of 32 16-bit masks | |
5099ac24 | 532 | pub type mask16x32 = Mask<i16, 32>; |
3c0e092e XL |
533 | |
534 | /// Vector of two 32-bit masks | |
535 | pub type mask32x2 = Mask<i32, 2>; | |
536 | ||
537 | /// Vector of four 32-bit masks | |
538 | pub type mask32x4 = Mask<i32, 4>; | |
539 | ||
540 | /// Vector of eight 32-bit masks | |
541 | pub type mask32x8 = Mask<i32, 8>; | |
542 | ||
543 | /// Vector of 16 32-bit masks | |
544 | pub type mask32x16 = Mask<i32, 16>; | |
545 | ||
546 | /// Vector of two 64-bit masks | |
547 | pub type mask64x2 = Mask<i64, 2>; | |
548 | ||
549 | /// Vector of four 64-bit masks | |
550 | pub type mask64x4 = Mask<i64, 4>; | |
551 | ||
552 | /// Vector of eight 64-bit masks | |
553 | pub type mask64x8 = Mask<i64, 8>; | |
554 | ||
555 | /// Vector of two pointer-width masks | |
556 | pub type masksizex2 = Mask<isize, 2>; | |
557 | ||
558 | /// Vector of four pointer-width masks | |
559 | pub type masksizex4 = Mask<isize, 4>; | |
560 | ||
561 | /// Vector of eight pointer-width masks | |
562 | pub type masksizex8 = Mask<isize, 8>; | |
563 | ||
564 | macro_rules! impl_from { | |
565 | { $from:ty => $($to:ty),* } => { | |
566 | $( | |
567 | impl<const LANES: usize> From<Mask<$from, LANES>> for Mask<$to, LANES> | |
568 | where | |
569 | LaneCount<LANES>: SupportedLaneCount, | |
570 | { | |
571 | fn from(value: Mask<$from, LANES>) -> Self { | |
572 | Self(value.0.convert()) | |
573 | } | |
574 | } | |
575 | )* | |
576 | } | |
577 | } | |
578 | impl_from! { i8 => i16, i32, i64, isize } | |
579 | impl_from! { i16 => i32, i64, isize, i8 } | |
580 | impl_from! { i32 => i64, isize, i8, i16 } | |
581 | impl_from! { i64 => isize, i8, i16, i32 } | |
582 | impl_from! { isize => i8, i16, i32, i64 } |