1 /// Implements a test on a unary operation using proptest.
3 /// Compares the vector operation to the equivalent scalar operation.
5 macro_rules! impl_unary_op_test {
6 { $vector:ty, $scalar:ty, $trait:ident :: $fn:ident, $scalar_fn:expr } => {
7 test_helpers::test_lanes! {
8 fn $fn<const LANES: usize>() {
9 test_helpers::test_unary_elementwise(
10 &<$vector as core::ops::$trait>::$fn,
17 { $vector:ty, $scalar:ty, $trait:ident :: $fn:ident } => {
18 impl_unary_op_test! { $vector, $scalar, $trait::$fn, <$scalar as core::ops::$trait>::$fn }
22 /// Implements a test on a binary operation using proptest.
24 /// Compares the vector operation to the equivalent scalar operation.
26 macro_rules! impl_binary_op_test {
27 { $vector:ty, $scalar:ty, $trait:ident :: $fn:ident, $trait_assign:ident :: $fn_assign:ident, $scalar_fn:expr } => {
31 test_helpers::test_lanes! {
32 fn normal<const LANES: usize>() {
33 test_helpers::test_binary_elementwise(
34 &<$vector as core::ops::$trait>::$fn,
40 fn scalar_rhs<const LANES: usize>() {
41 test_helpers::test_binary_scalar_rhs_elementwise(
42 &<$vector as core::ops::$trait<$scalar>>::$fn,
48 fn scalar_lhs<const LANES: usize>() {
49 test_helpers::test_binary_scalar_lhs_elementwise(
50 &<$scalar as core::ops::$trait<$vector>>::$fn,
56 fn assign<const LANES: usize>() {
57 test_helpers::test_binary_elementwise(
58 &|mut a, b| { <$vector as core::ops::$trait_assign>::$fn_assign(&mut a, b); a },
64 fn assign_scalar_rhs<const LANES: usize>() {
65 test_helpers::test_binary_scalar_rhs_elementwise(
66 &|mut a, b| { <$vector as core::ops::$trait_assign<$scalar>>::$fn_assign(&mut a, b); a },
74 { $vector:ty, $scalar:ty, $trait:ident :: $fn:ident, $trait_assign:ident :: $fn_assign:ident } => {
75 impl_binary_op_test! { $vector, $scalar, $trait::$fn, $trait_assign::$fn_assign, <$scalar as core::ops::$trait>::$fn }
79 /// Implements a test on a binary operation using proptest.
81 /// Like `impl_binary_op_test`, but allows providing a function for rejecting particular inputs
82 /// (like the `proptest_assume` macro).
84 /// Compares the vector operation to the equivalent scalar operation.
86 macro_rules! impl_binary_checked_op_test {
87 { $vector:ty, $scalar:ty, $trait:ident :: $fn:ident, $trait_assign:ident :: $fn_assign:ident, $scalar_fn:expr, $check_fn:expr } => {
91 test_helpers::test_lanes! {
92 fn normal<const LANES: usize>() {
93 test_helpers::test_binary_elementwise(
94 &<$vector as core::ops::$trait>::$fn,
96 &|x, y| x.iter().zip(y.iter()).all(|(x, y)| $check_fn(*x, *y)),
100 fn scalar_rhs<const LANES: usize>() {
101 test_helpers::test_binary_scalar_rhs_elementwise(
102 &<$vector as core::ops::$trait<$scalar>>::$fn,
104 &|x, y| x.iter().all(|x| $check_fn(*x, y)),
108 fn scalar_lhs<const LANES: usize>() {
109 test_helpers::test_binary_scalar_lhs_elementwise(
110 &<$scalar as core::ops::$trait<$vector>>::$fn,
112 &|x, y| y.iter().all(|y| $check_fn(x, *y)),
116 fn assign<const LANES: usize>() {
117 test_helpers::test_binary_elementwise(
118 &|mut a, b| { <$vector as core::ops::$trait_assign>::$fn_assign(&mut a, b); a },
120 &|x, y| x.iter().zip(y.iter()).all(|(x, y)| $check_fn(*x, *y)),
124 fn assign_scalar_rhs<const LANES: usize>() {
125 test_helpers::test_binary_scalar_rhs_elementwise(
126 &|mut a, b| { <$vector as core::ops::$trait_assign<$scalar>>::$fn_assign(&mut a, b); a },
128 &|x, y| x.iter().all(|x| $check_fn(*x, y)),
134 { $vector:ty, $scalar:ty, $trait:ident :: $fn:ident, $trait_assign:ident :: $fn_assign:ident, $check_fn:expr } => {
135 impl_binary_nonzero_rhs_op_test! { $vector, $scalar, $trait::$fn, $trait_assign::$fn_assign, <$scalar as core::ops::$trait>::$fn, $check_fn }
140 macro_rules! impl_common_integer_tests {
141 { $vector:ident, $scalar:ident } => {
142 test_helpers::test_lanes! {
143 fn horizontal_sum<const LANES: usize>() {
144 test_helpers::test_1(&|x| {
145 test_helpers::prop_assert_biteq! (
146 $vector::<LANES>::from_array(x).horizontal_sum(),
147 x.iter().copied().fold(0 as $scalar, $scalar::wrapping_add),
153 fn horizontal_product<const LANES: usize>() {
154 test_helpers::test_1(&|x| {
155 test_helpers::prop_assert_biteq! (
156 $vector::<LANES>::from_array(x).horizontal_product(),
157 x.iter().copied().fold(1 as $scalar, $scalar::wrapping_mul),
163 fn horizontal_and<const LANES: usize>() {
164 test_helpers::test_1(&|x| {
165 test_helpers::prop_assert_biteq! (
166 $vector::<LANES>::from_array(x).horizontal_and(),
167 x.iter().copied().fold(-1i8 as $scalar, <$scalar as core::ops::BitAnd>::bitand),
173 fn horizontal_or<const LANES: usize>() {
174 test_helpers::test_1(&|x| {
175 test_helpers::prop_assert_biteq! (
176 $vector::<LANES>::from_array(x).horizontal_or(),
177 x.iter().copied().fold(0 as $scalar, <$scalar as core::ops::BitOr>::bitor),
183 fn horizontal_xor<const LANES: usize>() {
184 test_helpers::test_1(&|x| {
185 test_helpers::prop_assert_biteq! (
186 $vector::<LANES>::from_array(x).horizontal_xor(),
187 x.iter().copied().fold(0 as $scalar, <$scalar as core::ops::BitXor>::bitxor),
193 fn horizontal_max<const LANES: usize>() {
194 test_helpers::test_1(&|x| {
195 test_helpers::prop_assert_biteq! (
196 $vector::<LANES>::from_array(x).horizontal_max(),
197 x.iter().copied().max().unwrap(),
203 fn horizontal_min<const LANES: usize>() {
204 test_helpers::test_1(&|x| {
205 test_helpers::prop_assert_biteq! (
206 $vector::<LANES>::from_array(x).horizontal_min(),
207 x.iter().copied().min().unwrap(),
216 /// Implement tests for signed integers.
218 macro_rules! impl_signed_tests {
219 { $vector:ident, $scalar:tt } => {
221 type Vector<const LANES: usize> = core_simd::$vector<LANES>;
222 type Scalar = $scalar;
224 impl_common_integer_tests! { Vector, Scalar }
226 test_helpers::test_lanes! {
227 fn neg<const LANES: usize>() {
228 test_helpers::test_unary_elementwise(
229 &<Vector::<LANES> as core::ops::Neg>::neg,
230 &<Scalar as core::ops::Neg>::neg,
231 &|x| !x.contains(&Scalar::MIN),
235 fn is_positive<const LANES: usize>() {
236 test_helpers::test_unary_mask_elementwise(
237 &Vector::<LANES>::is_positive,
238 &Scalar::is_positive,
243 fn is_negative<const LANES: usize>() {
244 test_helpers::test_unary_mask_elementwise(
245 &Vector::<LANES>::is_negative,
246 &Scalar::is_negative,
252 test_helpers::test_lanes_panic! {
253 fn div_min_overflow_panics<const LANES: usize>() {
254 let a = Vector::<LANES>::splat(Scalar::MIN);
255 let b = Vector::<LANES>::splat(-1);
259 fn div_by_all_zeros_panics<const LANES: usize>() {
260 let a = Vector::<LANES>::splat(42);
261 let b = Vector::<LANES>::splat(0);
265 fn div_by_one_zero_panics<const LANES: usize>() {
266 let a = Vector::<LANES>::splat(42);
267 let mut b = Vector::<LANES>::splat(21);
272 fn rem_min_overflow_panic<const LANES: usize>() {
273 let a = Vector::<LANES>::splat(Scalar::MIN);
274 let b = Vector::<LANES>::splat(-1);
278 fn rem_zero_panic<const LANES: usize>() {
279 let a = Vector::<LANES>::splat(42);
280 let b = Vector::<LANES>::splat(0);
285 test_helpers::test_lanes! {
286 fn div_neg_one_no_panic<const LANES: usize>() {
287 let a = Vector::<LANES>::splat(42);
288 let b = Vector::<LANES>::splat(-1);
292 fn rem_neg_one_no_panic<const LANES: usize>() {
293 let a = Vector::<LANES>::splat(42);
294 let b = Vector::<LANES>::splat(-1);
299 impl_binary_op_test!(Vector<LANES>, Scalar, Add::add, AddAssign::add_assign, Scalar::wrapping_add);
300 impl_binary_op_test!(Vector<LANES>, Scalar, Sub::sub, SubAssign::sub_assign, Scalar::wrapping_sub);
301 impl_binary_op_test!(Vector<LANES>, Scalar, Mul::mul, MulAssign::mul_assign, Scalar::wrapping_mul);
303 // Exclude Div and Rem panicking cases
304 impl_binary_checked_op_test!(Vector<LANES>, Scalar, Div::div, DivAssign::div_assign, Scalar::wrapping_div, |x, y| y != 0 && !(x == Scalar::MIN && y == -1));
305 impl_binary_checked_op_test!(Vector<LANES>, Scalar, Rem::rem, RemAssign::rem_assign, Scalar::wrapping_rem, |x, y| y != 0 && !(x == Scalar::MIN && y == -1));
307 impl_unary_op_test!(Vector<LANES>, Scalar, Not::not);
308 impl_binary_op_test!(Vector<LANES>, Scalar, BitAnd::bitand, BitAndAssign::bitand_assign);
309 impl_binary_op_test!(Vector<LANES>, Scalar, BitOr::bitor, BitOrAssign::bitor_assign);
310 impl_binary_op_test!(Vector<LANES>, Scalar, BitXor::bitxor, BitXorAssign::bitxor_assign);
315 /// Implement tests for unsigned integers.
317 macro_rules! impl_unsigned_tests {
318 { $vector:ident, $scalar:tt } => {
320 type Vector<const LANES: usize> = core_simd::$vector<LANES>;
321 type Scalar = $scalar;
323 impl_common_integer_tests! { Vector, Scalar }
325 test_helpers::test_lanes_panic! {
326 fn rem_zero_panic<const LANES: usize>() {
327 let a = Vector::<LANES>::splat(42);
328 let b = Vector::<LANES>::splat(0);
333 impl_binary_op_test!(Vector<LANES>, Scalar, Add::add, AddAssign::add_assign, Scalar::wrapping_add);
334 impl_binary_op_test!(Vector<LANES>, Scalar, Sub::sub, SubAssign::sub_assign, Scalar::wrapping_sub);
335 impl_binary_op_test!(Vector<LANES>, Scalar, Mul::mul, MulAssign::mul_assign, Scalar::wrapping_mul);
337 // Exclude Div and Rem panicking cases
338 impl_binary_checked_op_test!(Vector<LANES>, Scalar, Div::div, DivAssign::div_assign, Scalar::wrapping_div, |_, y| y != 0);
339 impl_binary_checked_op_test!(Vector<LANES>, Scalar, Rem::rem, RemAssign::rem_assign, Scalar::wrapping_rem, |_, y| y != 0);
341 impl_unary_op_test!(Vector<LANES>, Scalar, Not::not);
342 impl_binary_op_test!(Vector<LANES>, Scalar, BitAnd::bitand, BitAndAssign::bitand_assign);
343 impl_binary_op_test!(Vector<LANES>, Scalar, BitOr::bitor, BitOrAssign::bitor_assign);
344 impl_binary_op_test!(Vector<LANES>, Scalar, BitXor::bitxor, BitXorAssign::bitxor_assign);
349 /// Implement tests for floating point numbers.
351 macro_rules! impl_float_tests {
352 { $vector:ident, $scalar:tt, $int_scalar:tt } => {
354 type Vector<const LANES: usize> = core_simd::$vector<LANES>;
355 type Scalar = $scalar;
357 impl_unary_op_test!(Vector<LANES>, Scalar, Neg::neg);
358 impl_binary_op_test!(Vector<LANES>, Scalar, Add::add, AddAssign::add_assign);
359 impl_binary_op_test!(Vector<LANES>, Scalar, Sub::sub, SubAssign::sub_assign);
360 impl_binary_op_test!(Vector<LANES>, Scalar, Mul::mul, MulAssign::mul_assign);
361 impl_binary_op_test!(Vector<LANES>, Scalar, Div::div, DivAssign::div_assign);
362 impl_binary_op_test!(Vector<LANES>, Scalar, Rem::rem, RemAssign::rem_assign);
364 test_helpers::test_lanes! {
365 fn is_sign_positive<const LANES: usize>() {
366 test_helpers::test_unary_mask_elementwise(
367 &Vector::<LANES>::is_sign_positive,
368 &Scalar::is_sign_positive,
373 fn is_sign_negative<const LANES: usize>() {
374 test_helpers::test_unary_mask_elementwise(
375 &Vector::<LANES>::is_sign_negative,
376 &Scalar::is_sign_negative,
381 fn is_finite<const LANES: usize>() {
382 test_helpers::test_unary_mask_elementwise(
383 &Vector::<LANES>::is_finite,
389 fn is_infinite<const LANES: usize>() {
390 test_helpers::test_unary_mask_elementwise(
391 &Vector::<LANES>::is_infinite,
392 &Scalar::is_infinite,
397 fn is_nan<const LANES: usize>() {
398 test_helpers::test_unary_mask_elementwise(
399 &Vector::<LANES>::is_nan,
405 fn is_normal<const LANES: usize>() {
406 test_helpers::test_unary_mask_elementwise(
407 &Vector::<LANES>::is_normal,
413 fn is_subnormal<const LANES: usize>() {
414 test_helpers::test_unary_mask_elementwise(
415 &Vector::<LANES>::is_subnormal,
416 &Scalar::is_subnormal,
421 fn abs<const LANES: usize>() {
422 test_helpers::test_unary_elementwise(
423 &Vector::<LANES>::abs,
429 fn horizontal_sum<const LANES: usize>() {
430 test_helpers::test_1(&|x| {
431 test_helpers::prop_assert_biteq! (
432 Vector::<LANES>::from_array(x).horizontal_sum(),
439 fn horizontal_product<const LANES: usize>() {
440 test_helpers::test_1(&|x| {
441 test_helpers::prop_assert_biteq! (
442 Vector::<LANES>::from_array(x).horizontal_product(),
449 fn horizontal_max<const LANES: usize>() {
450 test_helpers::test_1(&|x| {
451 let vmax = Vector::<LANES>::from_array(x).horizontal_max();
452 let smax = x.iter().copied().fold(Scalar::NAN, Scalar::max);
453 // 0 and -0 are treated the same
454 if !(x.contains(&0.) && x.contains(&-0.) && vmax.abs() == 0. && smax.abs() == 0.) {
455 test_helpers::prop_assert_biteq!(vmax, smax);
461 fn horizontal_min<const LANES: usize>() {
462 test_helpers::test_1(&|x| {
463 let vmax = Vector::<LANES>::from_array(x).horizontal_min();
464 let smax = x.iter().copied().fold(Scalar::NAN, Scalar::min);
465 // 0 and -0 are treated the same
466 if !(x.contains(&0.) && x.contains(&-0.) && vmax.abs() == 0. && smax.abs() == 0.) {
467 test_helpers::prop_assert_biteq!(vmax, smax);