|
12 | 12 | )]
|
13 | 13 | mod mask_impl;
|
14 | 14 |
|
| 15 | +use crate::simd::intrinsics; |
15 | 16 | use crate::simd::{LaneCount, Simd, SimdElement, SupportedLaneCount};
|
16 | 17 | use core::cmp::Ordering;
|
17 |
| -use core::fmt; |
| 18 | +use core::{fmt, mem}; |
18 | 19 |
|
19 | 20 | mod sealed {
|
20 | 21 | use super::*;
|
@@ -105,22 +106,39 @@ where
|
105 | 106 | Self(mask_impl::Mask::splat(value))
|
106 | 107 | }
|
107 | 108 |
|
108 |
| - /// Converts an array to a SIMD vector. |
| 109 | + /// Converts an array of bools to a SIMD mask. |
109 | 110 | pub fn from_array(array: [bool; LANES]) -> Self {
|
110 |
| - let mut vector = Self::splat(false); |
111 |
| - for (i, v) in array.iter().enumerate() { |
112 |
| - vector.set(i, *v); |
| 111 | + // SAFETY: Rust's bool has a layout of 1 byte (u8) with a value of |
| 112 | + // true: 0b_0000_0001 |
| 113 | + // false: 0b_0000_0000 |
| 114 | + // Thus, an array of bools is also a valid array of bytes: [u8; N] |
| 115 | + // This would be hypothetically valid as an "in-place" transmute, |
| 116 | + // but these are "dependently-sized" types, so copy elision it is! |
| 117 | + unsafe { |
| 118 | + let bytes: [u8; LANES] = mem::transmute_copy(&array); |
| 119 | + let bools: Simd<i8, LANES> = |
| 120 | + intrinsics::simd_ne(Simd::from_array(bytes), Simd::splat(0u8)); |
| 121 | + Mask::from_int_unchecked(intrinsics::simd_cast(bools)) |
113 | 122 | }
|
114 |
| - vector |
115 | 123 | }
|
116 | 124 |
|
117 |
| - /// Converts a SIMD vector to an array. |
| 125 | + /// Converts a SIMD mask to an array of bools. |
118 | 126 | pub fn to_array(self) -> [bool; LANES] {
|
119 |
| - let mut array = [false; LANES]; |
120 |
| - for (i, v) in array.iter_mut().enumerate() { |
121 |
| - *v = self.test(i); |
| 127 | + // This follows mostly the same logic as from_array. |
| 128 | + // SAFETY: Rust's bool has a layout of 1 byte (u8) with a value of |
| 129 | + // true: 0b_0000_0001 |
| 130 | + // false: 0b_0000_0000 |
| 131 | + // Thus, an array of bools is also a valid array of bytes: [u8; N] |
| 132 | + // Since our masks are equal to integers where all bits are set, |
| 133 | + // we can simply convert them to i8s, and then bitand them by the |
| 134 | + // bitpattern for Rust's "true" bool. |
| 135 | + // This would be hypothetically valid as an "in-place" transmute, |
| 136 | + // but these are "dependently-sized" types, so copy elision it is! |
| 137 | + unsafe { |
| 138 | + let mut bytes: Simd<i8, LANES> = intrinsics::simd_cast(self.to_int()); |
| 139 | + bytes &= Simd::splat(1i8); |
| 140 | + mem::transmute_copy(&bytes) |
122 | 141 | }
|
123 |
| - array |
124 | 142 | }
|
125 | 143 |
|
126 | 144 | /// Converts a vector of integers to a mask, where 0 represents `false` and -1
|
|
0 commit comments