Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change Mask element to match Simd element #322

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
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
2 changes: 1 addition & 1 deletion crates/core_simd/src/elements/const_ptr.rs
Original file line number Diff line number Diff line change
@@ -79,7 +79,7 @@ where
type Usize = Simd<usize, LANES>;
type Isize = Simd<isize, LANES>;
type MutPtr = Simd<*mut T, LANES>;
type Mask = Mask<isize, LANES>;
type Mask = Mask<*const T, LANES>;

#[inline]
fn is_null(self) -> Self::Mask {
13 changes: 6 additions & 7 deletions crates/core_simd/src/elements/float.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use super::sealed::Sealed;
use crate::simd::{
intrinsics, LaneCount, Mask, Simd, SimdElement, SimdPartialEq, SimdPartialOrd,
SupportedLaneCount,
intrinsics, LaneCount, Mask, Simd, SimdPartialEq, SimdPartialOrd, SupportedLaneCount,
};

/// Operations on SIMD vectors of floats.
@@ -191,7 +190,7 @@ pub trait SimdFloat: Copy + Sealed {
}

macro_rules! impl_trait {
{ $($ty:ty { bits: $bits_ty:ty, mask: $mask_ty:ty }),* } => {
{ $($ty:ty { bits: $bits_ty:ty }),* } => {
$(
impl<const LANES: usize> Sealed for Simd<$ty, LANES>
where
@@ -203,7 +202,7 @@ macro_rules! impl_trait {
where
LaneCount<LANES>: SupportedLaneCount,
{
type Mask = Mask<<$mask_ty as SimdElement>::Mask, LANES>;
type Mask = Mask<$ty, LANES>;
type Scalar = $ty;
type Bits = Simd<$bits_ty, LANES>;

@@ -251,7 +250,7 @@ macro_rules! impl_trait {
#[inline]
fn is_sign_negative(self) -> Self::Mask {
let sign_bits = self.to_bits() & Simd::splat((!0 >> 1) + 1);
sign_bits.simd_gt(Simd::splat(0))
sign_bits.simd_gt(Simd::splat(0)).cast()
}

#[inline]
@@ -271,7 +270,7 @@ macro_rules! impl_trait {

#[inline]
fn is_subnormal(self) -> Self::Mask {
self.abs().simd_ne(Self::splat(0.0)) & (self.to_bits() & Self::splat(Self::Scalar::INFINITY).to_bits()).simd_eq(Simd::splat(0))
self.abs().simd_ne(Self::splat(0.0)) & (self.to_bits() & Self::splat(Self::Scalar::INFINITY).to_bits()).simd_eq(Simd::splat(0)).cast()
}

#[inline]
@@ -354,4 +353,4 @@ macro_rules! impl_trait {
}
}

impl_trait! { f32 { bits: u32, mask: i32 }, f64 { bits: u64, mask: i64 } }
impl_trait! { f32 { bits: u32 }, f64 { bits: u64 } }
6 changes: 2 additions & 4 deletions crates/core_simd/src/elements/int.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
use super::sealed::Sealed;
use crate::simd::{
intrinsics, LaneCount, Mask, Simd, SimdElement, SimdPartialOrd, SupportedLaneCount,
};
use crate::simd::{intrinsics, LaneCount, Mask, Simd, SimdPartialOrd, SupportedLaneCount};

/// Operations on SIMD vectors of signed integers.
pub trait SimdInt: Copy + Sealed {
@@ -196,7 +194,7 @@ macro_rules! impl_trait {
where
LaneCount<LANES>: SupportedLaneCount,
{
type Mask = Mask<<$ty as SimdElement>::Mask, LANES>;
type Mask = Mask<$ty, LANES>;
type Scalar = $ty;

#[inline]
2 changes: 1 addition & 1 deletion crates/core_simd/src/elements/mut_ptr.rs
Original file line number Diff line number Diff line change
@@ -74,7 +74,7 @@ where
type Usize = Simd<usize, LANES>;
type Isize = Simd<isize, LANES>;
type ConstPtr = Simd<*const T, LANES>;
type Mask = Mask<isize, LANES>;
type Mask = Mask<*mut T, LANES>;

#[inline]
fn is_null(self) -> Self::Mask {
16 changes: 8 additions & 8 deletions crates/core_simd/src/eq.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::simd::{
intrinsics, LaneCount, Mask, Simd, SimdConstPtr, SimdElement, SimdMutPtr, SupportedLaneCount,
intrinsics, LaneCount, Mask, Simd, SimdConstPtr, SimdMutPtr, SupportedLaneCount,
};

/// Parallel `PartialEq`.
@@ -23,7 +23,7 @@ macro_rules! impl_number {
where
LaneCount<LANES>: SupportedLaneCount,
{
type Mask = Mask<<$number as SimdElement>::Mask, LANES>;
type Mask = Mask<$number, LANES>;

#[inline]
fn simd_eq(self, other: Self) -> Self::Mask {
@@ -78,32 +78,32 @@ impl<T, const LANES: usize> SimdPartialEq for Simd<*const T, LANES>
where
LaneCount<LANES>: SupportedLaneCount,
{
type Mask = Mask<isize, LANES>;
type Mask = Mask<*const T, LANES>;

#[inline]
fn simd_eq(self, other: Self) -> Self::Mask {
self.addr().simd_eq(other.addr())
self.addr().simd_eq(other.addr()).cast()
}

#[inline]
fn simd_ne(self, other: Self) -> Self::Mask {
self.addr().simd_ne(other.addr())
self.addr().simd_ne(other.addr()).cast()
}
}

impl<T, const LANES: usize> SimdPartialEq for Simd<*mut T, LANES>
where
LaneCount<LANES>: SupportedLaneCount,
{
type Mask = Mask<isize, LANES>;
type Mask = Mask<*mut T, LANES>;

#[inline]
fn simd_eq(self, other: Self) -> Self::Mask {
self.addr().simd_eq(other.addr())
self.addr().simd_eq(other.addr()).cast()
}

#[inline]
fn simd_ne(self, other: Self) -> Self::Mask {
self.addr().simd_ne(other.addr())
self.addr().simd_ne(other.addr()).cast()
}
}
87 changes: 34 additions & 53 deletions crates/core_simd/src/masks.rs
Original file line number Diff line number Diff line change
@@ -91,19 +91,19 @@ impl_element! { isize }
#[repr(transparent)]
pub struct Mask<T, const LANES: usize>(mask_impl::Mask<T, LANES>)
where
T: MaskElement,
T: SimdElement,
LaneCount<LANES>: SupportedLaneCount;

impl<T, const LANES: usize> Copy for Mask<T, LANES>
where
T: MaskElement,
T: SimdElement,
LaneCount<LANES>: SupportedLaneCount,
{
}

impl<T, const LANES: usize> Clone for Mask<T, LANES>
where
T: MaskElement,
T: SimdElement,
LaneCount<LANES>: SupportedLaneCount,
{
#[inline]
@@ -114,7 +114,7 @@ where

impl<T, const LANES: usize> Mask<T, LANES>
where
T: MaskElement,
T: SimdElement,
LaneCount<LANES>: SupportedLaneCount,
{
/// Construct a mask by setting all lanes to the given value.
@@ -167,7 +167,7 @@ where
/// All lanes must be either 0 or -1.
#[inline]
#[must_use = "method returns a new mask and does not mutate the original value"]
pub unsafe fn from_int_unchecked(value: Simd<T, LANES>) -> Self {
pub unsafe fn from_int_unchecked(value: Simd<T::Mask, LANES>) -> Self {
// Safety: the caller must confirm this invariant
unsafe { Self(mask_impl::Mask::from_int_unchecked(value)) }
}
@@ -179,8 +179,8 @@ where
/// Panics if any lane is not 0 or -1.
#[inline]
#[must_use = "method returns a new mask and does not mutate the original value"]
pub fn from_int(value: Simd<T, LANES>) -> Self {
assert!(T::valid(value), "all values must be either 0 or -1",);
pub fn from_int(value: Simd<T::Mask, LANES>) -> Self {
assert!(T::Mask::valid(value), "all values must be either 0 or -1",);
// Safety: the validity has been checked
unsafe { Self::from_int_unchecked(value) }
}
@@ -189,15 +189,15 @@ where
/// represents `true`.
#[inline]
#[must_use = "method returns a new vector and does not mutate the original value"]
pub fn to_int(self) -> Simd<T, LANES> {
pub fn to_int(self) -> Simd<T::Mask, LANES> {
self.0.to_int()
}

/// Converts the mask to a mask of any other lane size.
#[inline]
#[must_use = "method returns a new mask and does not mutate the original value"]
pub fn cast<U: MaskElement>(self) -> Mask<U, LANES> {
Mask(self.0.convert())
pub fn cast<U: SimdElement>(self) -> Mask<U, LANES> {
Mask(self.0.cast())
}

/// Tests the value of the specified lane.
@@ -266,7 +266,7 @@ where
// vector/array conversion
impl<T, const LANES: usize> From<[bool; LANES]> for Mask<T, LANES>
where
T: MaskElement,
T: SimdElement,
LaneCount<LANES>: SupportedLaneCount,
{
#[inline]
@@ -277,7 +277,7 @@ where

impl<T, const LANES: usize> From<Mask<T, LANES>> for [bool; LANES]
where
T: MaskElement,
T: SimdElement,
LaneCount<LANES>: SupportedLaneCount,
{
#[inline]
@@ -288,7 +288,7 @@ where

impl<T, const LANES: usize> Default for Mask<T, LANES>
where
T: MaskElement,
T: SimdElement,
LaneCount<LANES>: SupportedLaneCount,
{
#[inline]
@@ -300,7 +300,8 @@ where

impl<T, const LANES: usize> PartialEq for Mask<T, LANES>
where
T: MaskElement + PartialEq,
T: SimdElement,
T::Mask: PartialEq,
LaneCount<LANES>: SupportedLaneCount,
{
#[inline]
@@ -312,7 +313,8 @@ where

impl<T, const LANES: usize> PartialOrd for Mask<T, LANES>
where
T: MaskElement + PartialOrd,
T: SimdElement,
T::Mask: PartialOrd,
LaneCount<LANES>: SupportedLaneCount,
{
#[inline]
@@ -324,7 +326,7 @@ where

impl<T, const LANES: usize> fmt::Debug for Mask<T, LANES>
where
T: MaskElement + fmt::Debug,
T: SimdElement + fmt::Debug,
LaneCount<LANES>: SupportedLaneCount,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@@ -336,7 +338,7 @@ where

impl<T, const LANES: usize> core::ops::BitAnd for Mask<T, LANES>
where
T: MaskElement,
T: SimdElement,
LaneCount<LANES>: SupportedLaneCount,
{
type Output = Self;
@@ -349,7 +351,7 @@ where

impl<T, const LANES: usize> core::ops::BitAnd<bool> for Mask<T, LANES>
where
T: MaskElement,
T: SimdElement,
LaneCount<LANES>: SupportedLaneCount,
{
type Output = Self;
@@ -362,7 +364,7 @@ where

impl<T, const LANES: usize> core::ops::BitAnd<Mask<T, LANES>> for bool
where
T: MaskElement,
T: SimdElement,
LaneCount<LANES>: SupportedLaneCount,
{
type Output = Mask<T, LANES>;
@@ -375,7 +377,7 @@ where

impl<T, const LANES: usize> core::ops::BitOr for Mask<T, LANES>
where
T: MaskElement,
T: SimdElement,
LaneCount<LANES>: SupportedLaneCount,
{
type Output = Self;
@@ -388,7 +390,7 @@ where

impl<T, const LANES: usize> core::ops::BitOr<bool> for Mask<T, LANES>
where
T: MaskElement,
T: SimdElement,
LaneCount<LANES>: SupportedLaneCount,
{
type Output = Self;
@@ -401,7 +403,7 @@ where

impl<T, const LANES: usize> core::ops::BitOr<Mask<T, LANES>> for bool
where
T: MaskElement,
T: SimdElement,
LaneCount<LANES>: SupportedLaneCount,
{
type Output = Mask<T, LANES>;
@@ -414,7 +416,7 @@ where

impl<T, const LANES: usize> core::ops::BitXor for Mask<T, LANES>
where
T: MaskElement,
T: SimdElement,
LaneCount<LANES>: SupportedLaneCount,
{
type Output = Self;
@@ -427,7 +429,7 @@ where

impl<T, const LANES: usize> core::ops::BitXor<bool> for Mask<T, LANES>
where
T: MaskElement,
T: SimdElement,
LaneCount<LANES>: SupportedLaneCount,
{
type Output = Self;
@@ -440,7 +442,7 @@ where

impl<T, const LANES: usize> core::ops::BitXor<Mask<T, LANES>> for bool
where
T: MaskElement,
T: SimdElement,
LaneCount<LANES>: SupportedLaneCount,
{
type Output = Mask<T, LANES>;
@@ -453,7 +455,7 @@ where

impl<T, const LANES: usize> core::ops::Not for Mask<T, LANES>
where
T: MaskElement,
T: SimdElement,
LaneCount<LANES>: SupportedLaneCount,
{
type Output = Mask<T, LANES>;
@@ -466,7 +468,7 @@ where

impl<T, const LANES: usize> core::ops::BitAndAssign for Mask<T, LANES>
where
T: MaskElement,
T: SimdElement,
LaneCount<LANES>: SupportedLaneCount,
{
#[inline]
@@ -477,7 +479,7 @@ where

impl<T, const LANES: usize> core::ops::BitAndAssign<bool> for Mask<T, LANES>
where
T: MaskElement,
T: SimdElement,
LaneCount<LANES>: SupportedLaneCount,
{
#[inline]
@@ -488,7 +490,7 @@ where

impl<T, const LANES: usize> core::ops::BitOrAssign for Mask<T, LANES>
where
T: MaskElement,
T: SimdElement,
LaneCount<LANES>: SupportedLaneCount,
{
#[inline]
@@ -499,7 +501,7 @@ where

impl<T, const LANES: usize> core::ops::BitOrAssign<bool> for Mask<T, LANES>
where
T: MaskElement,
T: SimdElement,
LaneCount<LANES>: SupportedLaneCount,
{
#[inline]
@@ -510,7 +512,7 @@ where

impl<T, const LANES: usize> core::ops::BitXorAssign for Mask<T, LANES>
where
T: MaskElement,
T: SimdElement,
LaneCount<LANES>: SupportedLaneCount,
{
#[inline]
@@ -521,32 +523,11 @@ where

impl<T, const LANES: usize> core::ops::BitXorAssign<bool> for Mask<T, LANES>
where
T: MaskElement,
T: SimdElement,
LaneCount<LANES>: SupportedLaneCount,
{
#[inline]
fn bitxor_assign(&mut self, rhs: bool) {
*self ^= Self::splat(rhs);
}
}

macro_rules! impl_from {
{ $from:ty => $($to:ty),* } => {
$(
impl<const LANES: usize> From<Mask<$from, LANES>> for Mask<$to, LANES>
where
LaneCount<LANES>: SupportedLaneCount,
{
#[inline]
fn from(value: Mask<$from, LANES>) -> Self {
value.cast()
}
}
)*
}
}
impl_from! { i8 => i16, i32, i64, isize }
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 }
40 changes: 22 additions & 18 deletions crates/core_simd/src/masks/bitmask.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#![allow(unused_imports)]
use super::MaskElement;
use super::{Sealed as _, SimdElement};
use crate::simd::intrinsics;
use crate::simd::{LaneCount, Simd, SupportedLaneCount, ToBitMask};
use core::marker::PhantomData;
@@ -11,19 +11,19 @@ pub struct Mask<T, const LANES: usize>(
PhantomData<T>,
)
where
T: MaskElement,
T: SimdElement,
LaneCount<LANES>: SupportedLaneCount;

impl<T, const LANES: usize> Copy for Mask<T, LANES>
where
T: MaskElement,
T: SimdElement,
LaneCount<LANES>: SupportedLaneCount,
{
}

impl<T, const LANES: usize> Clone for Mask<T, LANES>
where
T: MaskElement,
T: SimdElement,
LaneCount<LANES>: SupportedLaneCount,
{
#[inline]
@@ -34,7 +34,7 @@ where

impl<T, const LANES: usize> PartialEq for Mask<T, LANES>
where
T: MaskElement,
T: SimdElement,
LaneCount<LANES>: SupportedLaneCount,
{
#[inline]
@@ -45,7 +45,7 @@ where

impl<T, const LANES: usize> PartialOrd for Mask<T, LANES>
where
T: MaskElement,
T: SimdElement,
LaneCount<LANES>: SupportedLaneCount,
{
#[inline]
@@ -56,14 +56,14 @@ where

impl<T, const LANES: usize> Eq for Mask<T, LANES>
where
T: MaskElement,
T: SimdElement,
LaneCount<LANES>: SupportedLaneCount,
{
}

impl<T, const LANES: usize> Ord for Mask<T, LANES>
where
T: MaskElement,
T: SimdElement,
LaneCount<LANES>: SupportedLaneCount,
{
#[inline]
@@ -74,7 +74,7 @@ where

impl<T, const LANES: usize> Mask<T, LANES>
where
T: MaskElement,
T: SimdElement,
LaneCount<LANES>: SupportedLaneCount,
{
#[inline]
@@ -107,15 +107,19 @@ where

#[inline]
#[must_use = "method returns a new vector and does not mutate the original value"]
pub fn to_int(self) -> Simd<T, LANES> {
pub fn to_int(self) -> Simd<T::Mask, LANES> {
unsafe {
intrinsics::simd_select_bitmask(self.0, Simd::splat(T::TRUE), Simd::splat(T::FALSE))
intrinsics::simd_select_bitmask(
self.0,
Simd::splat(T::Mask::TRUE),
Simd::splat(T::Mask::FALSE),
)
}
}

#[inline]
#[must_use = "method returns a new mask and does not mutate the original value"]
pub unsafe fn from_int_unchecked(value: Simd<T, LANES>) -> Self {
pub unsafe fn from_int_unchecked(value: Simd<T::Mask, LANES>) -> Self {
unsafe { Self(intrinsics::simd_bitmask(value), PhantomData) }
}

@@ -159,9 +163,9 @@ where

#[inline]
#[must_use = "method returns a new mask and does not mutate the original value"]
pub fn convert<U>(self) -> Mask<U, LANES>
pub fn cast<U>(self) -> Mask<U, LANES>
where
U: MaskElement,
U: SimdElement,
{
// Safety: bitmask layout does not depend on the element width
unsafe { core::mem::transmute_copy(&self) }
@@ -182,7 +186,7 @@ where

impl<T, const LANES: usize> core::ops::BitAnd for Mask<T, LANES>
where
T: MaskElement,
T: SimdElement,
LaneCount<LANES>: SupportedLaneCount,
<LaneCount<LANES> as SupportedLaneCount>::BitMask: AsRef<[u8]> + AsMut<[u8]>,
{
@@ -199,7 +203,7 @@ where

impl<T, const LANES: usize> core::ops::BitOr for Mask<T, LANES>
where
T: MaskElement,
T: SimdElement,
LaneCount<LANES>: SupportedLaneCount,
<LaneCount<LANES> as SupportedLaneCount>::BitMask: AsRef<[u8]> + AsMut<[u8]>,
{
@@ -216,7 +220,7 @@ where

impl<T, const LANES: usize> core::ops::BitXor for Mask<T, LANES>
where
T: MaskElement,
T: SimdElement,
LaneCount<LANES>: SupportedLaneCount,
{
type Output = Self;
@@ -232,7 +236,7 @@ where

impl<T, const LANES: usize> core::ops::Not for Mask<T, LANES>
where
T: MaskElement,
T: SimdElement,
LaneCount<LANES>: SupportedLaneCount,
{
type Output = Self;
54 changes: 31 additions & 23 deletions crates/core_simd/src/masks/full_masks.rs
Original file line number Diff line number Diff line change
@@ -1,28 +1,28 @@
//! Masks that take up full SIMD vector registers.
use super::MaskElement;
use super::{Sealed as _, SimdElement};
use crate::simd::intrinsics;
use crate::simd::{LaneCount, Simd, SupportedLaneCount, ToBitMask};

#[cfg(feature = "generic_const_exprs")]
use crate::simd::ToBitMaskArray;

#[repr(transparent)]
pub struct Mask<T, const LANES: usize>(Simd<T, LANES>)
pub struct Mask<T, const LANES: usize>(Simd<T::Mask, LANES>)
where
T: MaskElement,
T: SimdElement,
LaneCount<LANES>: SupportedLaneCount;

impl<T, const LANES: usize> Copy for Mask<T, LANES>
where
T: MaskElement,
T: SimdElement,
LaneCount<LANES>: SupportedLaneCount,
{
}

impl<T, const LANES: usize> Clone for Mask<T, LANES>
where
T: MaskElement,
T: SimdElement,
LaneCount<LANES>: SupportedLaneCount,
{
#[inline]
@@ -34,7 +34,8 @@ where

impl<T, const LANES: usize> PartialEq for Mask<T, LANES>
where
T: MaskElement + PartialEq,
T: SimdElement,
T::Mask: PartialEq,
LaneCount<LANES>: SupportedLaneCount,
{
#[inline]
@@ -45,7 +46,8 @@ where

impl<T, const LANES: usize> PartialOrd for Mask<T, LANES>
where
T: MaskElement + PartialOrd,
T: SimdElement,
T::Mask: PartialOrd,
LaneCount<LANES>: SupportedLaneCount,
{
#[inline]
@@ -56,14 +58,16 @@ where

impl<T, const LANES: usize> Eq for Mask<T, LANES>
where
T: MaskElement + Eq,
T: SimdElement,
T::Mask: Eq,
LaneCount<LANES>: SupportedLaneCount,
{
}

impl<T, const LANES: usize> Ord for Mask<T, LANES>
where
T: MaskElement + Ord,
T: SimdElement,
T::Mask: Ord,
LaneCount<LANES>: SupportedLaneCount,
{
#[inline]
@@ -103,43 +107,47 @@ impl_reverse_bits! { u8, u16, u32, u64 }

impl<T, const LANES: usize> Mask<T, LANES>
where
T: MaskElement,
T: SimdElement,
LaneCount<LANES>: SupportedLaneCount,
{
#[inline]
#[must_use = "method returns a new mask and does not mutate the original value"]
pub fn splat(value: bool) -> Self {
Self(Simd::splat(if value { T::TRUE } else { T::FALSE }))
Self(Simd::splat(if value {
T::Mask::TRUE
} else {
T::Mask::FALSE
}))
}

#[inline]
#[must_use = "method returns a new bool and does not mutate the original value"]
pub unsafe fn test_unchecked(&self, lane: usize) -> bool {
T::eq(self.0[lane], T::TRUE)
T::Mask::eq(self.0[lane], T::Mask::TRUE)
}

#[inline]
pub unsafe fn set_unchecked(&mut self, lane: usize, value: bool) {
self.0[lane] = if value { T::TRUE } else { T::FALSE }
self.0[lane] = if value { T::Mask::TRUE } else { T::Mask::FALSE }
}

#[inline]
#[must_use = "method returns a new vector and does not mutate the original value"]
pub fn to_int(self) -> Simd<T, LANES> {
pub fn to_int(self) -> Simd<T::Mask, LANES> {
self.0
}

#[inline]
#[must_use = "method returns a new mask and does not mutate the original value"]
pub unsafe fn from_int_unchecked(value: Simd<T, LANES>) -> Self {
pub unsafe fn from_int_unchecked(value: Simd<T::Mask, LANES>) -> Self {
Self(value)
}

#[inline]
#[must_use = "method returns a new mask and does not mutate the original value"]
pub fn convert<U>(self) -> Mask<U, LANES>
pub fn cast<U>(self) -> Mask<U, LANES>
where
U: MaskElement,
U: SimdElement,
{
// Safety: masks are simply integer vectors of 0 and -1, and we can cast the element type.
unsafe { Mask(intrinsics::simd_cast(self.0)) }
@@ -260,9 +268,9 @@ where
}
}

impl<T, const LANES: usize> core::convert::From<Mask<T, LANES>> for Simd<T, LANES>
impl<T, const LANES: usize> core::convert::From<Mask<T, LANES>> for Simd<T::Mask, LANES>
where
T: MaskElement,
T: SimdElement,
LaneCount<LANES>: SupportedLaneCount,
{
#[inline]
@@ -273,7 +281,7 @@ where

impl<T, const LANES: usize> core::ops::BitAnd for Mask<T, LANES>
where
T: MaskElement,
T: SimdElement,
LaneCount<LANES>: SupportedLaneCount,
{
type Output = Self;
@@ -287,7 +295,7 @@ where

impl<T, const LANES: usize> core::ops::BitOr for Mask<T, LANES>
where
T: MaskElement,
T: SimdElement,
LaneCount<LANES>: SupportedLaneCount,
{
type Output = Self;
@@ -301,7 +309,7 @@ where

impl<T, const LANES: usize> core::ops::BitXor for Mask<T, LANES>
where
T: MaskElement,
T: SimdElement,
LaneCount<LANES>: SupportedLaneCount,
{
type Output = Self;
@@ -315,7 +323,7 @@ where

impl<T, const LANES: usize> core::ops::Not for Mask<T, LANES>
where
T: MaskElement,
T: SimdElement,
LaneCount<LANES>: SupportedLaneCount,
{
type Output = Self;
16 changes: 8 additions & 8 deletions crates/core_simd/src/ord.rs
Original file line number Diff line number Diff line change
@@ -220,22 +220,22 @@ where
{
#[inline]
fn simd_lt(self, other: Self) -> Self::Mask {
self.addr().simd_lt(other.addr())
self.addr().simd_lt(other.addr()).cast()
}

#[inline]
fn simd_le(self, other: Self) -> Self::Mask {
self.addr().simd_le(other.addr())
self.addr().simd_le(other.addr()).cast()
}

#[inline]
fn simd_gt(self, other: Self) -> Self::Mask {
self.addr().simd_gt(other.addr())
self.addr().simd_gt(other.addr()).cast()
}

#[inline]
fn simd_ge(self, other: Self) -> Self::Mask {
self.addr().simd_ge(other.addr())
self.addr().simd_ge(other.addr()).cast()
}
}

@@ -269,22 +269,22 @@ where
{
#[inline]
fn simd_lt(self, other: Self) -> Self::Mask {
self.addr().simd_lt(other.addr())
self.addr().simd_lt(other.addr()).cast()
}

#[inline]
fn simd_le(self, other: Self) -> Self::Mask {
self.addr().simd_le(other.addr())
self.addr().simd_le(other.addr()).cast()
}

#[inline]
fn simd_gt(self, other: Self) -> Self::Mask {
self.addr().simd_gt(other.addr())
self.addr().simd_gt(other.addr()).cast()
}

#[inline]
fn simd_ge(self, other: Self) -> Self::Mask {
self.addr().simd_ge(other.addr())
self.addr().simd_ge(other.addr()).cast()
}
}

15 changes: 6 additions & 9 deletions crates/core_simd/src/select.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use crate::simd::intrinsics;
use crate::simd::{LaneCount, Mask, MaskElement, Simd, SimdElement, SupportedLaneCount};
use crate::simd::{LaneCount, Mask, Simd, SimdElement, SupportedLaneCount};

impl<T, const LANES: usize> Mask<T, LANES>
where
T: MaskElement,
T: SimdElement,
LaneCount<LANES>: SupportedLaneCount,
{
/// Choose lanes from two vectors.
@@ -23,14 +23,11 @@ where
/// ```
#[inline]
#[must_use = "method returns a new vector and does not mutate the original inputs"]
pub fn select<U>(
pub fn select(
self,
true_values: Simd<U, LANES>,
false_values: Simd<U, LANES>,
) -> Simd<U, LANES>
where
U: SimdElement<Mask = T>,
{
true_values: Simd<T, LANES>,
false_values: Simd<T, LANES>,
) -> Simd<T, LANES> {
// Safety: The mask has been cast to a vector of integers,
// and the operands to select between are vectors of the same type and length.
unsafe { intrinsics::simd_select(self.to_int(), true_values, false_values) }
24 changes: 12 additions & 12 deletions crates/core_simd/src/vector.rs
Original file line number Diff line number Diff line change
@@ -313,11 +313,11 @@ where
#[inline]
pub fn gather_select(
slice: &[T],
enable: Mask<isize, LANES>,
enable: Mask<usize, LANES>,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note x86 has mask sizes match the data size, not the index/address size...we should probably match that:
https://www.felixcloutier.com/x86/vgatherdps:vgatherqps#vgatherqps--vex-128-version-

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

opened #323 to track this.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. With this change it would be easy to make this take Mask<T, LANES> instead, but I'll leave that to a separate PR.

idxs: Simd<usize, LANES>,
or: Self,
) -> Self {
let enable: Mask<isize, LANES> = enable & idxs.simd_lt(Simd::splat(slice.len()));
let enable: Mask<usize, LANES> = enable & idxs.simd_lt(Simd::splat(slice.len()));
// Safety: We have masked-off out-of-bounds lanes.
unsafe { Self::gather_select_unchecked(slice, enable, idxs, or) }
}
@@ -354,15 +354,15 @@ where
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub unsafe fn gather_select_unchecked(
slice: &[T],
enable: Mask<isize, LANES>,
enable: Mask<usize, LANES>,
idxs: Simd<usize, LANES>,
or: Self,
) -> Self {
let base_ptr = Simd::<*const T, LANES>::splat(slice.as_ptr());
// Ferris forgive me, I have done pointer arithmetic here.
let ptrs = base_ptr.wrapping_add(idxs);
// Safety: The caller is responsible for determining the indices are okay to read
unsafe { Self::gather_select_ptr(ptrs, enable, or) }
unsafe { Self::gather_select_ptr(ptrs, enable.cast(), or) }
}

/// Read pointers elementwise into a SIMD vector.
@@ -421,7 +421,7 @@ where
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub unsafe fn gather_select_ptr(
source: Simd<*const T, LANES>,
enable: Mask<isize, LANES>,
enable: Mask<*const T, LANES>,
or: Self,
) -> Self {
// Safety: The caller is responsible for upholding all invariants
@@ -472,10 +472,10 @@ where
pub fn scatter_select(
self,
slice: &mut [T],
enable: Mask<isize, LANES>,
enable: Mask<usize, LANES>,
idxs: Simd<usize, LANES>,
) {
let enable: Mask<isize, LANES> = enable & idxs.simd_lt(Simd::splat(slice.len()));
let enable: Mask<usize, LANES> = enable & idxs.simd_lt(Simd::splat(slice.len()));
// Safety: We have masked-off out-of-bounds lanes.
unsafe { self.scatter_select_unchecked(slice, enable, idxs) }
}
@@ -514,7 +514,7 @@ where
pub unsafe fn scatter_select_unchecked(
self,
slice: &mut [T],
enable: Mask<isize, LANES>,
enable: Mask<usize, LANES>,
idxs: Simd<usize, LANES>,
) {
// Safety: This block works with *mut T derived from &mut 'a [T],
@@ -533,7 +533,7 @@ where
// Ferris forgive me, I have done pointer arithmetic here.
let ptrs = base_ptr.wrapping_add(idxs);
// The ptrs have been bounds-masked to prevent memory-unsafe writes insha'allah
self.scatter_select_ptr(ptrs, enable);
self.scatter_select_ptr(ptrs, enable.cast());
// Cleared ☢️ *mut T Zone
}
}
@@ -586,7 +586,7 @@ where
/// ```
#[inline]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub unsafe fn scatter_select_ptr(self, dest: Simd<*mut T, LANES>, enable: Mask<isize, LANES>) {
pub unsafe fn scatter_select_ptr(self, dest: Simd<*mut T, LANES>, enable: Mask<*mut T, LANES>) {
// Safety: The caller is responsible for upholding all invariants
unsafe { intrinsics::simd_scatter(self, dest, enable.to_int()) }
}
@@ -630,7 +630,7 @@ where
// Safety: All SIMD vectors are SimdPartialEq, and the comparison produces a valid mask.
let mask = unsafe {
let tfvec: Simd<<T as SimdElement>::Mask, LANES> = intrinsics::simd_eq(*self, *other);
Mask::from_int_unchecked(tfvec)
Mask::<T, LANES>::from_int_unchecked(tfvec)
};

// Two vectors are equal if all lanes tested true for vertical equality.
@@ -643,7 +643,7 @@ where
// Safety: All SIMD vectors are SimdPartialEq, and the comparison produces a valid mask.
let mask = unsafe {
let tfvec: Simd<<T as SimdElement>::Mask, LANES> = intrinsics::simd_ne(*self, *other);
Mask::from_int_unchecked(tfvec)
Mask::<T, LANES>::from_int_unchecked(tfvec)
};

// Two vectors are non-equal if any lane tested true for vertical non-equality.
26 changes: 10 additions & 16 deletions crates/core_simd/tests/masks.rs
Original file line number Diff line number Diff line change
@@ -104,25 +104,29 @@ macro_rules! test_mask_api {

#[test]
fn cast() {
fn cast_impl<T: core_simd::simd::MaskElement>()
where
Mask<$type, 8>: Into<Mask<T, 8>>,
fn cast_impl<T: core_simd::simd::SimdElement>()
{
let values = [true, false, false, true, false, false, true, false];
let mask = Mask::<$type, 8>::from_array(values);

let cast_mask = mask.cast::<T>();
assert_eq!(values, cast_mask.to_array());

let into_mask: Mask<T, 8> = mask.into();
assert_eq!(values, into_mask.to_array());
}

cast_impl::<i8>();
cast_impl::<i16>();
cast_impl::<i32>();
cast_impl::<i64>();
cast_impl::<isize>();
cast_impl::<u8>();
cast_impl::<u16>();
cast_impl::<u32>();
cast_impl::<u64>();
cast_impl::<usize>();
cast_impl::<f32>();
cast_impl::<f64>();
cast_impl::<*mut u8>();
cast_impl::<*const u8>();
}

#[cfg(feature = "generic_const_exprs")]
@@ -149,13 +153,3 @@ mod mask_api {
test_mask_api! { i64 }
test_mask_api! { isize }
}

#[test]
fn convert() {
use core_simd::simd::Mask;
let values = [true, false, false, true, false, false, true, false];
assert_eq!(
Mask::<i8, 8>::from_array(values),
Mask::<i32, 8>::from_array(values).into()
);
}