Skip to content

Commit f935cb3

Browse files
committed
Implement traits over scalars with Simd as a self type
1 parent bce8032 commit f935cb3

16 files changed

Lines changed: 565 additions & 449 deletions

File tree

crates/core_simd/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#![no_std]
22
#![feature(
3+
arbitrary_self_types,
34
convert_float_to_int,
45
f16,
56
core_intrinsics,

crates/core_simd/src/masks.rs

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,80 @@ where
291291
unsafe { core::intrinsics::simd::simd_reduce_all(self.0) }
292292
}
293293

294+
/// Test if each element is equal to the corresponding element in `other`.
295+
#[inline]
296+
#[must_use = "method returns a new mask and does not mutate the original value"]
297+
pub fn simd_eq(self, other: Self) -> Self {
298+
// Safety: `self` is a mask vector, and the result of comparison is always a valid mask.
299+
unsafe { Self::from_simd_unchecked(core::intrinsics::simd::simd_eq(self.0, other.0)) }
300+
}
301+
302+
/// Test if each element is not equal to the corresponding element in `other`.
303+
#[inline]
304+
#[must_use = "method returns a new mask and does not mutate the original value"]
305+
pub fn simd_ne(self, other: Self) -> Self {
306+
// Safety: `self` is a mask vector, and the result of comparison is always a valid mask.
307+
unsafe { Self::from_simd_unchecked(core::intrinsics::simd::simd_ne(self.0, other.0)) }
308+
}
309+
310+
/// Test if each element is less than the corresponding element in `other`.
311+
#[inline]
312+
#[must_use = "method returns a new mask and does not mutate the original value"]
313+
pub fn simd_lt(self, other: Self) -> Self {
314+
// Safety: `self` is a mask vector, and the result of comparison is always a valid mask.
315+
unsafe { Self::from_simd_unchecked(core::intrinsics::simd::simd_lt(self.0, other.0)) }
316+
}
317+
318+
/// Test if each element is less than or equal to the corresponding element in `other`.
319+
#[inline]
320+
#[must_use = "method returns a new mask and does not mutate the original value"]
321+
pub fn simd_le(self, other: Self) -> Self {
322+
// Safety: `self` is a mask vector, and the result of comparison is always a valid mask.
323+
unsafe { Self::from_simd_unchecked(core::intrinsics::simd::simd_le(self.0, other.0)) }
324+
}
325+
326+
/// Test if each element is greater than the corresponding element in `other`.
327+
#[inline]
328+
#[must_use = "method returns a new mask and does not mutate the original value"]
329+
pub fn simd_gt(self, other: Self) -> Self {
330+
// Safety: `self` is a mask vector, and the result of comparison is always a valid mask.
331+
unsafe { Self::from_simd_unchecked(core::intrinsics::simd::simd_gt(self.0, other.0)) }
332+
}
333+
334+
/// Test if each element is greater than or equal to the corresponding element in `other`.
335+
#[inline]
336+
#[must_use = "method returns a new mask and does not mutate the original value"]
337+
pub fn simd_ge(self, other: Self) -> Self {
338+
// Safety: `self` is a mask vector, and the result of comparison is always a valid mask.
339+
unsafe { Self::from_simd_unchecked(core::intrinsics::simd::simd_ge(self.0, other.0)) }
340+
}
341+
342+
/// Returns the element-wise maximum with `other`.
343+
#[inline]
344+
#[must_use = "method returns a new mask and does not mutate the original value"]
345+
pub fn simd_max(self, other: Self) -> Self {
346+
self.simd_gt(other).select(other, self)
347+
}
348+
349+
/// Returns the element-wise minimum with `other`.
350+
#[inline]
351+
#[must_use = "method returns a new mask and does not mutate the original value"]
352+
pub fn simd_min(self, other: Self) -> Self {
353+
self.simd_lt(other).select(other, self)
354+
}
355+
356+
/// Restrict each element to a certain interval.
357+
#[inline]
358+
#[must_use = "method returns a new mask and does not mutate the original value"]
359+
#[track_caller]
360+
pub fn simd_clamp(self, min: Self, max: Self) -> Self {
361+
assert!(
362+
min.simd_le(max).all(),
363+
"each element in `min` must be less than or equal to the corresponding element in `max`",
364+
);
365+
self.simd_max(min).simd_min(max)
366+
}
367+
294368
/// Creates a bitmask from a mask.
295369
///
296370
/// Each bit is set if the corresponding element in the mask is `true`.
@@ -667,3 +741,10 @@ impl_from! { i16 => i32, i64, isize, i8 }
667741
impl_from! { i32 => i64, isize, i8, i16 }
668742
impl_from! { i64 => isize, i8, i16, i32 }
669743
impl_from! { isize => i8, i16, i32, i64 }
744+
745+
impl<T, const N: usize> core::ops::Receiver for Mask<T, N>
746+
where
747+
T: MaskElement,
748+
{
749+
type Target = T;
750+
}

crates/core_simd/src/simd/cmp/eq.rs

Lines changed: 24 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -4,32 +4,41 @@ use crate::simd::{
44
};
55

