Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions crates/core_simd/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#![no_std]
#![feature(
arbitrary_self_types,
convert_float_to_int,
f16,
core_intrinsics,
Expand Down
81 changes: 81 additions & 0 deletions crates/core_simd/src/masks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,80 @@ where
unsafe { core::intrinsics::simd::simd_reduce_all(self.0) }
}

/// Test if each element is equal to the corresponding element in `other`.
#[inline]
#[must_use = "method returns a new mask and does not mutate the original value"]
pub fn simd_eq(self, other: Self) -> Self {
// Safety: `self` is a mask vector, and the result of comparison is always a valid mask.
unsafe { Self::from_simd_unchecked(core::intrinsics::simd::simd_eq(self.0, other.0)) }
}

/// Test if each element is not equal to the corresponding element in `other`.
#[inline]
#[must_use = "method returns a new mask and does not mutate the original value"]
pub fn simd_ne(self, other: Self) -> Self {
// Safety: `self` is a mask vector, and the result of comparison is always a valid mask.
unsafe { Self::from_simd_unchecked(core::intrinsics::simd::simd_ne(self.0, other.0)) }
}

/// Test if each element is less than the corresponding element in `other`.
#[inline]
#[must_use = "method returns a new mask and does not mutate the original value"]
pub fn simd_lt(self, other: Self) -> Self {
// Safety: `self` is a mask vector, and the result of comparison is always a valid mask.
unsafe { Self::from_simd_unchecked(core::intrinsics::simd::simd_lt(self.0, other.0)) }
}

/// Test if each element is less than or equal to the corresponding element in `other`.
#[inline]
#[must_use = "method returns a new mask and does not mutate the original value"]
pub fn simd_le(self, other: Self) -> Self {
// Safety: `self` is a mask vector, and the result of comparison is always a valid mask.
unsafe { Self::from_simd_unchecked(core::intrinsics::simd::simd_le(self.0, other.0)) }
}

/// Test if each element is greater than the corresponding element in `other`.
#[inline]
#[must_use = "method returns a new mask and does not mutate the original value"]
pub fn simd_gt(self, other: Self) -> Self {
// Safety: `self` is a mask vector, and the result of comparison is always a valid mask.
unsafe { Self::from_simd_unchecked(core::intrinsics::simd::simd_gt(self.0, other.0)) }
}

/// Test if each element is greater than or equal to the corresponding element in `other`.
#[inline]
#[must_use = "method returns a new mask and does not mutate the original value"]
pub fn simd_ge(self, other: Self) -> Self {
// Safety: `self` is a mask vector, and the result of comparison is always a valid mask.
unsafe { Self::from_simd_unchecked(core::intrinsics::simd::simd_ge(self.0, other.0)) }
}

/// Returns the element-wise maximum with `other`.
#[inline]
#[must_use = "method returns a new mask and does not mutate the original value"]
pub fn simd_max(self, other: Self) -> Self {
self.simd_gt(other).select(other, self)
}

/// Returns the element-wise minimum with `other`.
#[inline]
#[must_use = "method returns a new mask and does not mutate the original value"]
pub fn simd_min(self, other: Self) -> Self {
self.simd_lt(other).select(other, self)
}

/// Restrict each element to a certain interval.
#[inline]
#[must_use = "method returns a new mask and does not mutate the original value"]
#[track_caller]
pub fn simd_clamp(self, min: Self, max: Self) -> Self {
assert!(
min.simd_le(max).all(),
"each element in `min` must be less than or equal to the corresponding element in `max`",
);
self.simd_max(min).simd_min(max)
}

/// Creates a bitmask from a mask.
///
/// Each bit is set if the corresponding element in the mask is `true`.
Expand Down Expand Up @@ -667,3 +741,10 @@ impl_from! { i16 => i32, i64, isize, i8 }
impl_from! { i32 => i64, isize, i8, i16 }
impl_from! { i64 => isize, i8, i16, i32 }
impl_from! { isize => i8, i16, i32, i64 }

impl<T, const N: usize> core::ops::Receiver for Mask<T, N>
where
T: MaskElement,
{
type Target = T;
}
73 changes: 24 additions & 49 deletions crates/core_simd/src/simd/cmp/eq.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,35 +4,41 @@ use crate::simd::{
};

