]> git.lizzy.rs Git - rust.git/commitdiff
Merge commit '533f0fc81ab9ba097779fcd27c8f9ea12261fef5' into psimd
authorVadim Petrochenkov <vadim.petrochenkov@gmail.com>
Fri, 17 Dec 2021 07:10:53 +0000 (15:10 +0800)
committerVadim Petrochenkov <vadim.petrochenkov@gmail.com>
Fri, 17 Dec 2021 07:10:53 +0000 (15:10 +0800)
1  2 
library/portable-simd/crates/core_simd/src/masks/bitmask.rs
library/portable-simd/crates/core_simd/src/masks/full_masks.rs
library/portable-simd/crates/core_simd/src/mod.rs
library/portable-simd/crates/core_simd/src/select.rs

index 4c964cb52e1963851689fc06ef70c39dc5fcdb9d,0000000000000000000000000000000000000000..b4217dc87ba9c209e3e07c57fe7120dc20bcb922
mode 100644,000000..100644
--- /dev/null
@@@ -1,227 -1,0 +1,223 @@@
-             crate::intrinsics::simd_select_bitmask(
-                 self.0,
-                 Simd::splat(T::TRUE),
-                 Simd::splat(T::FALSE),
-             )
 +#![allow(unused_imports)]
 +use super::MaskElement;
 +use crate::simd::intrinsics;
 +use crate::simd::{LaneCount, Simd, SupportedLaneCount};
 +use core::marker::PhantomData;
 +
 +/// A mask where each lane is represented by a single bit.
 +#[repr(transparent)]
 +pub struct Mask<T, const LANES: usize>(
 +    <LaneCount<LANES> as SupportedLaneCount>::BitMask,
 +    PhantomData<T>,
 +)
 +where
 +    T: MaskElement,
 +    LaneCount<LANES>: SupportedLaneCount;
 +
 +impl<T, const LANES: usize> Copy for Mask<T, LANES>
 +where
 +    T: MaskElement,
 +    LaneCount<LANES>: SupportedLaneCount,
 +{
 +}
 +
 +impl<T, const LANES: usize> Clone for Mask<T, LANES>
 +where
 +    T: MaskElement,
 +    LaneCount<LANES>: SupportedLaneCount,
 +{
 +    fn clone(&self) -> Self {
 +        *self
 +    }
 +}
 +
 +impl<T, const LANES: usize> PartialEq for Mask<T, LANES>
 +where
 +    T: MaskElement,
 +    LaneCount<LANES>: SupportedLaneCount,
 +{
 +    fn eq(&self, other: &Self) -> bool {
 +        self.0.as_ref() == other.0.as_ref()
 +    }
 +}
 +
 +impl<T, const LANES: usize> PartialOrd for Mask<T, LANES>
 +where
 +    T: MaskElement,
 +    LaneCount<LANES>: SupportedLaneCount,
 +{
 +    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
 +        self.0.as_ref().partial_cmp(other.0.as_ref())
 +    }
 +}
 +
 +impl<T, const LANES: usize> Eq for Mask<T, LANES>
 +where
 +    T: MaskElement,
 +    LaneCount<LANES>: SupportedLaneCount,
 +{
 +}
 +
 +impl<T, const LANES: usize> Ord for Mask<T, LANES>
 +where
 +    T: MaskElement,
 +    LaneCount<LANES>: SupportedLaneCount,
 +{
 +    fn cmp(&self, other: &Self) -> core::cmp::Ordering {
 +        self.0.as_ref().cmp(other.0.as_ref())
 +    }
 +}
 +
 +impl<T, const LANES: usize> Mask<T, LANES>
 +where
 +    T: MaskElement,
 +    LaneCount<LANES>: SupportedLaneCount,
 +{
 +    #[inline]
 +    #[must_use = "method returns a new mask and does not mutate the original value"]
 +    pub fn splat(value: bool) -> Self {
 +        let mut mask = <LaneCount<LANES> as SupportedLaneCount>::BitMask::default();
 +        if value {
 +            mask.as_mut().fill(u8::MAX)
 +        } else {
 +            mask.as_mut().fill(u8::MIN)
 +        }
 +        if LANES % 8 > 0 {
 +            *mask.as_mut().last_mut().unwrap() &= u8::MAX >> (8 - LANES % 8);
 +        }
 +        Self(mask, PhantomData)
 +    }
 +
 +    #[inline]
 +    #[must_use = "method returns a new bool and does not mutate the original value"]
 +    pub unsafe fn test_unchecked(&self, lane: usize) -> bool {
 +        (self.0.as_ref()[lane / 8] >> (lane % 8)) & 0x1 > 0
 +    }
 +
 +    #[inline]
 +    pub unsafe fn set_unchecked(&mut self, lane: usize, value: bool) {
 +        unsafe {
 +            self.0.as_mut()[lane / 8] ^= ((value ^ self.test_unchecked(lane)) as u8) << (lane % 8)
 +        }
 +    }
 +
 +    #[inline]
 +    #[must_use = "method returns a new vector and does not mutate the original value"]
 +    pub fn to_int(self) -> Simd<T, LANES> {
 +        unsafe {
-         unsafe { Self(crate::intrinsics::simd_bitmask(value), PhantomData) }
++            intrinsics::simd_select_bitmask(self.0, Simd::splat(T::TRUE), Simd::splat(T::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 {
++        unsafe { Self(intrinsics::simd_bitmask(value), PhantomData) }
 +    }
 +
 +    #[cfg(feature = "generic_const_exprs")]
 +    #[inline]
 +    #[must_use = "method returns a new array and does not mutate the original value"]
 +    pub fn to_bitmask(self) -> [u8; LaneCount::<LANES>::BITMASK_LEN] {
 +        // Safety: these are the same type and we are laundering the generic
 +        unsafe { core::mem::transmute_copy(&self.0) }
 +    }
 +
 +    #[cfg(feature = "generic_const_exprs")]
 +    #[inline]
 +    #[must_use = "method returns a new mask and does not mutate the original value"]
 +    pub fn from_bitmask(bitmask: [u8; LaneCount::<LANES>::BITMASK_LEN]) -> Self {
 +        // Safety: these are the same type and we are laundering the generic
 +        Self(unsafe { core::mem::transmute_copy(&bitmask) }, PhantomData)
 +    }
 +
 +    #[inline]
 +    #[must_use = "method returns a new mask and does not mutate the original value"]
 +    pub fn convert<U>(self) -> Mask<U, LANES>
 +    where
 +        U: MaskElement,
 +    {
 +        unsafe { core::mem::transmute_copy(&self) }
 +    }
 +
 +    #[inline]
 +    #[must_use = "method returns a new bool and does not mutate the original value"]
 +    pub fn any(self) -> bool {
 +        self != Self::splat(false)
 +    }
 +
 +    #[inline]
 +    #[must_use = "method returns a new bool and does not mutate the original value"]
 +    pub fn all(self) -> bool {
 +        self == Self::splat(true)
 +    }
 +}
 +
 +impl<T, const LANES: usize> core::ops::BitAnd for Mask<T, LANES>
 +where
 +    T: MaskElement,
 +    LaneCount<LANES>: SupportedLaneCount,
 +    <LaneCount<LANES> as SupportedLaneCount>::BitMask: AsRef<[u8]> + AsMut<[u8]>,
 +{
 +    type Output = Self;
 +    #[inline]
 +    #[must_use = "method returns a new mask and does not mutate the original value"]
 +    fn bitand(mut self, rhs: Self) -> Self {
 +        for (l, r) in self.0.as_mut().iter_mut().zip(rhs.0.as_ref().iter()) {
 +            *l &= r;
 +        }
 +        self
 +    }
 +}
 +
 +impl<T, const LANES: usize> core::ops::BitOr for Mask<T, LANES>
 +where
 +    T: MaskElement,
 +    LaneCount<LANES>: SupportedLaneCount,
 +    <LaneCount<LANES> as SupportedLaneCount>::BitMask: AsRef<[u8]> + AsMut<[u8]>,
 +{
 +    type Output = Self;
 +    #[inline]
 +    #[must_use = "method returns a new mask and does not mutate the original value"]
 +    fn bitor(mut self, rhs: Self) -> Self {
 +        for (l, r) in self.0.as_mut().iter_mut().zip(rhs.0.as_ref().iter()) {
 +            *l |= r;
 +        }
 +        self
 +    }
 +}
 +
 +impl<T, const LANES: usize> core::ops::BitXor for Mask<T, LANES>
 +where
 +    T: MaskElement,
 +    LaneCount<LANES>: SupportedLaneCount,
 +{
 +    type Output = Self;
 +    #[inline]
 +    #[must_use = "method returns a new mask and does not mutate the original value"]
 +    fn bitxor(mut self, rhs: Self) -> Self::Output {
 +        for (l, r) in self.0.as_mut().iter_mut().zip(rhs.0.as_ref().iter()) {
 +            *l ^= r;
 +        }
 +        self
 +    }
 +}
 +
 +impl<T, const LANES: usize> core::ops::Not for Mask<T, LANES>
 +where
 +    T: MaskElement,
 +    LaneCount<LANES>: SupportedLaneCount,
 +{
 +    type Output = Self;
 +    #[inline]
 +    #[must_use = "method returns a new mask and does not mutate the original value"]
 +    fn not(mut self) -> Self::Output {
 +        for x in self.0.as_mut() {
 +            *x = !*x;
 +        }
 +        if LANES % 8 > 0 {
 +            *self.0.as_mut().last_mut().unwrap() &= u8::MAX >> (8 - LANES % 8);
 +        }
 +        self
 +    }
 +}
index 5421ccbe3d8f5ce9c5e3b7221609314990412fcf,0000000000000000000000000000000000000000..e5bb784bb910f4b40da0746f3f7ad7604d25b285
mode 100644,000000..100644
--- /dev/null
@@@ -1,228 -1,0 +1,228 @@@
-                 crate::intrinsics::simd_bitmask(self.0);
 +//! Masks that take up full SIMD vector registers.
 +
 +use super::MaskElement;
 +use crate::simd::intrinsics;
 +use crate::simd::{LaneCount, Simd, SupportedLaneCount};
 +
 +#[repr(transparent)]
 +pub struct Mask<T, const LANES: usize>(Simd<T, LANES>)
 +where
 +    T: MaskElement,
 +    LaneCount<LANES>: SupportedLaneCount;
 +
 +impl<T, const LANES: usize> Copy for Mask<T, LANES>
 +where
 +    T: MaskElement,
 +    LaneCount<LANES>: SupportedLaneCount,
 +{
 +}
 +
 +impl<T, const LANES: usize> Clone for Mask<T, LANES>
 +where
 +    T: MaskElement,
 +    LaneCount<LANES>: SupportedLaneCount,
 +{
 +    #[inline]
 +    #[must_use = "method returns a new mask and does not mutate the original value"]
 +    fn clone(&self) -> Self {
 +        *self
 +    }
 +}
 +
 +impl<T, const LANES: usize> PartialEq for Mask<T, LANES>
 +where
 +    T: MaskElement + PartialEq,
 +    LaneCount<LANES>: SupportedLaneCount,
 +{
 +    fn eq(&self, other: &Self) -> bool {
 +        self.0.eq(&other.0)
 +    }
 +}
 +
 +impl<T, const LANES: usize> PartialOrd for Mask<T, LANES>
 +where
 +    T: MaskElement + PartialOrd,
 +    LaneCount<LANES>: SupportedLaneCount,
 +{
 +    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
 +        self.0.partial_cmp(&other.0)
 +    }
 +}
 +
 +impl<T, const LANES: usize> Eq for Mask<T, LANES>
 +where
 +    T: MaskElement + Eq,
 +    LaneCount<LANES>: SupportedLaneCount,
 +{
 +}
 +
 +impl<T, const LANES: usize> Ord for Mask<T, LANES>
 +where
 +    T: MaskElement + Ord,
 +    LaneCount<LANES>: SupportedLaneCount,
 +{
 +    fn cmp(&self, other: &Self) -> core::cmp::Ordering {
 +        self.0.cmp(&other.0)
 +    }
 +}
 +
 +impl<T, const LANES: usize> Mask<T, LANES>
 +where
 +    T: MaskElement,
 +    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 }))
 +    }
 +
 +    #[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)
 +    }
 +
 +    #[inline]
 +    pub unsafe fn set_unchecked(&mut self, lane: usize, value: bool) {
 +        self.0[lane] = if value { T::TRUE } else { T::FALSE }
 +    }
 +
 +    #[inline]
 +    #[must_use = "method returns a new vector and does not mutate the original value"]
 +    pub fn to_int(self) -> Simd<T, 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 {
 +        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>
 +    where
 +        U: MaskElement,
 +    {
 +        unsafe { Mask(intrinsics::simd_cast(self.0)) }
 +    }
 +
 +    #[cfg(feature = "generic_const_exprs")]
 +    #[inline]
 +    #[must_use = "method returns a new array and does not mutate the original value"]
 +    pub fn to_bitmask(self) -> [u8; LaneCount::<LANES>::BITMASK_LEN] {
 +        unsafe {
 +            let mut bitmask: [u8; LaneCount::<LANES>::BITMASK_LEN] =
-             Self::from_int_unchecked(crate::intrinsics::simd_select_bitmask(
++                intrinsics::simd_bitmask(self.0);
 +
 +            // There is a bug where LLVM appears to implement this operation with the wrong
 +            // bit order.
 +            // TODO fix this in a better way
 +            if cfg!(target_endian = "big") {
 +                for x in bitmask.as_mut() {
 +                    *x = x.reverse_bits();
 +                }
 +            }
 +
 +            bitmask
 +        }
 +    }
 +
 +    #[cfg(feature = "generic_const_exprs")]
 +    #[inline]
 +    #[must_use = "method returns a new mask and does not mutate the original value"]
 +    pub fn from_bitmask(mut bitmask: [u8; LaneCount::<LANES>::BITMASK_LEN]) -> Self {
 +        unsafe {
 +            // There is a bug where LLVM appears to implement this operation with the wrong
 +            // bit order.
 +            // TODO fix this in a better way
 +            if cfg!(target_endian = "big") {
 +                for x in bitmask.as_mut() {
 +                    *x = x.reverse_bits();
 +                }
 +            }
 +
++            Self::from_int_unchecked(intrinsics::simd_select_bitmask(
 +                bitmask,
 +                Self::splat(true).to_int(),
 +                Self::splat(false).to_int(),
 +            ))
 +        }
 +    }
 +
 +    #[inline]
 +    #[must_use = "method returns a new bool and does not mutate the original value"]
 +    pub fn any(self) -> bool {
 +        unsafe { intrinsics::simd_reduce_any(self.to_int()) }
 +    }
 +
 +    #[inline]
 +    #[must_use = "method returns a new vector and does not mutate the original value"]
 +    pub fn all(self) -> bool {
 +        unsafe { intrinsics::simd_reduce_all(self.to_int()) }
 +    }
 +}
 +
 +impl<T, const LANES: usize> core::convert::From<Mask<T, LANES>> for Simd<T, LANES>
 +where
 +    T: MaskElement,
 +    LaneCount<LANES>: SupportedLaneCount,
 +{
 +    fn from(value: Mask<T, LANES>) -> Self {
 +        value.0
 +    }
 +}
 +
 +impl<T, const LANES: usize> core::ops::BitAnd for Mask<T, LANES>
 +where
 +    T: MaskElement,
 +    LaneCount<LANES>: SupportedLaneCount,
 +{
 +    type Output = Self;
 +    #[inline]
 +    #[must_use = "method returns a new mask and does not mutate the original value"]
 +    fn bitand(self, rhs: Self) -> Self {
 +        unsafe { Self(intrinsics::simd_and(self.0, rhs.0)) }
 +    }
 +}
 +
 +impl<T, const LANES: usize> core::ops::BitOr for Mask<T, LANES>
 +where
 +    T: MaskElement,
 +    LaneCount<LANES>: SupportedLaneCount,
 +{
 +    type Output = Self;
 +    #[inline]
 +    #[must_use = "method returns a new mask and does not mutate the original value"]
 +    fn bitor(self, rhs: Self) -> Self {
 +        unsafe { Self(intrinsics::simd_or(self.0, rhs.0)) }
 +    }
 +}
 +
 +impl<T, const LANES: usize> core::ops::BitXor for Mask<T, LANES>
 +where
 +    T: MaskElement,
 +    LaneCount<LANES>: SupportedLaneCount,
 +{
 +    type Output = Self;
 +    #[inline]
 +    #[must_use = "method returns a new mask and does not mutate the original value"]
 +    fn bitxor(self, rhs: Self) -> Self {
 +        unsafe { Self(intrinsics::simd_xor(self.0, rhs.0)) }
 +    }
 +}
 +
 +impl<T, const LANES: usize> core::ops::Not for Mask<T, LANES>
 +where
 +    T: MaskElement,
 +    LaneCount<LANES>: SupportedLaneCount,
 +{
 +    type Output = Self;
 +    #[inline]
 +    #[must_use = "method returns a new mask and does not mutate the original value"]
 +    fn not(self) -> Self::Output {
 +        Self::splat(true) ^ self
 +    }
 +}
index ec874a22389d4e789281a2b15e2afe893b341de0,0000000000000000000000000000000000000000..85026265956a2092545c00a1e3ffa24e543aa672
mode 100644,000000..100644
--- /dev/null
@@@ -1,33 -1,0 +1,32 @@@
-     pub use crate::core_simd::select::Select;
 +#[macro_use]
 +mod reduction;
 +
 +#[macro_use]
 +mod swizzle;
 +
 +pub(crate) mod intrinsics;
 +
 +#[cfg(feature = "generic_const_exprs")]
 +mod to_bytes;
 +
 +mod comparisons;
 +mod fmt;
 +mod iter;
 +mod lane_count;
 +mod masks;
 +mod math;
 +mod ops;
 +mod round;
 +mod select;
 +mod vector;
 +mod vendor;
 +
 +#[doc = include_str!("core_simd_docs.md")]
 +pub mod simd {
 +    pub(crate) use crate::core_simd::intrinsics;
 +
 +    pub use crate::core_simd::lane_count::{LaneCount, SupportedLaneCount};
 +    pub use crate::core_simd::masks::*;
 +    pub use crate::core_simd::swizzle::*;
 +    pub use crate::core_simd::vector::*;
 +}
index 5d696ebf76ec299bccb57673f6a13c869f8ad09f,0000000000000000000000000000000000000000..8d521057fbd3ed7a9da2bc540af546f7d2cf9ee2
mode 100644,000000..100644
--- /dev/null
@@@ -1,89 -1,0 +1,57 @@@
- mod sealed {
-     pub trait Sealed<Mask> {
-         fn select(mask: Mask, true_values: Self, false_values: Self) -> Self;
-     }
- }
- use sealed::Sealed;
- /// Supporting trait for vector `select` function
- pub trait Select<Mask>: Sealed<Mask> {}
- impl<T, const LANES: usize> Sealed<Mask<T::Mask, LANES>> for Simd<T, LANES>
- where
-     T: SimdElement,
-     LaneCount<LANES>: SupportedLaneCount,
- {
-     #[inline]
-     #[must_use = "method returns a new vector and does not mutate the original inputs"]
-     fn select(mask: Mask<T::Mask, LANES>, true_values: Self, false_values: Self) -> Self {
-         unsafe { intrinsics::simd_select(mask.to_int(), true_values, false_values) }
-     }
- }
- impl<T, const LANES: usize> Select<Mask<T::Mask, LANES>> for Simd<T, LANES>
- where
-     T: SimdElement,
-     LaneCount<LANES>: SupportedLaneCount,
- {
- }
- impl<T, const LANES: usize> Sealed<Self> for Mask<T, LANES>
- where
-     T: MaskElement,
-     LaneCount<LANES>: SupportedLaneCount,
- {
-     #[inline]
-     #[must_use = "method returns a new vector and does not mutate the original inputs"]
-     fn select(mask: Self, true_values: Self, false_values: Self) -> Self {
-         mask & true_values | !mask & false_values
-     }
- }
- impl<T, const LANES: usize> Select<Self> for Mask<T, LANES>
- where
-     T: MaskElement,
-     LaneCount<LANES>: SupportedLaneCount,
- {
- }
 +use crate::simd::intrinsics;
 +use crate::simd::{LaneCount, Mask, MaskElement, Simd, SimdElement, SupportedLaneCount};
 +
-     /// `select` can also be used on masks:
 +impl<T, const LANES: usize> Mask<T, LANES>
 +where
 +    T: MaskElement,
 +    LaneCount<LANES>: SupportedLaneCount,
 +{
 +    /// Choose lanes from two vectors.
 +    ///
 +    /// For each lane in the mask, choose the corresponding lane from `true_values` if
 +    /// that lane mask is true, and `false_values` if that lane mask is false.
 +    ///
 +    /// ```
 +    /// # #![feature(portable_simd)]
 +    /// # #[cfg(feature = "std")] use core_simd::{Simd, Mask};
 +    /// # #[cfg(not(feature = "std"))] use core::simd::{Simd, Mask};
 +    /// let a = Simd::from_array([0, 1, 2, 3]);
 +    /// let b = Simd::from_array([4, 5, 6, 7]);
 +    /// let mask = Mask::from_array([true, false, false, true]);
 +    /// let c = mask.select(a, b);
 +    /// assert_eq!(c.to_array(), [0, 5, 6, 3]);
 +    /// ```
++    #[inline]
++    #[must_use = "method returns a new vector and does not mutate the original inputs"]
++    pub fn select<U>(
++        self,
++        true_values: Simd<U, LANES>,
++        false_values: Simd<U, LANES>,
++    ) -> Simd<U, LANES>
++    where
++        U: SimdElement<Mask = T>,
++    {
++        unsafe { intrinsics::simd_select(self.to_int(), true_values, false_values) }
++    }
++
++    /// Choose lanes from two masks.
++    ///
++    /// For each lane in the mask, choose the corresponding lane from `true_values` if
++    /// that lane mask is true, and `false_values` if that lane mask is false.
 +    ///
-     /// let c = mask.select(a, b);
 +    /// ```
 +    /// # #![feature(portable_simd)]
 +    /// # #[cfg(feature = "std")] use core_simd::Mask;
 +    /// # #[cfg(not(feature = "std"))] use core::simd::Mask;
 +    /// let a = Mask::<i32, 4>::from_array([true, true, false, false]);
 +    /// let b = Mask::<i32, 4>::from_array([false, false, true, true]);
 +    /// let mask = Mask::<i32, 4>::from_array([true, false, false, true]);
-     #[must_use = "method returns a new vector and does not mutate the original inputs"]
-     pub fn select<S: Select<Self>>(self, true_values: S, false_values: S) -> S {
-         S::select(self, true_values, false_values)
++    /// let c = mask.select_mask(a, b);
 +    /// assert_eq!(c.to_array(), [true, false, true, false]);
 +    /// ```
 +    #[inline]
++    #[must_use = "method returns a new mask and does not mutate the original inputs"]
++    pub fn select_mask(self, true_values: Self, false_values: Self) -> Self {
++        self & true_values | !self & false_values
 +    }
 +}