Move integer functions to traits.
This commit is contained in:
parent
9718639d61
commit
376957ad8c
5
crates/core_simd/src/elements.rs
Normal file
5
crates/core_simd/src/elements.rs
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
mod int;
|
||||||
|
mod uint;
|
||||||
|
|
||||||
|
pub use int::*;
|
||||||
|
pub use uint::*;
|
273
crates/core_simd/src/elements/int.rs
Normal file
273
crates/core_simd/src/elements/int.rs
Normal file
@ -0,0 +1,273 @@
|
|||||||
|
use crate::simd::{
|
||||||
|
intrinsics, LaneCount, Mask, Simd, SimdElement, SimdPartialOrd, SupportedLaneCount,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Operations on SIMD vectors of signed integers.
|
||||||
|
pub trait SimdInt: Sized {
|
||||||
|
/// Mask type used for manipulating this SIMD vector type.
|
||||||
|
type Mask;
|
||||||
|
|
||||||
|
/// Scalar type contained by this SIMD vector type.
|
||||||
|
type Scalar;
|
||||||
|
|
||||||
|
/// Lanewise saturating add.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
/// ```
|
||||||
|
/// # #![feature(portable_simd)]
|
||||||
|
/// # use core::simd::Simd;
|
||||||
|
/// use core::i32::{MIN, MAX};
|
||||||
|
/// let x = Simd::from_array([MIN, 0, 1, MAX]);
|
||||||
|
/// let max = Simd::splat(MAX);
|
||||||
|
/// let unsat = x + max;
|
||||||
|
/// let sat = x.saturating_add(max);
|
||||||
|
/// assert_eq!(unsat, Simd::from_array([-1, MAX, MIN, -2]));
|
||||||
|
/// assert_eq!(sat, Simd::from_array([-1, MAX, MAX, MAX]));
|
||||||
|
/// ```
|
||||||
|
fn saturating_add(self, second: Self) -> Self;
|
||||||
|
|
||||||
|
/// Lanewise saturating subtract.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
/// ```
|
||||||
|
/// # #![feature(portable_simd)]
|
||||||
|
/// # use core::simd::Simd;
|
||||||
|
/// use core::i32::{MIN, MAX};
|
||||||
|
/// let x = Simd::from_array([MIN, -2, -1, MAX]);
|
||||||
|
/// let max = Simd::splat(MAX);
|
||||||
|
/// let unsat = x - max;
|
||||||
|
/// let sat = x.saturating_sub(max);
|
||||||
|
/// assert_eq!(unsat, Simd::from_array([1, MAX, MIN, 0]));
|
||||||
|
/// assert_eq!(sat, Simd::from_array([MIN, MIN, MIN, 0]));
|
||||||
|
fn saturating_sub(self, second: Self) -> Self;
|
||||||
|
|
||||||
|
/// Lanewise absolute value, implemented in Rust.
|
||||||
|
/// Every lane becomes its absolute value.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
/// ```
|
||||||
|
/// # #![feature(portable_simd)]
|
||||||
|
/// # use core::simd::Simd;
|
||||||
|
/// use core::i32::{MIN, MAX};
|
||||||
|
/// let xs = Simd::from_array([MIN, MIN +1, -5, 0]);
|
||||||
|
/// assert_eq!(xs.abs(), Simd::from_array([MIN, MAX, 5, 0]));
|
||||||
|
/// ```
|
||||||
|
fn abs(self) -> Self;
|
||||||
|
|
||||||
|
/// Lanewise saturating absolute value, implemented in Rust.
|
||||||
|
/// As abs(), except the MIN value becomes MAX instead of itself.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
/// ```
|
||||||
|
/// # #![feature(portable_simd)]
|
||||||
|
/// # use core::simd::Simd;
|
||||||
|
/// use core::i32::{MIN, MAX};
|
||||||
|
/// let xs = Simd::from_array([MIN, -2, 0, 3]);
|
||||||
|
/// let unsat = xs.abs();
|
||||||
|
/// let sat = xs.saturating_abs();
|
||||||
|
/// assert_eq!(unsat, Simd::from_array([MIN, 2, 0, 3]));
|
||||||
|
/// assert_eq!(sat, Simd::from_array([MAX, 2, 0, 3]));
|
||||||
|
/// ```
|
||||||
|
fn saturating_abs(self) -> Self;
|
||||||
|
|
||||||
|
/// Lanewise saturating negation, implemented in Rust.
|
||||||
|
/// As neg(), except the MIN value becomes MAX instead of itself.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
/// ```
|
||||||
|
/// # #![feature(portable_simd)]
|
||||||
|
/// # use core::simd::Simd;
|
||||||
|
/// use core::i32::{MIN, MAX};
|
||||||
|
/// let x = Simd::from_array([MIN, -2, 3, MAX]);
|
||||||
|
/// let unsat = -x;
|
||||||
|
/// let sat = x.saturating_neg();
|
||||||
|
/// assert_eq!(unsat, Simd::from_array([MIN, 2, -3, MIN + 1]));
|
||||||
|
/// assert_eq!(sat, Simd::from_array([MAX, 2, -3, MIN + 1]));
|
||||||
|
/// ```
|
||||||
|
fn saturating_neg(self) -> Self;
|
||||||
|
|
||||||
|
/// Returns true for each positive lane and false if it is zero or negative.
|
||||||
|
fn is_positive(self) -> Self::Mask;
|
||||||
|
|
||||||
|
/// Returns true for each negative lane and false if it is zero or positive.
|
||||||
|
fn is_negative(self) -> Self::Mask;
|
||||||
|
|
||||||
|
/// Returns numbers representing the sign of each lane.
|
||||||
|
/// * `0` if the number is zero
|
||||||
|
/// * `1` if the number is positive
|
||||||
|
/// * `-1` if the number is negative
|
||||||
|
fn signum(self) -> Self;
|
||||||
|
|
||||||
|
/// Returns the sum of the lanes of the vector, with wrapping addition.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # #![feature(portable_simd)]
|
||||||
|
/// # use core::simd::i32x4;
|
||||||
|
/// let v = i32x4::from_array([1, 2, 3, 4]);
|
||||||
|
/// assert_eq!(v.reduce_sum(), 10);
|
||||||
|
///
|
||||||
|
/// // SIMD integer addition is always wrapping
|
||||||
|
/// let v = i32x4::from_array([i32::MAX, 1, 0, 0]);
|
||||||
|
/// assert_eq!(v.reduce_sum(), i32::MIN);
|
||||||
|
/// ```
|
||||||
|
fn reduce_sum(self) -> Self::Scalar;
|
||||||
|
|
||||||
|
/// Returns the product of the lanes of the vector, with wrapping multiplication.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # #![feature(portable_simd)]
|
||||||
|
/// # use core::simd::i32x4;
|
||||||
|
/// let v = i32x4::from_array([1, 2, 3, 4]);
|
||||||
|
/// assert_eq!(v.reduce_product(), 24);
|
||||||
|
///
|
||||||
|
/// // SIMD integer multiplication is always wrapping
|
||||||
|
/// let v = i32x4::from_array([i32::MAX, 2, 1, 1]);
|
||||||
|
/// assert!(v.reduce_product() < i32::MAX);
|
||||||
|
/// ```
|
||||||
|
fn reduce_product(self) -> Self::Scalar;
|
||||||
|
|
||||||
|
/// Returns the maximum lane in the vector.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # #![feature(portable_simd)]
|
||||||
|
/// # use core::simd::i32x4;
|
||||||
|
/// let v = i32x4::from_array([1, 2, 3, 4]);
|
||||||
|
/// assert_eq!(v.reduce_max(), 4);
|
||||||
|
/// ```
|
||||||
|
fn reduce_max(self) -> Self::Scalar;
|
||||||
|
|
||||||
|
/// Returns the minimum lane in the vector.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # #![feature(portable_simd)]
|
||||||
|
/// # use core::simd::i32x4;
|
||||||
|
/// let v = i32x4::from_array([1, 2, 3, 4]);
|
||||||
|
/// assert_eq!(v.reduce_min(), 1);
|
||||||
|
/// ```
|
||||||
|
fn reduce_min(self) -> Self::Scalar;
|
||||||
|
|
||||||
|
/// Returns the cumulative bitwise "and" across the lanes of the vector.
|
||||||
|
fn reduce_and(self) -> Self::Scalar;
|
||||||
|
|
||||||
|
/// Returns the cumulative bitwise "or" across the lanes of the vector.
|
||||||
|
fn reduce_or(self) -> Self::Scalar;
|
||||||
|
|
||||||
|
/// Returns the cumulative bitwise "xor" across the lanes of the vector.
|
||||||
|
fn reduce_xor(self) -> Self::Scalar;
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! impl_trait {
|
||||||
|
{ $($ty:ty),* } => {
|
||||||
|
$(
|
||||||
|
impl<const LANES: usize> SimdInt for Simd<$ty, LANES>
|
||||||
|
where
|
||||||
|
LaneCount<LANES>: SupportedLaneCount,
|
||||||
|
{
|
||||||
|
type Mask = Mask<<$ty as SimdElement>::Mask, LANES>;
|
||||||
|
type Scalar = $ty;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn saturating_add(self, second: Self) -> Self {
|
||||||
|
// Safety: `self` is a vector
|
||||||
|
unsafe { intrinsics::simd_saturating_add(self, second) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn saturating_sub(self, second: Self) -> Self {
|
||||||
|
// Safety: `self` is a vector
|
||||||
|
unsafe { intrinsics::simd_saturating_sub(self, second) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn abs(self) -> Self {
|
||||||
|
const SHR: $ty = <$ty>::BITS as $ty - 1;
|
||||||
|
let m = self >> Simd::splat(SHR);
|
||||||
|
(self^m) - m
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn saturating_abs(self) -> Self {
|
||||||
|
// arith shift for -1 or 0 mask based on sign bit, giving 2s complement
|
||||||
|
const SHR: $ty = <$ty>::BITS as $ty - 1;
|
||||||
|
let m = self >> Simd::splat(SHR);
|
||||||
|
(self^m).saturating_sub(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn saturating_neg(self) -> Self {
|
||||||
|
Self::splat(0).saturating_sub(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn is_positive(self) -> Self::Mask {
|
||||||
|
self.simd_gt(Self::splat(0))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn is_negative(self) -> Self::Mask {
|
||||||
|
self.simd_lt(Self::splat(0))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn signum(self) -> Self {
|
||||||
|
self.is_positive().select(
|
||||||
|
Self::splat(1),
|
||||||
|
self.is_negative().select(Self::splat(-1), Self::splat(0))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn reduce_sum(self) -> Self::Scalar {
|
||||||
|
// Safety: `self` is an integer vector
|
||||||
|
unsafe { intrinsics::simd_reduce_add_ordered(self, 0) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn reduce_product(self) -> Self::Scalar {
|
||||||
|
// Safety: `self` is an integer vector
|
||||||
|
unsafe { intrinsics::simd_reduce_mul_ordered(self, 1) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn reduce_max(self) -> Self::Scalar {
|
||||||
|
// Safety: `self` is an integer vector
|
||||||
|
unsafe { intrinsics::simd_reduce_max(self) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn reduce_min(self) -> Self::Scalar {
|
||||||
|
// Safety: `self` is an integer vector
|
||||||
|
unsafe { intrinsics::simd_reduce_min(self) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn reduce_and(self) -> Self::Scalar {
|
||||||
|
// Safety: `self` is an integer vector
|
||||||
|
unsafe { intrinsics::simd_reduce_and(self) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn reduce_or(self) -> Self::Scalar {
|
||||||
|
// Safety: `self` is an integer vector
|
||||||
|
unsafe { intrinsics::simd_reduce_or(self) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn reduce_xor(self) -> Self::Scalar {
|
||||||
|
// Safety: `self` is an integer vector
|
||||||
|
unsafe { intrinsics::simd_reduce_xor(self) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_trait! { i8, i16, i32, i64, isize }
|
128
crates/core_simd/src/elements/uint.rs
Normal file
128
crates/core_simd/src/elements/uint.rs
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
use crate::simd::{intrinsics, LaneCount, Simd, SupportedLaneCount};
|
||||||
|
|
||||||
|
/// Operations on SIMD vectors of unsigned integers.
|
||||||
|
pub trait SimdUint: Sized {
|
||||||
|
/// Scalar type contained by this SIMD vector type.
|
||||||
|
type Scalar;
|
||||||
|
|
||||||
|
/// Lanewise saturating add.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
/// ```
|
||||||
|
/// # #![feature(portable_simd)]
|
||||||
|
/// # use core::simd::Simd;
|
||||||
|
/// use core::u32::MAX;
|
||||||
|
/// let x = Simd::from_array([2, 1, 0, MAX]);
|
||||||
|
/// let max = Simd::splat(MAX);
|
||||||
|
/// let unsat = x + max;
|
||||||
|
/// let sat = x.saturating_add(max);
|
||||||
|
/// assert_eq!(unsat, Simd::from_array([1, 0, MAX, MAX - 1]));
|
||||||
|
/// assert_eq!(sat, max);
|
||||||
|
/// ```
|
||||||
|
fn saturating_add(self, second: Self) -> Self;
|
||||||
|
|
||||||
|
/// Lanewise saturating subtract.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
/// ```
|
||||||
|
/// # #![feature(portable_simd)]
|
||||||
|
/// # use core::simd::Simd;
|
||||||
|
/// use core::u32::MAX;
|
||||||
|
/// let x = Simd::from_array([2, 1, 0, MAX]);
|
||||||
|
/// let max = Simd::splat(MAX);
|
||||||
|
/// let unsat = x - max;
|
||||||
|
/// let sat = x.saturating_sub(max);
|
||||||
|
/// assert_eq!(unsat, Simd::from_array([3, 2, 1, 0]));
|
||||||
|
/// assert_eq!(sat, Simd::splat(0));
|
||||||
|
fn saturating_sub(self, second: Self) -> Self;
|
||||||
|
|
||||||
|
/// Returns the sum of the lanes of the vector, with wrapping addition.
|
||||||
|
fn reduce_sum(self) -> Self::Scalar;
|
||||||
|
|
||||||
|
/// Returns the product of the lanes of the vector, with wrapping multiplication.
|
||||||
|
fn reduce_product(self) -> Self::Scalar;
|
||||||
|
|
||||||
|
/// Returns the maximum lane in the vector.
|
||||||
|
fn reduce_max(self) -> Self::Scalar;
|
||||||
|
|
||||||
|
/// Returns the minimum lane in the vector.
|
||||||
|
fn reduce_min(self) -> Self::Scalar;
|
||||||
|
|
||||||
|
/// Returns the cumulative bitwise "and" across the lanes of the vector.
|
||||||
|
fn reduce_and(self) -> Self::Scalar;
|
||||||
|
|
||||||
|
/// Returns the cumulative bitwise "or" across the lanes of the vector.
|
||||||
|
fn reduce_or(self) -> Self::Scalar;
|
||||||
|
|
||||||
|
/// Returns the cumulative bitwise "xor" across the lanes of the vector.
|
||||||
|
fn reduce_xor(self) -> Self::Scalar;
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! impl_trait {
|
||||||
|
{ $($ty:ty),* } => {
|
||||||
|
$(
|
||||||
|
impl<const LANES: usize> SimdUint for Simd<$ty, LANES>
|
||||||
|
where
|
||||||
|
LaneCount<LANES>: SupportedLaneCount,
|
||||||
|
{
|
||||||
|
type Scalar = $ty;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn saturating_add(self, second: Self) -> Self {
|
||||||
|
// Safety: `self` is a vector
|
||||||
|
unsafe { intrinsics::simd_saturating_add(self, second) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn saturating_sub(self, second: Self) -> Self {
|
||||||
|
// Safety: `self` is a vector
|
||||||
|
unsafe { intrinsics::simd_saturating_sub(self, second) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn reduce_sum(self) -> Self::Scalar {
|
||||||
|
// Safety: `self` is an integer vector
|
||||||
|
unsafe { intrinsics::simd_reduce_add_ordered(self, 0) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn reduce_product(self) -> Self::Scalar {
|
||||||
|
// Safety: `self` is an integer vector
|
||||||
|
unsafe { intrinsics::simd_reduce_mul_ordered(self, 1) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn reduce_max(self) -> Self::Scalar {
|
||||||
|
// Safety: `self` is an integer vector
|
||||||
|
unsafe { intrinsics::simd_reduce_max(self) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn reduce_min(self) -> Self::Scalar {
|
||||||
|
// Safety: `self` is an integer vector
|
||||||
|
unsafe { intrinsics::simd_reduce_min(self) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn reduce_and(self) -> Self::Scalar {
|
||||||
|
// Safety: `self` is an integer vector
|
||||||
|
unsafe { intrinsics::simd_reduce_and(self) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn reduce_or(self) -> Self::Scalar {
|
||||||
|
// Safety: `self` is an integer vector
|
||||||
|
unsafe { intrinsics::simd_reduce_or(self) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn reduce_xor(self) -> Self::Scalar {
|
||||||
|
// Safety: `self` is an integer vector
|
||||||
|
unsafe { intrinsics::simd_reduce_xor(self) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_trait! { u8, u16, u32, u64, usize }
|
@ -1,156 +0,0 @@
|
|||||||
use crate::simd::intrinsics::{simd_saturating_add, simd_saturating_sub};
|
|
||||||
use crate::simd::{LaneCount, Simd, SupportedLaneCount};
|
|
||||||
|
|
||||||
macro_rules! impl_uint_arith {
|
|
||||||
($($ty:ty),+) => {
|
|
||||||
$( impl<const LANES: usize> Simd<$ty, LANES> where LaneCount<LANES>: SupportedLaneCount {
|
|
||||||
|
|
||||||
/// Lanewise saturating add.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
/// ```
|
|
||||||
/// # #![feature(portable_simd)]
|
|
||||||
/// # use core::simd::Simd;
|
|
||||||
#[doc = concat!("# use core::", stringify!($ty), "::MAX;")]
|
|
||||||
/// let x = Simd::from_array([2, 1, 0, MAX]);
|
|
||||||
/// let max = Simd::splat(MAX);
|
|
||||||
/// let unsat = x + max;
|
|
||||||
/// let sat = x.saturating_add(max);
|
|
||||||
/// assert_eq!(unsat, Simd::from_array([1, 0, MAX, MAX - 1]));
|
|
||||||
/// assert_eq!(sat, max);
|
|
||||||
/// ```
|
|
||||||
#[inline]
|
|
||||||
pub fn saturating_add(self, second: Self) -> Self {
|
|
||||||
// Safety: `self` is a vector
|
|
||||||
unsafe { simd_saturating_add(self, second) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Lanewise saturating subtract.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
/// ```
|
|
||||||
/// # #![feature(portable_simd)]
|
|
||||||
/// # use core::simd::Simd;
|
|
||||||
#[doc = concat!("# use core::", stringify!($ty), "::MAX;")]
|
|
||||||
/// let x = Simd::from_array([2, 1, 0, MAX]);
|
|
||||||
/// let max = Simd::splat(MAX);
|
|
||||||
/// let unsat = x - max;
|
|
||||||
/// let sat = x.saturating_sub(max);
|
|
||||||
/// assert_eq!(unsat, Simd::from_array([3, 2, 1, 0]));
|
|
||||||
/// assert_eq!(sat, Simd::splat(0));
|
|
||||||
#[inline]
|
|
||||||
pub fn saturating_sub(self, second: Self) -> Self {
|
|
||||||
// Safety: `self` is a vector
|
|
||||||
unsafe { simd_saturating_sub(self, second) }
|
|
||||||
}
|
|
||||||
})+
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! impl_int_arith {
|
|
||||||
($($ty:ty),+) => {
|
|
||||||
$( impl<const LANES: usize> Simd<$ty, LANES> where LaneCount<LANES>: SupportedLaneCount {
|
|
||||||
|
|
||||||
/// Lanewise saturating add.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
/// ```
|
|
||||||
/// # #![feature(portable_simd)]
|
|
||||||
/// # use core::simd::Simd;
|
|
||||||
#[doc = concat!("# use core::", stringify!($ty), "::{MIN, MAX};")]
|
|
||||||
/// let x = Simd::from_array([MIN, 0, 1, MAX]);
|
|
||||||
/// let max = Simd::splat(MAX);
|
|
||||||
/// let unsat = x + max;
|
|
||||||
/// let sat = x.saturating_add(max);
|
|
||||||
/// assert_eq!(unsat, Simd::from_array([-1, MAX, MIN, -2]));
|
|
||||||
/// assert_eq!(sat, Simd::from_array([-1, MAX, MAX, MAX]));
|
|
||||||
/// ```
|
|
||||||
#[inline]
|
|
||||||
pub fn saturating_add(self, second: Self) -> Self {
|
|
||||||
// Safety: `self` is a vector
|
|
||||||
unsafe { simd_saturating_add(self, second) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Lanewise saturating subtract.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
/// ```
|
|
||||||
/// # #![feature(portable_simd)]
|
|
||||||
/// # use core::simd::Simd;
|
|
||||||
#[doc = concat!("# use core::", stringify!($ty), "::{MIN, MAX};")]
|
|
||||||
/// let x = Simd::from_array([MIN, -2, -1, MAX]);
|
|
||||||
/// let max = Simd::splat(MAX);
|
|
||||||
/// let unsat = x - max;
|
|
||||||
/// let sat = x.saturating_sub(max);
|
|
||||||
/// assert_eq!(unsat, Simd::from_array([1, MAX, MIN, 0]));
|
|
||||||
/// assert_eq!(sat, Simd::from_array([MIN, MIN, MIN, 0]));
|
|
||||||
#[inline]
|
|
||||||
pub fn saturating_sub(self, second: Self) -> Self {
|
|
||||||
// Safety: `self` is a vector
|
|
||||||
unsafe { simd_saturating_sub(self, second) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Lanewise absolute value, implemented in Rust.
|
|
||||||
/// Every lane becomes its absolute value.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
/// ```
|
|
||||||
/// # #![feature(portable_simd)]
|
|
||||||
/// # use core::simd::Simd;
|
|
||||||
#[doc = concat!("# use core::", stringify!($ty), "::{MIN, MAX};")]
|
|
||||||
/// let xs = Simd::from_array([MIN, MIN +1, -5, 0]);
|
|
||||||
/// assert_eq!(xs.abs(), Simd::from_array([MIN, MAX, 5, 0]));
|
|
||||||
/// ```
|
|
||||||
#[inline]
|
|
||||||
pub fn abs(self) -> Self {
|
|
||||||
const SHR: $ty = <$ty>::BITS as $ty - 1;
|
|
||||||
let m = self >> Simd::splat(SHR);
|
|
||||||
(self^m) - m
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Lanewise saturating absolute value, implemented in Rust.
|
|
||||||
/// As abs(), except the MIN value becomes MAX instead of itself.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
/// ```
|
|
||||||
/// # #![feature(portable_simd)]
|
|
||||||
/// # use core::simd::Simd;
|
|
||||||
#[doc = concat!("# use core::", stringify!($ty), "::{MIN, MAX};")]
|
|
||||||
/// let xs = Simd::from_array([MIN, -2, 0, 3]);
|
|
||||||
/// let unsat = xs.abs();
|
|
||||||
/// let sat = xs.saturating_abs();
|
|
||||||
/// assert_eq!(unsat, Simd::from_array([MIN, 2, 0, 3]));
|
|
||||||
/// assert_eq!(sat, Simd::from_array([MAX, 2, 0, 3]));
|
|
||||||
/// ```
|
|
||||||
#[inline]
|
|
||||||
pub fn saturating_abs(self) -> Self {
|
|
||||||
// arith shift for -1 or 0 mask based on sign bit, giving 2s complement
|
|
||||||
const SHR: $ty = <$ty>::BITS as $ty - 1;
|
|
||||||
let m = self >> Simd::splat(SHR);
|
|
||||||
(self^m).saturating_sub(m)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Lanewise saturating negation, implemented in Rust.
|
|
||||||
/// As neg(), except the MIN value becomes MAX instead of itself.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
/// ```
|
|
||||||
/// # #![feature(portable_simd)]
|
|
||||||
/// # use core::simd::Simd;
|
|
||||||
#[doc = concat!("# use core::", stringify!($ty), "::{MIN, MAX};")]
|
|
||||||
/// let x = Simd::from_array([MIN, -2, 3, MAX]);
|
|
||||||
/// let unsat = -x;
|
|
||||||
/// let sat = x.saturating_neg();
|
|
||||||
/// assert_eq!(unsat, Simd::from_array([MIN, 2, -3, MIN + 1]));
|
|
||||||
/// assert_eq!(sat, Simd::from_array([MAX, 2, -3, MIN + 1]));
|
|
||||||
/// ```
|
|
||||||
#[inline]
|
|
||||||
pub fn saturating_neg(self) -> Self {
|
|
||||||
Self::splat(0).saturating_sub(self)
|
|
||||||
}
|
|
||||||
})+
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl_uint_arith! { u8, u16, u32, u64, usize }
|
|
||||||
impl_int_arith! { i8, i16, i32, i64, isize }
|
|
@ -9,12 +9,12 @@ pub(crate) mod intrinsics;
|
|||||||
#[cfg(feature = "generic_const_exprs")]
|
#[cfg(feature = "generic_const_exprs")]
|
||||||
mod to_bytes;
|
mod to_bytes;
|
||||||
|
|
||||||
|
mod elements;
|
||||||
mod eq;
|
mod eq;
|
||||||
mod fmt;
|
mod fmt;
|
||||||
mod iter;
|
mod iter;
|
||||||
mod lane_count;
|
mod lane_count;
|
||||||
mod masks;
|
mod masks;
|
||||||
mod math;
|
|
||||||
mod ops;
|
mod ops;
|
||||||
mod ord;
|
mod ord;
|
||||||
mod round;
|
mod round;
|
||||||
@ -26,6 +26,7 @@ mod vendor;
|
|||||||
pub mod simd {
|
pub mod simd {
|
||||||
pub(crate) use crate::core_simd::intrinsics;
|
pub(crate) use crate::core_simd::intrinsics;
|
||||||
|
|
||||||
|
pub use crate::core_simd::elements::*;
|
||||||
pub use crate::core_simd::eq::*;
|
pub use crate::core_simd::eq::*;
|
||||||
pub use crate::core_simd::lane_count::{LaneCount, SupportedLaneCount};
|
pub use crate::core_simd::lane_count::{LaneCount, SupportedLaneCount};
|
||||||
pub use crate::core_simd::masks::*;
|
pub use crate::core_simd::masks::*;
|
||||||
|
@ -1,105 +1,7 @@
|
|||||||
use crate::simd::intrinsics::{
|
use crate::simd::intrinsics::{
|
||||||
simd_reduce_add_ordered, simd_reduce_and, simd_reduce_max, simd_reduce_min,
|
simd_reduce_add_ordered, simd_reduce_max, simd_reduce_min, simd_reduce_mul_ordered,
|
||||||
simd_reduce_mul_ordered, simd_reduce_or, simd_reduce_xor,
|
|
||||||
};
|
};
|
||||||
use crate::simd::{LaneCount, Simd, SimdElement, SupportedLaneCount};
|
use crate::simd::{LaneCount, Simd, SupportedLaneCount};
|
||||||
use core::ops::{BitAnd, BitOr, BitXor};
|
|
||||||
|
|
||||||
macro_rules! impl_integer_reductions {
|
|
||||||
{ $scalar:ty } => {
|
|
||||||
impl<const LANES: usize> Simd<$scalar, LANES>
|
|
||||||
where
|
|
||||||
LaneCount<LANES>: SupportedLaneCount,
|
|
||||||
{
|
|
||||||
/// Reducing wrapping add. Returns the sum of the lanes of the vector, with wrapping addition.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # #![feature(portable_simd)]
|
|
||||||
/// # use core::simd::Simd;
|
|
||||||
#[doc = concat!("# use core::simd::", stringify!($scalar), "x4;")]
|
|
||||||
#[doc = concat!("let v = ", stringify!($scalar), "x4::from_array([1, 2, 3, 4]);")]
|
|
||||||
/// assert_eq!(v.reduce_sum(), 10);
|
|
||||||
///
|
|
||||||
/// // SIMD integer addition is always wrapping
|
|
||||||
#[doc = concat!("let v = ", stringify!($scalar), "x4::from_array([", stringify!($scalar) ,"::MAX, 1, 0, 0]);")]
|
|
||||||
#[doc = concat!("assert_eq!(v.reduce_sum(), ", stringify!($scalar), "::MIN);")]
|
|
||||||
/// ```
|
|
||||||
#[inline]
|
|
||||||
pub fn reduce_sum(self) -> $scalar {
|
|
||||||
// Safety: `self` is an integer vector
|
|
||||||
unsafe { simd_reduce_add_ordered(self, 0) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Reducing wrapping multiply. Returns the product of the lanes of the vector, with wrapping multiplication.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # #![feature(portable_simd)]
|
|
||||||
/// # use core::simd::Simd;
|
|
||||||
#[doc = concat!("# use core::simd::", stringify!($scalar), "x4;")]
|
|
||||||
#[doc = concat!("let v = ", stringify!($scalar), "x4::from_array([1, 2, 3, 4]);")]
|
|
||||||
/// assert_eq!(v.reduce_product(), 24);
|
|
||||||
///
|
|
||||||
/// // SIMD integer multiplication is always wrapping
|
|
||||||
#[doc = concat!("let v = ", stringify!($scalar), "x4::from_array([", stringify!($scalar) ,"::MAX, 2, 1, 1]);")]
|
|
||||||
#[doc = concat!("assert!(v.reduce_product() < ", stringify!($scalar), "::MAX);")]
|
|
||||||
/// ```
|
|
||||||
#[inline]
|
|
||||||
pub fn reduce_product(self) -> $scalar {
|
|
||||||
// Safety: `self` is an integer vector
|
|
||||||
unsafe { simd_reduce_mul_ordered(self, 1) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Reducing maximum. Returns the maximum lane in the vector.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # #![feature(portable_simd)]
|
|
||||||
/// # use core::simd::Simd;
|
|
||||||
#[doc = concat!("# use core::simd::", stringify!($scalar), "x4;")]
|
|
||||||
#[doc = concat!("let v = ", stringify!($scalar), "x4::from_array([1, 2, 3, 4]);")]
|
|
||||||
/// assert_eq!(v.reduce_max(), 4);
|
|
||||||
/// ```
|
|
||||||
#[inline]
|
|
||||||
pub fn reduce_max(self) -> $scalar {
|
|
||||||
// Safety: `self` is an integer vector
|
|
||||||
unsafe { simd_reduce_max(self) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Reducing minimum. Returns the minimum lane in the vector.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # #![feature(portable_simd)]
|
|
||||||
/// # use core::simd::Simd;
|
|
||||||
#[doc = concat!("# use core::simd::", stringify!($scalar), "x4;")]
|
|
||||||
#[doc = concat!("let v = ", stringify!($scalar), "x4::from_array([1, 2, 3, 4]);")]
|
|
||||||
/// assert_eq!(v.reduce_min(), 1);
|
|
||||||
/// ```
|
|
||||||
#[inline]
|
|
||||||
pub fn reduce_min(self) -> $scalar {
|
|
||||||
// Safety: `self` is an integer vector
|
|
||||||
unsafe { simd_reduce_min(self) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl_integer_reductions! { i8 }
|
|
||||||
impl_integer_reductions! { i16 }
|
|
||||||
impl_integer_reductions! { i32 }
|
|
||||||
impl_integer_reductions! { i64 }
|
|
||||||
impl_integer_reductions! { isize }
|
|
||||||
impl_integer_reductions! { u8 }
|
|
||||||
impl_integer_reductions! { u16 }
|
|
||||||
impl_integer_reductions! { u32 }
|
|
||||||
impl_integer_reductions! { u64 }
|
|
||||||
impl_integer_reductions! { usize }
|
|
||||||
|
|
||||||
macro_rules! impl_float_reductions {
|
macro_rules! impl_float_reductions {
|
||||||
{ $scalar:ty } => {
|
{ $scalar:ty } => {
|
||||||
@ -223,45 +125,3 @@ macro_rules! impl_float_reductions {
|
|||||||
|
|
||||||
impl_float_reductions! { f32 }
|
impl_float_reductions! { f32 }
|
||||||
impl_float_reductions! { f64 }
|
impl_float_reductions! { f64 }
|
||||||
|
|
||||||
impl<T, const LANES: usize> Simd<T, LANES>
|
|
||||||
where
|
|
||||||
Self: BitAnd<Self, Output = Self>,
|
|
||||||
T: SimdElement + BitAnd<T, Output = T>,
|
|
||||||
LaneCount<LANES>: SupportedLaneCount,
|
|
||||||
{
|
|
||||||
/// Reducing bitwise "and". Returns the cumulative bitwise "and" across the lanes of
|
|
||||||
/// the vector.
|
|
||||||
#[inline]
|
|
||||||
pub fn reduce_and(self) -> T {
|
|
||||||
unsafe { simd_reduce_and(self) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T, const LANES: usize> Simd<T, LANES>
|
|
||||||
where
|
|
||||||
Self: BitOr<Self, Output = Self>,
|
|
||||||
T: SimdElement + BitOr<T, Output = T>,
|
|
||||||
LaneCount<LANES>: SupportedLaneCount,
|
|
||||||
{
|
|
||||||
/// Reducing bitwise "or". Returns the cumulative bitwise "or" across the lanes of
|
|
||||||
/// the vector.
|
|
||||||
#[inline]
|
|
||||||
pub fn reduce_or(self) -> T {
|
|
||||||
unsafe { simd_reduce_or(self) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T, const LANES: usize> Simd<T, LANES>
|
|
||||||
where
|
|
||||||
Self: BitXor<Self, Output = Self>,
|
|
||||||
T: SimdElement + BitXor<T, Output = T>,
|
|
||||||
LaneCount<LANES>: SupportedLaneCount,
|
|
||||||
{
|
|
||||||
/// Reducing bitwise "xor". Returns the cumulative bitwise "xor" across the lanes of
|
|
||||||
/// the vector.
|
|
||||||
#[inline]
|
|
||||||
pub fn reduce_xor(self) -> T {
|
|
||||||
unsafe { simd_reduce_xor(self) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,46 +1,6 @@
|
|||||||
#![allow(non_camel_case_types)]
|
#![allow(non_camel_case_types)]
|
||||||
|
|
||||||
use crate::simd::{LaneCount, Mask, Simd, SimdPartialOrd, SupportedLaneCount};
|
use crate::simd::Simd;
|
||||||
|
|
||||||
/// Implements additional integer traits (Eq, Ord, Hash) on the specified vector `$name`, holding multiple `$lanes` of `$type`.
|
|
||||||
macro_rules! impl_integer_vector {
|
|
||||||
{ $type:ty } => {
|
|
||||||
impl<const LANES: usize> Simd<$type, LANES>
|
|
||||||
where
|
|
||||||
LaneCount<LANES>: SupportedLaneCount,
|
|
||||||
{
|
|
||||||
/// Returns true for each positive lane and false if it is zero or negative.
|
|
||||||
#[inline]
|
|
||||||
pub fn is_positive(self) -> Mask<$type, LANES> {
|
|
||||||
self.simd_gt(Self::splat(0))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns true for each negative lane and false if it is zero or positive.
|
|
||||||
#[inline]
|
|
||||||
pub fn is_negative(self) -> Mask<$type, LANES> {
|
|
||||||
self.simd_lt(Self::splat(0))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns numbers representing the sign of each lane.
|
|
||||||
/// * `0` if the number is zero
|
|
||||||
/// * `1` if the number is positive
|
|
||||||
/// * `-1` if the number is negative
|
|
||||||
#[inline]
|
|
||||||
pub fn signum(self) -> Self {
|
|
||||||
self.is_positive().select(
|
|
||||||
Self::splat(1),
|
|
||||||
self.is_negative().select(Self::splat(-1), Self::splat(0))
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl_integer_vector! { isize }
|
|
||||||
impl_integer_vector! { i16 }
|
|
||||||
impl_integer_vector! { i32 }
|
|
||||||
impl_integer_vector! { i64 }
|
|
||||||
impl_integer_vector! { i8 }
|
|
||||||
|
|
||||||
/// A SIMD vector with two elements of type `isize`.
|
/// A SIMD vector with two elements of type `isize`.
|
||||||
pub type isizex2 = Simd<isize, 2>;
|
pub type isizex2 = Simd<isize, 2>;
|
||||||
|
@ -172,6 +172,7 @@ macro_rules! impl_common_integer_tests {
|
|||||||
macro_rules! impl_signed_tests {
|
macro_rules! impl_signed_tests {
|
||||||
{ $scalar:tt } => {
|
{ $scalar:tt } => {
|
||||||
mod $scalar {
|
mod $scalar {
|
||||||
|
use core_simd::simd::SimdInt;
|
||||||
type Vector<const LANES: usize> = core_simd::Simd<Scalar, LANES>;
|
type Vector<const LANES: usize> = core_simd::Simd<Scalar, LANES>;
|
||||||
type Scalar = $scalar;
|
type Scalar = $scalar;
|
||||||
|
|
||||||
@ -312,6 +313,7 @@ macro_rules! impl_signed_tests {
|
|||||||
macro_rules! impl_unsigned_tests {
|
macro_rules! impl_unsigned_tests {
|
||||||
{ $scalar:tt } => {
|
{ $scalar:tt } => {
|
||||||
mod $scalar {
|
mod $scalar {
|
||||||
|
use core_simd::simd::SimdUint;
|
||||||
type Vector<const LANES: usize> = core_simd::Simd<Scalar, LANES>;
|
type Vector<const LANES: usize> = core_simd::Simd<Scalar, LANES>;
|
||||||
type Scalar = $scalar;
|
type Scalar = $scalar;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user