Skip to content

Commit a4f5f01

Browse files
Use intrinsics for Mask::{to,from}_array
This significantly simplifies codegen and should improve mask perf. Co-authored-by: Jacob Lifshay <[email protected]>
1 parent 41db153 commit a4f5f01

File tree

1 file changed

+29
-11
lines changed

1 file changed

+29
-11
lines changed

crates/core_simd/src/masks.rs

+29-11
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,10 @@
1212
)]
1313
mod mask_impl;
1414

15+
use crate::simd::intrinsics;
1516
use crate::simd::{LaneCount, Simd, SimdElement, SupportedLaneCount};
1617
use core::cmp::Ordering;
17-
use core::fmt;
18+
use core::{fmt, mem};
1819

1920
mod sealed {
2021
use super::*;
@@ -105,22 +106,39 @@ where
105106
Self(mask_impl::Mask::splat(value))
106107
}
107108

108-
/// Converts an array to a SIMD vector.
109+
/// Converts an array of bools to a SIMD mask.
109110
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))
113122
}
114-
vector
115123
}
116124

117-
/// Converts a SIMD vector to an array.
125+
/// Converts a SIMD mask to an array of bools.
118126
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)
122141
}
123-
array
124142
}
125143

126144
/// Converts a vector of integers to a mask, where 0 represents `false` and -1

0 commit comments

Comments
 (0)