66
/// Parallel `PartialEq`.
7-
pub trait SimdPartialEq<T, const N: usize>
8-
where
9-
T: SimdElement,
10-
{
7+
pub trait SimdPartialEq: SimdElement {
118
/// Test if each element is equal to the corresponding element in `other`.
129
#[must_use = "method returns a new mask and does not mutate the original value"]
13-
fn simd_eq(self, other: Self) -> Mask<<T as SimdElement>::Mask, N>;
10+
fn simd_eq<const N: usize>(
11+
self: Simd<Self, N>,
12+
other: Simd<Self, N>,
13+
) -> Mask<<Self as SimdElement>::Mask, N>;
1414

1515
/// Test if each element is not equal to the corresponding element in `other`.
1616
#[must_use = "method returns a new mask and does not mutate the original value"]
17-
fn simd_ne(self, other: Self) -> Mask<<T as SimdElement>::Mask, N>;
17+
fn simd_ne<const N: usize>(
18+
self: Simd<Self, N>,
19+
other: Simd<Self, N>,
20+
) -> Mask<<Self as SimdElement>::Mask, N>;
1821
}
1922

2023
macro_rules! impl_number {
2124
{ $($number:ty),* } => {
2225
$(
23-
impl<const N: usize> SimdPartialEq<$number, N> for Simd<$number, N> {
26+
impl SimdPartialEq for $number {
2427
#[inline]
25-
fn simd_eq(self, other: Self) -> Mask<<$number as SimdElement>::Mask, N> {
28+
fn simd_eq<const N: usize>(
29+
self: Simd<Self, N>,
30+
other: Simd<Self, N>,
31+
) -> Mask<<Self as SimdElement>::Mask, N> {
2632
// Safety: `self` is a vector, and the result of the comparison
2733
// is always a valid mask.
2834
unsafe { Mask::from_simd_unchecked(core::intrinsics::simd::simd_eq(self, other)) }
2935
}
3036

3137
#[inline]
32-
fn simd_ne(self, other: Self) -> Mask<<$number as SimdElement>::Mask, N> {
38+
fn simd_ne<const N: usize>(
39+
self: Simd<Self, N>,
40+
other: Simd<Self, N>,
41+
) -> Mask<<Self as SimdElement>::Mask, N> {
3342
// Safety: `self` is a vector, and the result of the comparison
3443
// is always a valid mask.
3544
unsafe { Mask::from_simd_unchecked(core::intrinsics::simd::simd_ne(self, other)) }
@@ -41,50 +50,26 @@ macro_rules! impl_number {
4150

4251
impl_number! { f16, f32, f64, u8, u16, u32, u64, usize, i8, i16, i32, i64, isize }
4352

44-
macro_rules! impl_mask {
45-
{ $($integer:ty),* } => {
46-
$(
47-
impl<const N: usize> SimdPartialEq<$integer, N> for Mask<$integer, N> {
48-
#[inline]
49-
fn simd_eq(self, other: Self) -> Mask<<$integer as SimdElement>::Mask, N> {
50-
// Safety: `self` is a vector, and the result of the comparison
51-
// is always a valid mask.
52-
unsafe { Self::from_simd_unchecked(core::intrinsics::simd::simd_eq(self.to_simd(), other.to_simd())) }
53-
}
54-
55-
#[inline]
56-
fn simd_ne(self, other: Self) -> Mask<<$integer as SimdElement>::Mask, N> {
57-
// Safety: `self` is a vector, and the result of the comparison
58-
// is always a valid mask.
59-
unsafe { Self::from_simd_unchecked(core::intrinsics::simd::simd_ne(self.to_simd(), other.to_simd())) }
60-
}
61-
}
62-
)*
63-
}
64-
}
65-
66-
impl_mask! { i8, i16, i32, i64, isize }
67-
68-
impl<T, const N: usize> SimdPartialEq<*const T, N> for Simd<*const T, N> {
53+
impl<T> SimdPartialEq for *const T {
6954
#[inline]
70-
fn simd_eq(self, other: Self) -> Mask<isize, N> {
55+
fn simd_eq<const N: usize>(self: Simd<Self, N>, other: Simd<Self, N>) -> Mask<isize, N> {
7156
self.addr().simd_eq(other.addr())
7257
}
7358

7459
#[inline]
75-
fn simd_ne(self, other: Self) -> Mask<isize, N> {
60+
fn simd_ne<const N: usize>(self: Simd<Self, N>, other: Simd<Self, N>) -> Mask<isize, N> {
7661
self.addr().simd_ne(other.addr())
7762
}
7863
}
7964

80-
impl<T, const N: usize> SimdPartialEq<*mut T, N> for Simd<*mut T, N> {
65+
impl<T> SimdPartialEq for *mut T {
8166
#[inline]
82-
fn simd_eq(self, other: Self) -> Mask<isize, N> {
67+
fn simd_eq<const N: usize>(self: Simd<Self, N>, other: Simd<Self, N>) -> Mask<isize, N> {
8368
self.addr().simd_eq(other.addr())
8469
}
8570

8671
#[inline]
87-
fn simd_ne(self, other: Self) -> Mask<isize, N> {
72+
fn simd_ne<const N: usize>(self: Simd<Self, N>, other: Simd<Self, N>) -> Mask<isize, N> {
8873
self.addr().simd_ne(other.addr())
8974
}
9075
}

0 commit comments

Comments
 (0)