2021-02-13 14:58:44 -06:00
|
|
|
/// Implements a test on a unary operation using proptest.
|
|
|
|
///
|
|
|
|
/// Compares the vector operation to the equivalent scalar operation.
|
2021-02-13 13:19:16 -06:00
|
|
|
#[macro_export]
|
2021-01-07 00:26:29 -06:00
|
|
|
macro_rules! impl_unary_op_test {
|
2021-08-07 15:38:41 -05:00
|
|
|
{ $scalar:ty, $trait:ident :: $fn:ident, $scalar_fn:expr } => {
|
2021-01-07 00:26:29 -06:00
|
|
|
test_helpers::test_lanes! {
|
|
|
|
fn $fn<const LANES: usize>() {
|
|
|
|
test_helpers::test_unary_elementwise(
|
2022-11-27 22:44:20 -06:00
|
|
|
&<core_simd::simd::Simd<$scalar, LANES> as core::ops::$trait>::$fn,
|
2021-02-13 01:14:47 -06:00
|
|
|
&$scalar_fn,
|
|
|
|
&|_| true,
|
2021-01-07 00:26:29 -06:00
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
2021-08-07 15:38:41 -05:00
|
|
|
{ $scalar:ty, $trait:ident :: $fn:ident } => {
|
|
|
|
impl_unary_op_test! { $scalar, $trait::$fn, <$scalar as core::ops::$trait>::$fn }
|
2021-01-07 00:26:29 -06:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2021-02-13 14:58:44 -06:00
|
|
|
/// Implements a test on a binary operation using proptest.
|
|
|
|
///
|
|
|
|
/// Compares the vector operation to the equivalent scalar operation.
|
2021-02-13 13:19:16 -06:00
|
|
|
#[macro_export]
|
2021-01-07 00:26:29 -06:00
|
|
|
macro_rules! impl_binary_op_test {
|
2021-08-07 15:38:41 -05:00
|
|
|
{ $scalar:ty, $trait:ident :: $fn:ident, $trait_assign:ident :: $fn_assign:ident, $scalar_fn:expr } => {
|
2021-01-07 00:26:29 -06:00
|
|
|
mod $fn {
|
|
|
|
use super::*;
|
2022-11-27 22:44:20 -06:00
|
|
|
use core_simd::simd::Simd;
|
2021-01-07 00:26:29 -06:00
|
|
|
|
|
|
|
test_helpers::test_lanes! {
|
|
|
|
fn normal<const LANES: usize>() {
|
|
|
|
test_helpers::test_binary_elementwise(
|
2021-08-07 15:38:41 -05:00
|
|
|
&<Simd<$scalar, LANES> as core::ops::$trait>::$fn,
|
2021-02-13 01:14:47 -06:00
|
|
|
&$scalar_fn,
|
|
|
|
&|_, _| true,
|
2021-01-07 00:26:29 -06:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn assign<const LANES: usize>() {
|
|
|
|
test_helpers::test_binary_elementwise(
|
2021-08-07 15:38:41 -05:00
|
|
|
&|mut a, b| { <Simd<$scalar, LANES> as core::ops::$trait_assign>::$fn_assign(&mut a, b); a },
|
2021-02-13 01:14:47 -06:00
|
|
|
&$scalar_fn,
|
|
|
|
&|_, _| true,
|
|
|
|
);
|
2021-01-07 00:26:29 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
2021-08-07 15:38:41 -05:00
|
|
|
{ $scalar:ty, $trait:ident :: $fn:ident, $trait_assign:ident :: $fn_assign:ident } => {
|
|
|
|
impl_binary_op_test! { $scalar, $trait::$fn, $trait_assign::$fn_assign, <$scalar as core::ops::$trait>::$fn }
|
2021-01-07 00:26:29 -06:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2021-02-13 14:58:44 -06:00
|
|
|
/// Implements a test on a binary operation using proptest.
|
|
|
|
///
|
|
|
|
/// Like `impl_binary_op_test`, but allows providing a function for rejecting particular inputs
|
|
|
|
/// (like the `proptest_assume` macro).
|
|
|
|
///
|
|
|
|
/// Compares the vector operation to the equivalent scalar operation.
|
2021-02-13 13:19:16 -06:00
|
|
|
#[macro_export]
|
2021-01-07 00:26:29 -06:00
|
|
|
macro_rules! impl_binary_checked_op_test {
|
2021-08-07 15:38:41 -05:00
|
|
|
{ $scalar:ty, $trait:ident :: $fn:ident, $trait_assign:ident :: $fn_assign:ident, $scalar_fn:expr, $check_fn:expr } => {
|
2021-01-07 00:26:29 -06:00
|
|
|
mod $fn {
|
|
|
|
use super::*;
|
2022-11-27 22:44:20 -06:00
|
|
|
use core_simd::simd::Simd;
|
2021-01-07 00:26:29 -06:00
|
|
|
|
|
|
|
test_helpers::test_lanes! {
|
|
|
|
fn normal<const LANES: usize>() {
|
|
|
|
test_helpers::test_binary_elementwise(
|
2021-08-07 15:38:41 -05:00
|
|
|
&<Simd<$scalar, LANES> as core::ops::$trait>::$fn,
|
2021-02-13 01:14:47 -06:00
|
|
|
&$scalar_fn,
|
|
|
|
&|x, y| x.iter().zip(y.iter()).all(|(x, y)| $check_fn(*x, *y)),
|
2021-01-07 00:26:29 -06:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn assign<const LANES: usize>() {
|
|
|
|
test_helpers::test_binary_elementwise(
|
2021-08-07 15:38:41 -05:00
|
|
|
&|mut a, b| { <Simd<$scalar, LANES> as core::ops::$trait_assign>::$fn_assign(&mut a, b); a },
|
2021-02-13 01:14:47 -06:00
|
|
|
&$scalar_fn,
|
|
|
|
&|x, y| x.iter().zip(y.iter()).all(|(x, y)| $check_fn(*x, *y)),
|
2021-01-07 00:26:29 -06:00
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
2021-08-07 15:38:41 -05:00
|
|
|
{ $scalar:ty, $trait:ident :: $fn:ident, $trait_assign:ident :: $fn_assign:ident, $check_fn:expr } => {
|
|
|
|
impl_binary_checked_op_test! { $scalar, $trait::$fn, $trait_assign::$fn_assign, <$scalar as core::ops::$trait>::$fn, $check_fn }
|
2021-01-07 00:26:29 -06:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2021-03-07 23:48:18 -06:00
|
|
|
#[macro_export]
|
|
|
|
macro_rules! impl_common_integer_tests {
|
|
|
|
{ $vector:ident, $scalar:ident } => {
|
|
|
|
test_helpers::test_lanes! {
|
2023-07-28 20:26:14 -05:00
|
|
|
fn shr<const LANES: usize>() {
|
|
|
|
use core::ops::Shr;
|
|
|
|
let shr = |x: $scalar, y: $scalar| x.wrapping_shr(y as _);
|
|
|
|
test_helpers::test_binary_elementwise(
|
|
|
|
&<$vector::<LANES> as Shr<$vector::<LANES>>>::shr,
|
|
|
|
&shr,
|
|
|
|
&|_, _| true,
|
|
|
|
);
|
|
|
|
test_helpers::test_binary_scalar_rhs_elementwise(
|
|
|
|
&<$vector::<LANES> as Shr<$scalar>>::shr,
|
|
|
|
&shr,
|
|
|
|
&|_, _| true,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn shl<const LANES: usize>() {
|
|
|
|
use core::ops::Shl;
|
|
|
|
let shl = |x: $scalar, y: $scalar| x.wrapping_shl(y as _);
|
|
|
|
test_helpers::test_binary_elementwise(
|
|
|
|
&<$vector::<LANES> as Shl<$vector::<LANES>>>::shl,
|
|
|
|
&shl,
|
|
|
|
&|_, _| true,
|
|
|
|
);
|
|
|
|
test_helpers::test_binary_scalar_rhs_elementwise(
|
|
|
|
&<$vector::<LANES> as Shl<$scalar>>::shl,
|
|
|
|
&shl,
|
|
|
|
&|_, _| true,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2022-03-11 16:49:06 -06:00
|
|
|
fn reduce_sum<const LANES: usize>() {
|
2021-03-07 23:48:18 -06:00
|
|
|
test_helpers::test_1(&|x| {
|
|
|
|
test_helpers::prop_assert_biteq! (
|
2022-03-11 16:49:06 -06:00
|
|
|
$vector::<LANES>::from_array(x).reduce_sum(),
|
2021-03-07 23:48:18 -06:00
|
|
|
x.iter().copied().fold(0 as $scalar, $scalar::wrapping_add),
|
|
|
|
);
|
|
|
|
Ok(())
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2022-03-11 16:49:06 -06:00
|
|
|
fn reduce_product<const LANES: usize>() {
|
2021-03-07 23:48:18 -06:00
|
|
|
test_helpers::test_1(&|x| {
|
|
|
|
test_helpers::prop_assert_biteq! (
|
2022-03-11 16:49:06 -06:00
|
|
|
$vector::<LANES>::from_array(x).reduce_product(),
|
2021-03-07 23:48:18 -06:00
|
|
|
x.iter().copied().fold(1 as $scalar, $scalar::wrapping_mul),
|
|
|
|
);
|
|
|
|
Ok(())
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2022-03-11 16:49:06 -06:00
|
|
|
fn reduce_and<const LANES: usize>() {
|
2021-03-07 23:48:18 -06:00
|
|
|
test_helpers::test_1(&|x| {
|
|
|
|
test_helpers::prop_assert_biteq! (
|
2022-03-11 16:49:06 -06:00
|
|
|
$vector::<LANES>::from_array(x).reduce_and(),
|
2021-03-07 23:48:18 -06:00
|
|
|
x.iter().copied().fold(-1i8 as $scalar, <$scalar as core::ops::BitAnd>::bitand),
|
|
|
|
);
|
|
|
|
Ok(())
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2022-03-11 16:49:06 -06:00
|
|
|
fn reduce_or<const LANES: usize>() {
|
2021-03-07 23:48:18 -06:00
|
|
|
test_helpers::test_1(&|x| {
|
|
|
|
test_helpers::prop_assert_biteq! (
|
2022-03-11 16:49:06 -06:00
|
|
|
$vector::<LANES>::from_array(x).reduce_or(),
|
2021-03-07 23:48:18 -06:00
|
|
|
x.iter().copied().fold(0 as $scalar, <$scalar as core::ops::BitOr>::bitor),
|
|
|
|
);
|
|
|
|
Ok(())
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2022-03-11 16:49:06 -06:00
|
|
|
fn reduce_xor<const LANES: usize>() {
|
2021-03-07 23:48:18 -06:00
|
|
|
test_helpers::test_1(&|x| {
|
|
|
|
test_helpers::prop_assert_biteq! (
|
2022-03-11 16:49:06 -06:00
|
|
|
$vector::<LANES>::from_array(x).reduce_xor(),
|
2021-03-07 23:48:18 -06:00
|
|
|
x.iter().copied().fold(0 as $scalar, <$scalar as core::ops::BitXor>::bitxor),
|
|
|
|
);
|
|
|
|
Ok(())
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2022-03-11 16:49:06 -06:00
|
|
|
fn reduce_max<const LANES: usize>() {
|
2021-03-07 23:48:18 -06:00
|
|
|
test_helpers::test_1(&|x| {
|
|
|
|
test_helpers::prop_assert_biteq! (
|
2022-03-11 16:49:06 -06:00
|
|
|
$vector::<LANES>::from_array(x).reduce_max(),
|
2021-03-07 23:48:18 -06:00
|
|
|
x.iter().copied().max().unwrap(),
|
|
|
|
);
|
|
|
|
Ok(())
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2022-03-11 16:49:06 -06:00
|
|
|
fn reduce_min<const LANES: usize>() {
|
2021-03-07 23:48:18 -06:00
|
|
|
test_helpers::test_1(&|x| {
|
|
|
|
test_helpers::prop_assert_biteq! (
|
2022-03-11 16:49:06 -06:00
|
|
|
$vector::<LANES>::from_array(x).reduce_min(),
|
2021-03-07 23:48:18 -06:00
|
|
|
x.iter().copied().min().unwrap(),
|
|
|
|
);
|
|
|
|
Ok(())
|
|
|
|
});
|
|
|
|
}
|
2023-07-30 14:53:32 -05:00
|
|
|
|
|
|
|
fn swap_bytes<const LANES: usize>() {
|
|
|
|
test_helpers::test_unary_elementwise(
|
|
|
|
&$vector::<LANES>::swap_bytes,
|
|
|
|
&$scalar::swap_bytes,
|
|
|
|
&|_| true,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn reverse_bits<const LANES: usize>() {
|
|
|
|
test_helpers::test_unary_elementwise(
|
|
|
|
&$vector::<LANES>::reverse_bits,
|
|
|
|
&$scalar::reverse_bits,
|
|
|
|
&|_| true,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn leading_zeros<const LANES: usize>() {
|
|
|
|
test_helpers::test_unary_elementwise(
|
|
|
|
&$vector::<LANES>::leading_zeros,
|
|
|
|
&|x| x.leading_zeros() as $scalar,
|
|
|
|
&|_| true,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn trailing_zeros<const LANES: usize>() {
|
|
|
|
test_helpers::test_unary_elementwise(
|
2023-07-30 15:20:20 -05:00
|
|
|
&$vector::<LANES>::trailing_zeros,
|
2023-07-30 14:53:32 -05:00
|
|
|
&|x| x.trailing_zeros() as $scalar,
|
|
|
|
&|_| true,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn leading_ones<const LANES: usize>() {
|
|
|
|
test_helpers::test_unary_elementwise(
|
|
|
|
&$vector::<LANES>::leading_ones,
|
|
|
|
&|x| x.leading_ones() as $scalar,
|
|
|
|
&|_| true,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn trailing_ones<const LANES: usize>() {
|
|
|
|
test_helpers::test_unary_elementwise(
|
2023-07-30 15:20:20 -05:00
|
|
|
&$vector::<LANES>::trailing_ones,
|
2023-07-30 14:53:32 -05:00
|
|
|
&|x| x.trailing_ones() as $scalar,
|
|
|
|
&|_| true,
|
|
|
|
)
|
|
|
|
}
|
2021-03-07 23:48:18 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-13 14:58:44 -06:00
|
|
|
/// Implement tests for signed integers.
|
2021-02-13 13:19:16 -06:00
|
|
|
#[macro_export]
|
2021-01-07 00:26:29 -06:00
|
|
|
macro_rules! impl_signed_tests {
|
2021-08-07 15:38:41 -05:00
|
|
|
{ $scalar:tt } => {
|
2021-01-07 00:26:29 -06:00
|
|
|
mod $scalar {
|
2022-04-11 00:38:07 -05:00
|
|
|
use core_simd::simd::SimdInt;
|
2022-11-27 22:44:20 -06:00
|
|
|
type Vector<const LANES: usize> = core_simd::simd::Simd<Scalar, LANES>;
|
2021-01-07 00:26:29 -06:00
|
|
|
type Scalar = $scalar;
|
|
|
|
|
2021-03-07 23:48:18 -06:00
|
|
|
impl_common_integer_tests! { Vector, Scalar }
|
|
|
|
|
2021-01-07 00:26:29 -06:00
|
|
|
test_helpers::test_lanes! {
|
|
|
|
fn neg<const LANES: usize>() {
|
|
|
|
test_helpers::test_unary_elementwise(
|
2021-03-06 01:14:58 -06:00
|
|
|
&<Vector::<LANES> as core::ops::Neg>::neg,
|
2021-02-13 01:14:47 -06:00
|
|
|
&<Scalar as core::ops::Neg>::neg,
|
|
|
|
&|x| !x.contains(&Scalar::MIN),
|
2021-01-07 00:26:29 -06:00
|
|
|
);
|
|
|
|
}
|
2021-03-06 01:14:58 -06:00
|
|
|
|
|
|
|
fn is_positive<const LANES: usize>() {
|
|
|
|
test_helpers::test_unary_mask_elementwise(
|
|
|
|
&Vector::<LANES>::is_positive,
|
|
|
|
&Scalar::is_positive,
|
|
|
|
&|_| true,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn is_negative<const LANES: usize>() {
|
|
|
|
test_helpers::test_unary_mask_elementwise(
|
|
|
|
&Vector::<LANES>::is_negative,
|
|
|
|
&Scalar::is_negative,
|
|
|
|
&|_| true,
|
|
|
|
);
|
|
|
|
}
|
2021-06-13 13:45:45 -05:00
|
|
|
|
|
|
|
fn signum<const LANES: usize>() {
|
|
|
|
test_helpers::test_unary_elementwise(
|
|
|
|
&Vector::<LANES>::signum,
|
|
|
|
&Scalar::signum,
|
|
|
|
&|_| true,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2022-02-07 23:24:21 -06:00
|
|
|
fn div_min_may_overflow<const LANES: usize>() {
|
|
|
|
let a = Vector::<LANES>::splat(Scalar::MIN);
|
|
|
|
let b = Vector::<LANES>::splat(-1);
|
2022-02-08 19:38:21 -06:00
|
|
|
assert_eq!(a / b, a);
|
2022-02-07 23:24:21 -06:00
|
|
|
}
|
2021-01-07 00:26:29 -06:00
|
|
|
|
2022-02-07 23:24:21 -06:00
|
|
|
fn rem_min_may_overflow<const LANES: usize>() {
|
2021-02-13 14:42:04 -06:00
|
|
|
let a = Vector::<LANES>::splat(Scalar::MIN);
|
|
|
|
let b = Vector::<LANES>::splat(-1);
|
2022-02-08 19:38:21 -06:00
|
|
|
assert_eq!(a % b, Vector::<LANES>::splat(0));
|
2021-02-13 14:42:04 -06:00
|
|
|
}
|
|
|
|
|
2022-03-13 14:07:36 -05:00
|
|
|
fn simd_min<const LANES: usize>() {
|
|
|
|
use core_simd::simd::SimdOrd;
|
2022-03-10 17:12:40 -06:00
|
|
|
let a = Vector::<LANES>::splat(Scalar::MIN);
|
|
|
|
let b = Vector::<LANES>::splat(0);
|
2022-03-13 14:07:36 -05:00
|
|
|
assert_eq!(a.simd_min(b), a);
|
2022-03-10 17:12:40 -06:00
|
|
|
let a = Vector::<LANES>::splat(Scalar::MAX);
|
|
|
|
let b = Vector::<LANES>::splat(0);
|
2022-03-13 14:07:36 -05:00
|
|
|
assert_eq!(a.simd_min(b), b);
|
2022-03-10 17:12:40 -06:00
|
|
|
}
|
|
|
|
|
2022-03-13 14:07:36 -05:00
|
|
|
fn simd_max<const LANES: usize>() {
|
|
|
|
use core_simd::simd::SimdOrd;
|
2022-03-10 17:12:40 -06:00
|
|
|
let a = Vector::<LANES>::splat(Scalar::MIN);
|
|
|
|
let b = Vector::<LANES>::splat(0);
|
2022-03-13 14:07:36 -05:00
|
|
|
assert_eq!(a.simd_max(b), b);
|
2022-03-10 17:12:40 -06:00
|
|
|
let a = Vector::<LANES>::splat(Scalar::MAX);
|
|
|
|
let b = Vector::<LANES>::splat(0);
|
2022-03-13 14:07:36 -05:00
|
|
|
assert_eq!(a.simd_max(b), a);
|
2022-03-10 17:12:40 -06:00
|
|
|
}
|
2022-03-12 17:32:28 -06:00
|
|
|
|
2022-03-13 14:07:36 -05:00
|
|
|
fn simd_clamp<const LANES: usize>() {
|
|
|
|
use core_simd::simd::SimdOrd;
|
2022-03-12 17:32:28 -06:00
|
|
|
let min = Vector::<LANES>::splat(Scalar::MIN);
|
|
|
|
let max = Vector::<LANES>::splat(Scalar::MAX);
|
|
|
|
let zero = Vector::<LANES>::splat(0);
|
|
|
|
let one = Vector::<LANES>::splat(1);
|
|
|
|
let negone = Vector::<LANES>::splat(-1);
|
2022-03-13 14:07:36 -05:00
|
|
|
assert_eq!(zero.simd_clamp(min, max), zero);
|
|
|
|
assert_eq!(zero.simd_clamp(min, one), zero);
|
|
|
|
assert_eq!(zero.simd_clamp(one, max), one);
|
|
|
|
assert_eq!(zero.simd_clamp(min, negone), negone);
|
2022-03-12 17:32:28 -06:00
|
|
|
}
|
2022-02-07 23:24:21 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
test_helpers::test_lanes_panic! {
|
2021-02-13 14:42:04 -06:00
|
|
|
fn div_by_all_zeros_panics<const LANES: usize>() {
|
|
|
|
let a = Vector::<LANES>::splat(42);
|
|
|
|
let b = Vector::<LANES>::splat(0);
|
|
|
|
let _ = a / b;
|
|
|
|
}
|
|
|
|
|
|
|
|
fn div_by_one_zero_panics<const LANES: usize>() {
|
|
|
|
let a = Vector::<LANES>::splat(42);
|
|
|
|
let mut b = Vector::<LANES>::splat(21);
|
|
|
|
b[0] = 0 as _;
|
|
|
|
let _ = a / b;
|
|
|
|
}
|
|
|
|
|
|
|
|
fn rem_zero_panic<const LANES: usize>() {
|
|
|
|
let a = Vector::<LANES>::splat(42);
|
|
|
|
let b = Vector::<LANES>::splat(0);
|
|
|
|
let _ = a % b;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
test_helpers::test_lanes! {
|
|
|
|
fn div_neg_one_no_panic<const LANES: usize>() {
|
|
|
|
let a = Vector::<LANES>::splat(42);
|
|
|
|
let b = Vector::<LANES>::splat(-1);
|
|
|
|
let _ = a / b;
|
|
|
|
}
|
|
|
|
|
|
|
|
fn rem_neg_one_no_panic<const LANES: usize>() {
|
|
|
|
let a = Vector::<LANES>::splat(42);
|
|
|
|
let b = Vector::<LANES>::splat(-1);
|
|
|
|
let _ = a % b;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-07 15:38:41 -05:00
|
|
|
impl_binary_op_test!(Scalar, Add::add, AddAssign::add_assign, Scalar::wrapping_add);
|
|
|
|
impl_binary_op_test!(Scalar, Sub::sub, SubAssign::sub_assign, Scalar::wrapping_sub);
|
|
|
|
impl_binary_op_test!(Scalar, Mul::mul, MulAssign::mul_assign, Scalar::wrapping_mul);
|
2021-02-13 14:58:44 -06:00
|
|
|
|
|
|
|
// Exclude Div and Rem panicking cases
|
2021-08-07 15:38:41 -05:00
|
|
|
impl_binary_checked_op_test!(Scalar, Div::div, DivAssign::div_assign, Scalar::wrapping_div, |x, y| y != 0 && !(x == Scalar::MIN && y == -1));
|
|
|
|
impl_binary_checked_op_test!(Scalar, Rem::rem, RemAssign::rem_assign, Scalar::wrapping_rem, |x, y| y != 0 && !(x == Scalar::MIN && y == -1));
|
2021-01-07 00:26:29 -06:00
|
|
|
|
2021-08-07 15:38:41 -05:00
|
|
|
impl_unary_op_test!(Scalar, Not::not);
|
|
|
|
impl_binary_op_test!(Scalar, BitAnd::bitand, BitAndAssign::bitand_assign);
|
|
|
|
impl_binary_op_test!(Scalar, BitOr::bitor, BitOrAssign::bitor_assign);
|
|
|
|
impl_binary_op_test!(Scalar, BitXor::bitxor, BitXorAssign::bitxor_assign);
|
2021-01-07 00:26:29 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-13 14:58:44 -06:00
|
|
|
/// Implement tests for unsigned integers.
|
2021-02-13 13:19:16 -06:00
|
|
|
#[macro_export]
|
2021-01-07 00:26:29 -06:00
|
|
|
macro_rules! impl_unsigned_tests {
|
2021-08-07 15:38:41 -05:00
|
|
|
{ $scalar:tt } => {
|
2021-01-07 00:26:29 -06:00
|
|
|
mod $scalar {
|
2022-04-11 00:38:07 -05:00
|
|
|
use core_simd::simd::SimdUint;
|
2022-11-27 22:44:20 -06:00
|
|
|
type Vector<const LANES: usize> = core_simd::simd::Simd<Scalar, LANES>;
|
2021-01-07 00:26:29 -06:00
|
|
|
type Scalar = $scalar;
|
|
|
|
|
2021-03-07 23:48:18 -06:00
|
|
|
impl_common_integer_tests! { Vector, Scalar }
|
|
|
|
|
2021-02-13 14:42:04 -06:00
|
|
|
test_helpers::test_lanes_panic! {
|
|
|
|
fn rem_zero_panic<const LANES: usize>() {
|
|
|
|
let a = Vector::<LANES>::splat(42);
|
|
|
|
let b = Vector::<LANES>::splat(0);
|
|
|
|
let _ = a % b;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-07 15:38:41 -05:00
|
|
|
impl_binary_op_test!(Scalar, Add::add, AddAssign::add_assign, Scalar::wrapping_add);
|
|
|
|
impl_binary_op_test!(Scalar, Sub::sub, SubAssign::sub_assign, Scalar::wrapping_sub);
|
|
|
|
impl_binary_op_test!(Scalar, Mul::mul, MulAssign::mul_assign, Scalar::wrapping_mul);
|
2021-02-13 14:58:44 -06:00
|
|
|
|
|
|
|
// Exclude Div and Rem panicking cases
|
2021-08-07 15:38:41 -05:00
|
|
|
impl_binary_checked_op_test!(Scalar, Div::div, DivAssign::div_assign, Scalar::wrapping_div, |_, y| y != 0);
|
|
|
|
impl_binary_checked_op_test!(Scalar, Rem::rem, RemAssign::rem_assign, Scalar::wrapping_rem, |_, y| y != 0);
|
2021-01-07 00:26:29 -06:00
|
|
|
|
2021-08-07 15:38:41 -05:00
|
|
|
impl_unary_op_test!(Scalar, Not::not);
|
|
|
|
impl_binary_op_test!(Scalar, BitAnd::bitand, BitAndAssign::bitand_assign);
|
|
|
|
impl_binary_op_test!(Scalar, BitOr::bitor, BitOrAssign::bitor_assign);
|
|
|
|
impl_binary_op_test!(Scalar, BitXor::bitxor, BitXorAssign::bitxor_assign);
|
2021-01-07 00:26:29 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-13 14:58:44 -06:00
|
|
|
/// Implement tests for floating point numbers.
|
2021-02-13 13:19:16 -06:00
|
|
|
#[macro_export]
|
|
|
|
macro_rules! impl_float_tests {
|
2021-08-07 15:38:41 -05:00
|
|
|
{ $scalar:tt, $int_scalar:tt } => {
|
2021-02-13 13:19:16 -06:00
|
|
|
mod $scalar {
|
2022-11-27 22:44:20 -06:00
|
|
|
use core_simd::simd::SimdFloat;
|
|
|
|
type Vector<const LANES: usize> = core_simd::simd::Simd<Scalar, LANES>;
|
2021-02-13 13:19:16 -06:00
|
|
|
type Scalar = $scalar;
|
|
|
|
|
2021-08-07 15:38:41 -05:00
|
|
|
impl_unary_op_test!(Scalar, Neg::neg);
|
|
|
|
impl_binary_op_test!(Scalar, Add::add, AddAssign::add_assign);
|
|
|
|
impl_binary_op_test!(Scalar, Sub::sub, SubAssign::sub_assign);
|
|
|
|
impl_binary_op_test!(Scalar, Mul::mul, MulAssign::mul_assign);
|
|
|
|
impl_binary_op_test!(Scalar, Div::div, DivAssign::div_assign);
|
|
|
|
impl_binary_op_test!(Scalar, Rem::rem, RemAssign::rem_assign);
|
2021-02-13 13:19:16 -06:00
|
|
|
|
2021-03-06 20:56:01 -06:00
|
|
|
test_helpers::test_lanes! {
|
2021-03-06 01:14:58 -06:00
|
|
|
fn is_sign_positive<const LANES: usize>() {
|
|
|
|
test_helpers::test_unary_mask_elementwise(
|
|
|
|
&Vector::<LANES>::is_sign_positive,
|
|
|
|
&Scalar::is_sign_positive,
|
|
|
|
&|_| true,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn is_sign_negative<const LANES: usize>() {
|
|
|
|
test_helpers::test_unary_mask_elementwise(
|
|
|
|
&Vector::<LANES>::is_sign_negative,
|
|
|
|
&Scalar::is_sign_negative,
|
|
|
|
&|_| true,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn is_finite<const LANES: usize>() {
|
|
|
|
test_helpers::test_unary_mask_elementwise(
|
|
|
|
&Vector::<LANES>::is_finite,
|
|
|
|
&Scalar::is_finite,
|
|
|
|
&|_| true,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn is_infinite<const LANES: usize>() {
|
|
|
|
test_helpers::test_unary_mask_elementwise(
|
|
|
|
&Vector::<LANES>::is_infinite,
|
|
|
|
&Scalar::is_infinite,
|
|
|
|
&|_| true,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn is_nan<const LANES: usize>() {
|
|
|
|
test_helpers::test_unary_mask_elementwise(
|
|
|
|
&Vector::<LANES>::is_nan,
|
|
|
|
&Scalar::is_nan,
|
|
|
|
&|_| true,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn is_normal<const LANES: usize>() {
|
|
|
|
test_helpers::test_unary_mask_elementwise(
|
|
|
|
&Vector::<LANES>::is_normal,
|
|
|
|
&Scalar::is_normal,
|
|
|
|
&|_| true,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn is_subnormal<const LANES: usize>() {
|
|
|
|
test_helpers::test_unary_mask_elementwise(
|
|
|
|
&Vector::<LANES>::is_subnormal,
|
|
|
|
&Scalar::is_subnormal,
|
|
|
|
&|_| true,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2021-03-06 20:56:01 -06:00
|
|
|
fn abs<const LANES: usize>() {
|
|
|
|
test_helpers::test_unary_elementwise(
|
|
|
|
&Vector::<LANES>::abs,
|
|
|
|
&Scalar::abs,
|
|
|
|
&|_| true,
|
|
|
|
)
|
|
|
|
}
|
2021-03-07 23:48:18 -06:00
|
|
|
|
2021-06-13 13:45:45 -05:00
|
|
|
fn recip<const LANES: usize>() {
|
|
|
|
test_helpers::test_unary_elementwise(
|
|
|
|
&Vector::<LANES>::recip,
|
|
|
|
&Scalar::recip,
|
|
|
|
&|_| true,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn to_degrees<const LANES: usize>() {
|
|
|
|
test_helpers::test_unary_elementwise(
|
|
|
|
&Vector::<LANES>::to_degrees,
|
|
|
|
&Scalar::to_degrees,
|
|
|
|
&|_| true,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn to_radians<const LANES: usize>() {
|
|
|
|
test_helpers::test_unary_elementwise(
|
|
|
|
&Vector::<LANES>::to_radians,
|
|
|
|
&Scalar::to_radians,
|
|
|
|
&|_| true,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn signum<const LANES: usize>() {
|
|
|
|
test_helpers::test_unary_elementwise(
|
|
|
|
&Vector::<LANES>::signum,
|
|
|
|
&Scalar::signum,
|
|
|
|
&|_| true,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn copysign<const LANES: usize>() {
|
|
|
|
test_helpers::test_binary_elementwise(
|
|
|
|
&Vector::<LANES>::copysign,
|
|
|
|
&Scalar::copysign,
|
|
|
|
&|_, _| true,
|
|
|
|
)
|
|
|
|
}
|
2021-06-13 14:47:32 -05:00
|
|
|
|
2022-03-13 14:07:36 -05:00
|
|
|
fn simd_min<const LANES: usize>() {
|
2021-06-13 14:47:32 -05:00
|
|
|
// Regular conditions (both values aren't zero)
|
|
|
|
test_helpers::test_binary_elementwise(
|
2022-03-13 14:07:36 -05:00
|
|
|
&Vector::<LANES>::simd_min,
|
2021-06-13 14:47:32 -05:00
|
|
|
&Scalar::min,
|
|
|
|
// Reject the case where both values are zero with different signs
|
|
|
|
&|a, b| {
|
|
|
|
for (a, b) in a.iter().zip(b.iter()) {
|
|
|
|
if *a == 0. && *b == 0. && a.signum() != b.signum() {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
true
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
// Special case where both values are zero
|
|
|
|
let p_zero = Vector::<LANES>::splat(0.);
|
|
|
|
let n_zero = Vector::<LANES>::splat(-0.);
|
2022-03-13 14:07:36 -05:00
|
|
|
assert!(p_zero.simd_min(n_zero).to_array().iter().all(|x| *x == 0.));
|
|
|
|
assert!(n_zero.simd_min(p_zero).to_array().iter().all(|x| *x == 0.));
|
2021-06-13 14:47:32 -05:00
|
|
|
}
|
|
|
|
|
2022-03-13 14:07:36 -05:00
|
|
|
fn simd_max<const LANES: usize>() {
|
2021-06-13 14:47:32 -05:00
|
|
|
// Regular conditions (both values aren't zero)
|
|
|
|
test_helpers::test_binary_elementwise(
|
2022-03-13 14:07:36 -05:00
|
|
|
&Vector::<LANES>::simd_max,
|
2021-06-13 14:47:32 -05:00
|
|
|
&Scalar::max,
|
|
|
|
// Reject the case where both values are zero with different signs
|
|
|
|
&|a, b| {
|
|
|
|
for (a, b) in a.iter().zip(b.iter()) {
|
|
|
|
if *a == 0. && *b == 0. && a.signum() != b.signum() {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
true
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
// Special case where both values are zero
|
|
|
|
let p_zero = Vector::<LANES>::splat(0.);
|
|
|
|
let n_zero = Vector::<LANES>::splat(-0.);
|
2022-03-13 14:07:36 -05:00
|
|
|
assert!(p_zero.simd_max(n_zero).to_array().iter().all(|x| *x == 0.));
|
|
|
|
assert!(n_zero.simd_max(p_zero).to_array().iter().all(|x| *x == 0.));
|
2021-06-13 14:47:32 -05:00
|
|
|
}
|
|
|
|
|
2022-03-13 14:07:36 -05:00
|
|
|
fn simd_clamp<const LANES: usize>() {
|
2021-06-13 14:47:32 -05:00
|
|
|
test_helpers::test_3(&|value: [Scalar; LANES], mut min: [Scalar; LANES], mut max: [Scalar; LANES]| {
|
|
|
|
for (min, max) in min.iter_mut().zip(max.iter_mut()) {
|
|
|
|
if max < min {
|
|
|
|
core::mem::swap(min, max);
|
|
|
|
}
|
|
|
|
if min.is_nan() {
|
|
|
|
*min = Scalar::NEG_INFINITY;
|
|
|
|
}
|
|
|
|
if max.is_nan() {
|
|
|
|
*max = Scalar::INFINITY;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut result_scalar = [Scalar::default(); LANES];
|
|
|
|
for i in 0..LANES {
|
|
|
|
result_scalar[i] = value[i].clamp(min[i], max[i]);
|
|
|
|
}
|
2022-03-13 14:07:36 -05:00
|
|
|
let result_vector = Vector::from_array(value).simd_clamp(min.into(), max.into()).to_array();
|
2021-06-13 14:47:32 -05:00
|
|
|
test_helpers::prop_assert_biteq!(result_scalar, result_vector);
|
|
|
|
Ok(())
|
|
|
|
})
|
|
|
|
}
|
2021-06-13 13:45:45 -05:00
|
|
|
|
2022-03-11 16:49:06 -06:00
|
|
|
fn reduce_sum<const LANES: usize>() {
|
2021-03-07 23:48:18 -06:00
|
|
|
test_helpers::test_1(&|x| {
|
|
|
|
test_helpers::prop_assert_biteq! (
|
2022-03-11 16:49:06 -06:00
|
|
|
Vector::<LANES>::from_array(x).reduce_sum(),
|
2021-03-12 19:10:51 -06:00
|
|
|
x.iter().sum(),
|
2021-03-07 23:48:18 -06:00
|
|
|
);
|
|
|
|
Ok(())
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2022-03-11 16:49:06 -06:00
|
|
|
fn reduce_product<const LANES: usize>() {
|
2021-03-07 23:48:18 -06:00
|
|
|
test_helpers::test_1(&|x| {
|
|
|
|
test_helpers::prop_assert_biteq! (
|
2022-03-11 16:49:06 -06:00
|
|
|
Vector::<LANES>::from_array(x).reduce_product(),
|
2021-03-12 19:10:51 -06:00
|
|
|
x.iter().product(),
|
2021-03-07 23:48:18 -06:00
|
|
|
);
|
|
|
|
Ok(())
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2022-03-11 16:49:06 -06:00
|
|
|
fn reduce_max<const LANES: usize>() {
|
2021-03-07 23:48:18 -06:00
|
|
|
test_helpers::test_1(&|x| {
|
2022-03-11 16:49:06 -06:00
|
|
|
let vmax = Vector::<LANES>::from_array(x).reduce_max();
|
2021-03-10 22:47:43 -06:00
|
|
|
let smax = x.iter().copied().fold(Scalar::NAN, Scalar::max);
|
|
|
|
// 0 and -0 are treated the same
|
|
|
|
if !(x.contains(&0.) && x.contains(&-0.) && vmax.abs() == 0. && smax.abs() == 0.) {
|
|
|
|
test_helpers::prop_assert_biteq!(vmax, smax);
|
|
|
|
}
|
2021-03-07 23:48:18 -06:00
|
|
|
Ok(())
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2022-03-11 16:49:06 -06:00
|
|
|
fn reduce_min<const LANES: usize>() {
|
2021-03-07 23:48:18 -06:00
|
|
|
test_helpers::test_1(&|x| {
|
2022-03-11 16:49:06 -06:00
|
|
|
let vmax = Vector::<LANES>::from_array(x).reduce_min();
|
2021-03-10 22:47:43 -06:00
|
|
|
let smax = x.iter().copied().fold(Scalar::NAN, Scalar::min);
|
|
|
|
// 0 and -0 are treated the same
|
|
|
|
if !(x.contains(&0.) && x.contains(&-0.) && vmax.abs() == 0. && smax.abs() == 0.) {
|
|
|
|
test_helpers::prop_assert_biteq!(vmax, smax);
|
|
|
|
}
|
2021-03-07 23:48:18 -06:00
|
|
|
Ok(())
|
|
|
|
});
|
|
|
|
}
|
2021-02-13 13:19:16 -06:00
|
|
|
}
|
2021-07-27 23:19:31 -05:00
|
|
|
|
|
|
|
#[cfg(feature = "std")]
|
2021-09-21 20:55:05 -05:00
|
|
|
mod std {
|
2021-12-21 17:29:29 -06:00
|
|
|
use std_float::StdFloat;
|
|
|
|
|
2021-09-21 20:55:05 -05:00
|
|
|
use super::*;
|
|
|
|
test_helpers::test_lanes! {
|
|
|
|
fn sqrt<const LANES: usize>() {
|
|
|
|
test_helpers::test_unary_elementwise(
|
|
|
|
&Vector::<LANES>::sqrt,
|
|
|
|
&Scalar::sqrt,
|
|
|
|
&|_| true,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn mul_add<const LANES: usize>() {
|
|
|
|
test_helpers::test_ternary_elementwise(
|
|
|
|
&Vector::<LANES>::mul_add,
|
|
|
|
&Scalar::mul_add,
|
|
|
|
&|_, _, _| true,
|
|
|
|
)
|
|
|
|
}
|
2021-07-27 23:19:31 -05:00
|
|
|
}
|
|
|
|
}
|
2021-02-13 13:19:16 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|