macro_rules! impl_simd_uint {
(
// SAFETY: The contents of this macro assume that:
//
// - `T` implements `Pod`
// - `Pod` can be implemented for `Simd`
// - `size_of::<Simd>()` is `size_of::<T>() * N`
unsafe {
T = $T:ident,
N = $N:literal,
Simd = $Simd:ident,
IntSimd = $IntSimd:ident,
T_BITS = $T_BITS:literal,
T_BITS_MUL_2 = $T_BITS_MUL_2:literal,
[$($index:literal),* $(,)?],
optional_type_x86_inner { $(X86Inner = $X86Inner:ident)? },
optional_type_arm_inner { $(ArmInner = $ArmInner:ident)? },
optional_type_wasm_inner { $(WasmInner = $WasmInner:ident)? },
}
$fn_not:item
$fn_add:item
$fn_sub:item
$fn_mul:item
$fn_bitand:item
$fn_bitor:item
$fn_bitxor:item
$fn_simd_eq:item
$fn_simd_ne:item
$fn_simd_lt:item
$fn_simd_gt:item
$fn_simd_le:item
$fn_simd_ge:item
$fn_reduce_add:item
$fn_reduce_mul:item
$fn_bitselect:item
$fn_select:item
$fn_to_bitmask:item
$fn_any:item
$fn_all:item
$fn_shuffle:item
$fn_shuffle_zeroing:item
$fn_shuffle_wrapping:item
$fn_shuffle_2:item
$fn_shuffle_zeroing_2:item
$fn_shuffle_wrapping_2:item
$fn_shuffle_3:item
$fn_shuffle_zeroing_3:item
$fn_shuffle_wrapping_3:item
$fn_shuffle_4:item
$fn_shuffle_zeroing_4:item
$fn_shuffle_wrapping_4:item
$fn_transpose:item
$fn_shl_unsigned_simd:item
$fn_shl_u32:item
$fn_shr_unsigned_simd:item
$fn_shr_u32:item
$fn_max:item
$fn_min:item
$fn_reduce_max:item
$fn_reduce_min:item
$fn_unbounded_shl:item
$fn_unbounded_shl_scalar:item
$fn_unbounded_shr:item
$fn_unbounded_shr_scalar:item
$fn_saturating_add:item
$fn_saturating_sub:item
$fn_overflowing_mul:item
optional_fn_widening_mul { $($fn_widening_mul:item)? }
$fn_mul_keep_low_high:item
$fn_mul_keep_high:item
optional_fn_deserialize { $($fn_deserialize:item)? }
) => {
impl_simd!(
unsafe {
T = $T,
N = $N,
Simd = $Simd,
UintSimd = $Simd,
optional_type_x86_inner { $(X86Inner = $X86Inner)? },
optional_type_arm_inner { $(ArmInner = $ArmInner)? },
optional_type_wasm_inner { $(WasmInner = $WasmInner)? },
}
$fn_simd_eq
$fn_simd_ne
$fn_simd_lt
$fn_simd_gt
$fn_simd_le
$fn_simd_ge
$fn_reduce_add
$fn_reduce_mul
$fn_bitselect
$fn_select
$fn_to_bitmask
$fn_any
$fn_all
$fn_shuffle
$fn_shuffle_zeroing
$fn_shuffle_wrapping
$fn_shuffle_2
$fn_shuffle_zeroing_2
$fn_shuffle_wrapping_2
$fn_shuffle_3
$fn_shuffle_zeroing_3
$fn_shuffle_wrapping_3
$fn_shuffle_4
$fn_shuffle_zeroing_4
$fn_shuffle_wrapping_4
$fn_transpose
optional_fn_deserialize { $($fn_deserialize)? }
);
impl_unary_operator!(
$Simd,
Neg,
neg,
#[inline]
fn neg(self) -> Self::Output {
Self::default() - self
}
);
impl_unary_operator!($Simd, Not, not, $fn_not);
impl_binary_operator!($T, $Simd, Add, add, AddAssign, add_assign, $fn_add);
impl_binary_operator!($T, $Simd, Sub, sub, SubAssign, sub_assign, $fn_sub);
impl_binary_operator!($T, $Simd, Mul, mul, MulAssign, mul_assign, $fn_mul);
impl_binary_operator!(
$T,
$Simd,
Div,
div,
DivAssign,
div_assign,
#[inline]
fn div(self, rhs: Self) -> Self::Output {
let self_array = self.to_array();
let rhs_array = rhs.to_array();
Self::new([$(self_array[$index].wrapping_div(rhs_array[$index])),*])
},
,
,
);
impl_binary_operator!(
$T,
$Simd,
Rem,
rem,
RemAssign,
rem_assign,
#[inline]
fn rem(self, rhs: Self) -> Self::Output {
let self_array = self.to_array();
let rhs_array = rhs.to_array();
Self::new([$(self_array[$index].wrapping_rem(rhs_array[$index])),*])
},
,
,
);
impl_shift_operator!(
$T,
$Simd,
$Simd,
$IntSimd,
Shl,
shl,
ShlAssign,
shl_assign,
$fn_shl_unsigned_simd,
$fn_shl_u32,
#[doc = concat!("[`wrapping_shl`]: ", stringify!($T), "::wrapping_shl")]
#[doc = concat!("[`unbounded_shl`]: ", stringify!($Simd), "::unbounded_shl")]
,
#[doc = concat!("[`wrapping_shl`]: ", stringify!($T), "::wrapping_shl")]
#[doc = concat!("[`unbounded_shl_scalar`]: ", stringify!($Simd), "::unbounded_shl_scalar")]
,
#[doc = concat!("[`wrapping_shl`]: ", stringify!($T), "::wrapping_shl")]
#[doc = concat!("[`unbounded_shl`]: ", stringify!($Simd), "::unbounded_shl")]
);
impl_shift_operator!(
$T,
$Simd,
$Simd,
$IntSimd,
Shr,
shr,
ShrAssign,
shr_assign,
$fn_shr_unsigned_simd,
$fn_shr_u32,
#[doc = concat!("[`wrapping_shr`]: ", stringify!($T), "::wrapping_shr")]
#[doc = concat!("[`unbounded_shr`]: ", stringify!($Simd), "::unbounded_shr")]
,
#[doc = concat!("[`wrapping_shr`]: ", stringify!($T), "::wrapping_shr")]
#[doc = concat!("[`unbounded_shr_scalar`]: ", stringify!($Simd), "::unbounded_shr_scalar")]
,
#[doc = concat!("[`wrapping_shr`]: ", stringify!($T), "::wrapping_shr")]
#[doc = concat!("[`unbounded_shr`]: ", stringify!($Simd), "::unbounded_shr")]
);
impl_binary_operator!(
$T,
$Simd,
BitAnd,
bitand,
BitAndAssign,
bitand_assign,
$fn_bitand
);
impl_binary_operator!(
$T,
$Simd,
BitOr,
bitor,
BitOrAssign,
bitor_assign,
$fn_bitor
);
impl_binary_operator!(
$T,
$Simd,
BitXor,
bitxor,
BitXorAssign,
bitxor_assign,
$fn_bitxor
);
impl<Rhs> core::iter::Sum<Rhs> for $Simd
where
$Simd: AddAssign<Rhs>,
{
#[inline]
fn sum<I: Iterator<Item = Rhs>>(iter: I) -> Self {
let mut total = Self::zeroed();
for val in iter {
total += val;
}
total
}
}
impl<Rhs> core::iter::Product<Rhs> for $Simd
where
$Simd: MulAssign<Rhs>,
{
#[inline]
fn product<I: Iterator<Item = Rhs>>(iter: I) -> Self {
let mut total = Self::from(1);
for val in iter {
total *= val;
}
total
}
}
macro_rules! impl_formatting_trait {
($Trait:path) => {
impl $Trait for $Simd {
#[allow(clippy::missing_inline_in_public_items)]
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "(")?;
for (i, x) in self.to_array().iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
<$T as $Trait>::fmt(x, f)?;
}
write!(f, ")")
}
}
}
}
impl_formatting_trait!(core::fmt::Binary);
impl_formatting_trait!(core::fmt::LowerHex);
impl_formatting_trait!(core::fmt::Octal);
impl_formatting_trait!(core::fmt::UpperHex);
impl $Simd {
pub const ONE: Self = Self::splat(1);
pub const ZERO: Self = Self::splat(0);
#[doc = concat!("A SIMD vector with all elements set to [`", stringify!($T) ,"::MAX`].")]
pub const MAX: Self = Self::splat($T::MAX);
#[doc = concat!("A SIMD vector with all elements set to [`", stringify!($T) ,"::MIN`].")]
pub const MIN: Self = Self::splat($T::MIN);
pub const LANES: u16 = $N;
pub const BITS: u16 = (size_of::<Self>() * 8) as u16;
#[must_use]
$fn_max
#[must_use]
$fn_min
#[inline]
#[must_use]
pub fn clamp(self, min: Self, max: Self) -> Self {
self.max(min).min(max)
}
#[must_use]
$fn_reduce_max
#[must_use]
$fn_reduce_min
#[inline]
#[must_use]
pub const fn cast_signed(self) -> $IntSimd {
unsafe { core::mem::transmute::<$Simd, $IntSimd>(self) }
}
#[doc = concat!("If `rhs` is larger than or equal to the number of bits in [`", stringify!($T), "`],")]
#[doc = concat!("[`wrapping_shl`]: ", stringify!($T), "::wrapping_shl")]
#[must_use]
$fn_unbounded_shl
#[doc = concat!("If `rhs` is larger than or equal to the number of bits in [`", stringify!($T), "`],")]
#[doc = concat!("[`wrapping_shl`]: ", stringify!($T), "::wrapping_shl")]
#[must_use]
$fn_unbounded_shl_scalar
#[doc = concat!("If `rhs` is larger than or equal to the number of bits in [`", stringify!($T), "`],")]
#[doc = concat!("[`wrapping_shr`]: ", stringify!($T), "::wrapping_shr")]
#[must_use]
$fn_unbounded_shr
#[doc = concat!("If `rhs` is larger than or equal to the number of bits in [`", stringify!($T), "`],")]
#[doc = concat!("[`wrapping_shr`]: ", stringify!($T), "::wrapping_shr")]
#[must_use]
$fn_unbounded_shr_scalar
#[must_use]
$fn_saturating_add
#[must_use]
$fn_saturating_sub
#[inline]
#[must_use]
pub fn saturating_mul(self, rhs: Self) -> Self {
let (low, high) = self.mul_keep_low_high(rhs);
low | high.simd_ne(Self::ZERO)
}
#[inline]
#[must_use]
pub fn saturating_div(self, rhs: Self) -> Self {
let self_array = self.to_array();
let rhs_array = rhs.to_array();
Self::new([$(self_array[$index].saturating_div(rhs_array[$index])),*])
}
#[inline]
#[must_use]
pub fn overflowing_add(self, rhs: Self) -> (Self, Self) {
let result = self + rhs;
let overflow = result.simd_lt(self);
(result, overflow)
}
#[inline]
#[must_use]
pub fn overflowing_sub(self, rhs: Self) -> (Self, Self) {
let result = self - rhs;
let overflow = result.simd_gt(self);
(result, overflow)
}
#[must_use]
$fn_overflowing_mul
#[inline]
#[must_use]
pub fn overflowing_div(self, rhs: Self) -> (Self, Self) {
(self / rhs, Self::ZERO)
}
#[inline]
#[must_use]
pub fn overflowing_rem(self, rhs: Self) -> (Self, Self) {
(self % rhs, Self::ZERO)
}
$(
#[must_use]
$fn_widening_mul
)?
#[doc = concat!(
"Computes `self * rhs`, producing intermediate ",
$T_BITS_MUL_2,
"-bit integers, then returns their low ",
$T_BITS,
"-bit parts and high ",
$T_BITS,
"-bit parts in two seperate SIMD vectors."
)]
#[must_use]
$fn_mul_keep_low_high
#[doc = concat!(
"Computes `self * rhs`, producing intermediate ",
$T_BITS_MUL_2,
"-bit integers, then returns their high ",
$T_BITS,
"-bit parts."
)]
#[must_use]
$fn_mul_keep_high
}
};
}