]> git.proxmox.com Git - rustc.git/blame - library/portable-simd/crates/core_simd/src/masks.rs
New upstream version 1.61.0+dfsg1
[rustc.git] / library / portable-simd / crates / core_simd / src / masks.rs
CommitLineData
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)]
13mod mask_impl;
14
ee023bcb
FG
15mod to_bitmask;
16pub use to_bitmask::ToBitMask;
17
18use crate::simd::{intrinsics, LaneCount, Simd, SimdElement, SupportedLaneCount};
3c0e092e 19use core::cmp::Ordering;
5099ac24 20use core::{fmt, mem};
3c0e092e
XL
21
22mod 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}
44use 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
50pub unsafe trait MaskElement: SimdElement + Sealed {}
51
52macro_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
72impl_element! { i8 }
73impl_element! { i16 }
74impl_element! { i32 }
75impl_element! { i64 }
76impl_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)]
82pub struct Mask<T, const LANES: usize>(mask_impl::Mask<T, LANES>)
83where
84 T: MaskElement,
85 LaneCount<LANES>: SupportedLaneCount;
86
87impl<T, const LANES: usize> Copy for Mask<T, LANES>
88where
89 T: MaskElement,
90 LaneCount<LANES>: SupportedLaneCount,
91{
92}
93
94impl<T, const LANES: usize> Clone for Mask<T, LANES>
95where
96 T: MaskElement,
97 LaneCount<LANES>: SupportedLaneCount,
98{
99 fn clone(&self) -> Self {
100 *self
101 }
102}
103
104impl<T, const LANES: usize> Mask<T, LANES>
105where
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
246impl<T, const LANES: usize> From<[bool; LANES]> for Mask<T, LANES>
247where
248 T: MaskElement,
249 LaneCount<LANES>: SupportedLaneCount,
250{
251 fn from(array: [bool; LANES]) -> Self {
252 Self::from_array(array)
253 }
254}
255
256impl<T, const LANES: usize> From<Mask<T, LANES>> for [bool; LANES]
257where
258 T: MaskElement,
259 LaneCount<LANES>: SupportedLaneCount,
260{
261 fn from(vector: Mask<T, LANES>) -> Self {
262 vector.to_array()
263 }
264}
265
266impl<T, const LANES: usize> Default for Mask<T, LANES>
267where
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
278impl<T, const LANES: usize> PartialEq for Mask<T, LANES>
279where
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
290impl<T, const LANES: usize> PartialOrd for Mask<T, LANES>
291where
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
302impl<T, const LANES: usize> fmt::Debug for Mask<T, LANES>
303where
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
314impl<T, const LANES: usize> core::ops::BitAnd for Mask<T, LANES>
315where
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
327impl<T, const LANES: usize> core::ops::BitAnd<bool> for Mask<T, LANES>
328where
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
340impl<T, const LANES: usize> core::ops::BitAnd<Mask<T, LANES>> for bool
341where
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
353impl<T, const LANES: usize> core::ops::BitOr for Mask<T, LANES>
354where
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
366impl<T, const LANES: usize> core::ops::BitOr<bool> for Mask<T, LANES>
367where
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
379impl<T, const LANES: usize> core::ops::BitOr<Mask<T, LANES>> for bool
380where
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
392impl<T, const LANES: usize> core::ops::BitXor for Mask<T, LANES>
393where
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
405impl<T, const LANES: usize> core::ops::BitXor<bool> for Mask<T, LANES>
406where
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
418impl<T, const LANES: usize> core::ops::BitXor<Mask<T, LANES>> for bool
419where
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
431impl<T, const LANES: usize> core::ops::Not for Mask<T, LANES>
432where
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
444impl<T, const LANES: usize> core::ops::BitAndAssign for Mask<T, LANES>
445where
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
455impl<T, const LANES: usize> core::ops::BitAndAssign<bool> for Mask<T, LANES>
456where
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
466impl<T, const LANES: usize> core::ops::BitOrAssign for Mask<T, LANES>
467where
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
477impl<T, const LANES: usize> core::ops::BitOrAssign<bool> for Mask<T, LANES>
478where
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
488impl<T, const LANES: usize> core::ops::BitXorAssign for Mask<T, LANES>
489where
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
499impl<T, const LANES: usize> core::ops::BitXorAssign<bool> for Mask<T, LANES>
500where
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
511pub type mask8x8 = Mask<i8, 8>;
512
513/// Vector of 16 8-bit masks
514pub type mask8x16 = Mask<i8, 16>;
515
516/// Vector of 32 8-bit masks
517pub type mask8x32 = Mask<i8, 32>;
518
519/// Vector of 16 8-bit masks
520pub type mask8x64 = Mask<i8, 64>;
521
522/// Vector of four 16-bit masks
523pub type mask16x4 = Mask<i16, 4>;
524
525/// Vector of eight 16-bit masks
526pub type mask16x8 = Mask<i16, 8>;
527
528/// Vector of 16 16-bit masks
529pub type mask16x16 = Mask<i16, 16>;
530
531/// Vector of 32 16-bit masks
5099ac24 532pub type mask16x32 = Mask<i16, 32>;
3c0e092e
XL
533
534/// Vector of two 32-bit masks
535pub type mask32x2 = Mask<i32, 2>;
536
537/// Vector of four 32-bit masks
538pub type mask32x4 = Mask<i32, 4>;
539
540/// Vector of eight 32-bit masks
541pub type mask32x8 = Mask<i32, 8>;
542
543/// Vector of 16 32-bit masks
544pub type mask32x16 = Mask<i32, 16>;
545
546/// Vector of two 64-bit masks
547pub type mask64x2 = Mask<i64, 2>;
548
549/// Vector of four 64-bit masks
550pub type mask64x4 = Mask<i64, 4>;
551
552/// Vector of eight 64-bit masks
553pub type mask64x8 = Mask<i64, 8>;
554
555/// Vector of two pointer-width masks
556pub type masksizex2 = Mask<isize, 2>;
557
558/// Vector of four pointer-width masks
559pub type masksizex4 = Mask<isize, 4>;
560
561/// Vector of eight pointer-width masks
562pub type masksizex8 = Mask<isize, 8>;
563
564macro_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}
578impl_from! { i8 => i16, i32, i64, isize }
579impl_from! { i16 => i32, i64, isize, i8 }
580impl_from! { i32 => i64, isize, i8, i16 }
581impl_from! { i64 => isize, i8, i16, i32 }
582impl_from! { isize => i8, i16, i32, i64 }