/// Parallel `PartialEq`.
pub trait SimdPartialEq {
/// The mask type returned by each comparison.
type Mask;

pub trait SimdPartialEq: SimdElement {
/// Test if each element is equal to the corresponding element in `other`.
#[must_use = "method returns a new mask and does not mutate the original value"]
fn simd_eq(self, other: Self) -> Self::Mask;
fn simd_eq<const N: usize>(
self: Simd<Self, N>,
other: Simd<Self, N>,
) -> Mask<<Self as SimdElement>::Mask, N>;

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

macro_rules! impl_number {
{ $($number:ty),* } => {
$(
impl<const N: usize> SimdPartialEq for Simd<$number, N>
{
type Mask = Mask<<$number as SimdElement>::Mask, N>;

impl SimdPartialEq for $number {
#[inline]
fn simd_eq(self, other: Self) -> Self::Mask {
fn simd_eq<const N: usize>(
self: Simd<Self, N>,
other: Simd<Self, N>,
) -> Mask<<Self as SimdElement>::Mask, N> {
// Safety: `self` is a vector, and the result of the comparison
// is always a valid mask.
unsafe { Mask::from_simd_unchecked(core::intrinsics::simd::simd_eq(self, other)) }
}

#[inline]
fn simd_ne(self, other: Self) -> Self::Mask {
fn simd_ne<const N: usize>(
self: Simd<Self, N>,
other: Simd<Self, N>,
) -> Mask<<Self as SimdElement>::Mask, N> {
// Safety: `self` is a vector, and the result of the comparison
// is always a valid mask.
unsafe { Mask::from_simd_unchecked(core::intrinsics::simd::simd_ne(self, other)) }
Expand All @@ -44,57 +50,26 @@ macro_rules! impl_number {

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

macro_rules! impl_mask {
{ $($integer:ty),* } => {
$(
impl<const N: usize> SimdPartialEq for Mask<$integer, N>
{
type Mask = Self;

#[inline]
fn simd_eq(self, other: Self) -> Self::Mask {
// Safety: `self` is a vector, and the result of the comparison
// is always a valid mask.
unsafe { Self::from_simd_unchecked(core::intrinsics::simd::simd_eq(self.to_simd(), other.to_simd())) }
}

#[inline]
fn simd_ne(self, other: Self) -> Self::Mask {
// Safety: `self` is a vector, and the result of the comparison
// is always a valid mask.
unsafe { Self::from_simd_unchecked(core::intrinsics::simd::simd_ne(self.to_simd(), other.to_simd())) }
}
}
)*
}
}

impl_mask! { i8, i16, i32, i64, isize }

impl<T, const N: usize> SimdPartialEq for Simd<*const T, N> {
type Mask = Mask<isize, N>;

impl<T> SimdPartialEq for *const T {
#[inline]
fn simd_eq(self, other: Self) -> Self::Mask {
fn simd_eq<const N: usize>(self: Simd<Self, N>, other: Simd<Self, N>) -> Mask<isize, N> {
self.addr().simd_eq(other.addr())
}

#[inline]
fn simd_ne(self, other: Self) -> Self::Mask {
fn simd_ne<const N: usize>(self: Simd<Self, N>, other: Simd<Self, N>) -> Mask<isize, N> {
self.addr().simd_ne(other.addr())
}
}

impl<T, const N: usize> SimdPartialEq for Simd<*mut T, N> {
type Mask = Mask<isize, N>;

impl<T> SimdPartialEq for *mut T {
#[inline]
fn simd_eq(self, other: Self) -> Self::Mask {
fn simd_eq<const N: usize>(self: Simd<Self, N>, other: Simd<Self, N>) -> Mask<isize, N> {
self.addr().simd_eq(other.addr())
}

#[inline]
fn simd_ne(self, other: Self) -> Self::Mask {
fn simd_ne<const N: usize>(self: Simd<Self, N>, other: Simd<Self, N>) -> Mask<isize, N> {
self.addr().simd_ne(other.addr())
}
}
Loading
Loading