]> git.lizzy.rs Git - rust.git/blob - library/portable-simd/crates/test_helpers/src/lib.rs
Rollup merge of #101420 - kraktus:doc_hir_local, r=cjgillot
[rust.git] / library / portable-simd / crates / test_helpers / src / lib.rs
1 pub mod array;
2
3 #[cfg(target_arch = "wasm32")]
4 pub mod wasm;
5
6 #[macro_use]
7 pub mod biteq;
8
9 /// Specifies the default strategy for testing a type.
10 ///
11 /// This strategy should be what "makes sense" to test.
12 pub trait DefaultStrategy {
13     type Strategy: proptest::strategy::Strategy<Value = Self>;
14     fn default_strategy() -> Self::Strategy;
15 }
16
17 macro_rules! impl_num {
18     { $type:tt } => {
19         impl DefaultStrategy for $type {
20             type Strategy = proptest::num::$type::Any;
21             fn default_strategy() -> Self::Strategy {
22                 proptest::num::$type::ANY
23             }
24         }
25     }
26 }
27
28 impl_num! { i8 }
29 impl_num! { i16 }
30 impl_num! { i32 }
31 impl_num! { i64 }
32 impl_num! { isize }
33 impl_num! { u8 }
34 impl_num! { u16 }
35 impl_num! { u32 }
36 impl_num! { u64 }
37 impl_num! { usize }
38 impl_num! { f32 }
39 impl_num! { f64 }
40
41 #[cfg(not(target_arch = "wasm32"))]
42 impl DefaultStrategy for u128 {
43     type Strategy = proptest::num::u128::Any;
44     fn default_strategy() -> Self::Strategy {
45         proptest::num::u128::ANY
46     }
47 }
48
49 #[cfg(not(target_arch = "wasm32"))]
50 impl DefaultStrategy for i128 {
51     type Strategy = proptest::num::i128::Any;
52     fn default_strategy() -> Self::Strategy {
53         proptest::num::i128::ANY
54     }
55 }
56
57 #[cfg(target_arch = "wasm32")]
58 impl DefaultStrategy for u128 {
59     type Strategy = crate::wasm::u128::Any;
60     fn default_strategy() -> Self::Strategy {
61         crate::wasm::u128::ANY
62     }
63 }
64
65 #[cfg(target_arch = "wasm32")]
66 impl DefaultStrategy for i128 {
67     type Strategy = crate::wasm::i128::Any;
68     fn default_strategy() -> Self::Strategy {
69         crate::wasm::i128::ANY
70     }
71 }
72
73 impl<T: core::fmt::Debug + DefaultStrategy, const LANES: usize> DefaultStrategy for [T; LANES] {
74     type Strategy = crate::array::UniformArrayStrategy<T::Strategy, Self>;
75     fn default_strategy() -> Self::Strategy {
76         Self::Strategy::new(T::default_strategy())
77     }
78 }
79
80 #[cfg(not(miri))]
81 pub fn make_runner() -> proptest::test_runner::TestRunner {
82     Default::default()
83 }
84 #[cfg(miri)]
85 pub fn make_runner() -> proptest::test_runner::TestRunner {
86     // Only run a few tests on Miri
87     proptest::test_runner::TestRunner::new(proptest::test_runner::Config::with_cases(4))
88 }
89
90 /// Test a function that takes a single value.
91 pub fn test_1<A: core::fmt::Debug + DefaultStrategy>(
92     f: &dyn Fn(A) -> proptest::test_runner::TestCaseResult,
93 ) {
94     let mut runner = make_runner();
95     runner.run(&A::default_strategy(), f).unwrap();
96 }
97
98 /// Test a function that takes two values.
99 pub fn test_2<A: core::fmt::Debug + DefaultStrategy, B: core::fmt::Debug + DefaultStrategy>(
100     f: &dyn Fn(A, B) -> proptest::test_runner::TestCaseResult,
101 ) {
102     let mut runner = make_runner();
103     runner
104         .run(&(A::default_strategy(), B::default_strategy()), |(a, b)| {
105             f(a, b)
106         })
107         .unwrap();
108 }
109
110 /// Test a function that takes two values.
111 pub fn test_3<
112     A: core::fmt::Debug + DefaultStrategy,
113     B: core::fmt::Debug + DefaultStrategy,
114     C: core::fmt::Debug + DefaultStrategy,
115 >(
116     f: &dyn Fn(A, B, C) -> proptest::test_runner::TestCaseResult,
117 ) {
118     let mut runner = make_runner();
119     runner
120         .run(
121             &(
122                 A::default_strategy(),
123                 B::default_strategy(),
124                 C::default_strategy(),
125             ),
126             |(a, b, c)| f(a, b, c),
127         )
128         .unwrap();
129 }
130
131 /// Test a unary vector function against a unary scalar function, applied elementwise.
132 #[inline(never)]
133 pub fn test_unary_elementwise<Scalar, ScalarResult, Vector, VectorResult, const LANES: usize>(
134     fv: &dyn Fn(Vector) -> VectorResult,
135     fs: &dyn Fn(Scalar) -> ScalarResult,
136     check: &dyn Fn([Scalar; LANES]) -> bool,
137 ) where
138     Scalar: Copy + Default + core::fmt::Debug + DefaultStrategy,
139     ScalarResult: Copy + Default + biteq::BitEq + core::fmt::Debug + DefaultStrategy,
140     Vector: Into<[Scalar; LANES]> + From<[Scalar; LANES]> + Copy,
141     VectorResult: Into<[ScalarResult; LANES]> + From<[ScalarResult; LANES]> + Copy,
142 {
143     test_1(&|x: [Scalar; LANES]| {
144         proptest::prop_assume!(check(x));
145         let result_1: [ScalarResult; LANES] = fv(x.into()).into();
146         let result_2: [ScalarResult; LANES] = {
147             let mut result = [ScalarResult::default(); LANES];
148             for (i, o) in x.iter().zip(result.iter_mut()) {
149                 *o = fs(*i);
150             }
151             result
152         };
153         crate::prop_assert_biteq!(result_1, result_2);
154         Ok(())
155     });
156 }
157
158 /// Test a unary vector function against a unary scalar function, applied elementwise.
159 #[inline(never)]
160 pub fn test_unary_mask_elementwise<Scalar, Vector, Mask, const LANES: usize>(
161     fv: &dyn Fn(Vector) -> Mask,
162     fs: &dyn Fn(Scalar) -> bool,
163     check: &dyn Fn([Scalar; LANES]) -> bool,
164 ) where
165     Scalar: Copy + Default + core::fmt::Debug + DefaultStrategy,
166     Vector: Into<[Scalar; LANES]> + From<[Scalar; LANES]> + Copy,
167     Mask: Into<[bool; LANES]> + From<[bool; LANES]> + Copy,
168 {
169     test_1(&|x: [Scalar; LANES]| {
170         proptest::prop_assume!(check(x));
171         let result_1: [bool; LANES] = fv(x.into()).into();
172         let result_2: [bool; LANES] = {
173             let mut result = [false; LANES];
174             for (i, o) in x.iter().zip(result.iter_mut()) {
175                 *o = fs(*i);
176             }
177             result
178         };
179         crate::prop_assert_biteq!(result_1, result_2);
180         Ok(())
181     });
182 }
183
184 /// Test a binary vector function against a binary scalar function, applied elementwise.
185 #[inline(never)]
186 pub fn test_binary_elementwise<
187     Scalar1,
188     Scalar2,
189     ScalarResult,
190     Vector1,
191     Vector2,
192     VectorResult,
193     const LANES: usize,
194 >(
195     fv: &dyn Fn(Vector1, Vector2) -> VectorResult,
196     fs: &dyn Fn(Scalar1, Scalar2) -> ScalarResult,
197     check: &dyn Fn([Scalar1; LANES], [Scalar2; LANES]) -> bool,
198 ) where
199     Scalar1: Copy + Default + core::fmt::Debug + DefaultStrategy,
200     Scalar2: Copy + Default + core::fmt::Debug + DefaultStrategy,
201     ScalarResult: Copy + Default + biteq::BitEq + core::fmt::Debug + DefaultStrategy,
202     Vector1: Into<[Scalar1; LANES]> + From<[Scalar1; LANES]> + Copy,
203     Vector2: Into<[Scalar2; LANES]> + From<[Scalar2; LANES]> + Copy,
204     VectorResult: Into<[ScalarResult; LANES]> + From<[ScalarResult; LANES]> + Copy,
205 {
206     test_2(&|x: [Scalar1; LANES], y: [Scalar2; LANES]| {
207         proptest::prop_assume!(check(x, y));
208         let result_1: [ScalarResult; LANES] = fv(x.into(), y.into()).into();
209         let result_2: [ScalarResult; LANES] = {
210             let mut result = [ScalarResult::default(); LANES];
211             for ((i1, i2), o) in x.iter().zip(y.iter()).zip(result.iter_mut()) {
212                 *o = fs(*i1, *i2);
213             }
214             result
215         };
216         crate::prop_assert_biteq!(result_1, result_2);
217         Ok(())
218     });
219 }
220
221 /// Test a binary vector-scalar function against a binary scalar function, applied elementwise.
222 #[inline(never)]
223 pub fn test_binary_scalar_rhs_elementwise<
224     Scalar1,
225     Scalar2,
226     ScalarResult,
227     Vector,
228     VectorResult,
229     const LANES: usize,
230 >(
231     fv: &dyn Fn(Vector, Scalar2) -> VectorResult,
232     fs: &dyn Fn(Scalar1, Scalar2) -> ScalarResult,
233     check: &dyn Fn([Scalar1; LANES], Scalar2) -> bool,
234 ) where
235     Scalar1: Copy + Default + core::fmt::Debug + DefaultStrategy,
236     Scalar2: Copy + Default + core::fmt::Debug + DefaultStrategy,
237     ScalarResult: Copy + Default + biteq::BitEq + core::fmt::Debug + DefaultStrategy,
238     Vector: Into<[Scalar1; LANES]> + From<[Scalar1; LANES]> + Copy,
239     VectorResult: Into<[ScalarResult; LANES]> + From<[ScalarResult; LANES]> + Copy,
240 {
241     test_2(&|x: [Scalar1; LANES], y: Scalar2| {
242         proptest::prop_assume!(check(x, y));
243         let result_1: [ScalarResult; LANES] = fv(x.into(), y).into();
244         let result_2: [ScalarResult; LANES] = {
245             let mut result = [ScalarResult::default(); LANES];
246             for (i, o) in x.iter().zip(result.iter_mut()) {
247                 *o = fs(*i, y);
248             }
249             result
250         };
251         crate::prop_assert_biteq!(result_1, result_2);
252         Ok(())
253     });
254 }
255
256 /// Test a binary vector-scalar function against a binary scalar function, applied elementwise.
257 #[inline(never)]
258 pub fn test_binary_scalar_lhs_elementwise<
259     Scalar1,
260     Scalar2,
261     ScalarResult,
262     Vector,
263     VectorResult,
264     const LANES: usize,
265 >(
266     fv: &dyn Fn(Scalar1, Vector) -> VectorResult,
267     fs: &dyn Fn(Scalar1, Scalar2) -> ScalarResult,
268     check: &dyn Fn(Scalar1, [Scalar2; LANES]) -> bool,
269 ) where
270     Scalar1: Copy + Default + core::fmt::Debug + DefaultStrategy,
271     Scalar2: Copy + Default + core::fmt::Debug + DefaultStrategy,
272     ScalarResult: Copy + Default + biteq::BitEq + core::fmt::Debug + DefaultStrategy,
273     Vector: Into<[Scalar2; LANES]> + From<[Scalar2; LANES]> + Copy,
274     VectorResult: Into<[ScalarResult; LANES]> + From<[ScalarResult; LANES]> + Copy,
275 {
276     test_2(&|x: Scalar1, y: [Scalar2; LANES]| {
277         proptest::prop_assume!(check(x, y));
278         let result_1: [ScalarResult; LANES] = fv(x, y.into()).into();
279         let result_2: [ScalarResult; LANES] = {
280             let mut result = [ScalarResult::default(); LANES];
281             for (i, o) in y.iter().zip(result.iter_mut()) {
282                 *o = fs(x, *i);
283             }
284             result
285         };
286         crate::prop_assert_biteq!(result_1, result_2);
287         Ok(())
288     });
289 }
290
291 /// Test a ternary vector function against a ternary scalar function, applied elementwise.
292 #[inline(never)]
293 pub fn test_ternary_elementwise<
294     Scalar1,
295     Scalar2,
296     Scalar3,
297     ScalarResult,
298     Vector1,
299     Vector2,
300     Vector3,
301     VectorResult,
302     const LANES: usize,
303 >(
304     fv: &dyn Fn(Vector1, Vector2, Vector3) -> VectorResult,
305     fs: &dyn Fn(Scalar1, Scalar2, Scalar3) -> ScalarResult,
306     check: &dyn Fn([Scalar1; LANES], [Scalar2; LANES], [Scalar3; LANES]) -> bool,
307 ) where
308     Scalar1: Copy + Default + core::fmt::Debug + DefaultStrategy,
309     Scalar2: Copy + Default + core::fmt::Debug + DefaultStrategy,
310     Scalar3: Copy + Default + core::fmt::Debug + DefaultStrategy,
311     ScalarResult: Copy + Default + biteq::BitEq + core::fmt::Debug + DefaultStrategy,
312     Vector1: Into<[Scalar1; LANES]> + From<[Scalar1; LANES]> + Copy,
313     Vector2: Into<[Scalar2; LANES]> + From<[Scalar2; LANES]> + Copy,
314     Vector3: Into<[Scalar3; LANES]> + From<[Scalar3; LANES]> + Copy,
315     VectorResult: Into<[ScalarResult; LANES]> + From<[ScalarResult; LANES]> + Copy,
316 {
317     test_3(
318         &|x: [Scalar1; LANES], y: [Scalar2; LANES], z: [Scalar3; LANES]| {
319             proptest::prop_assume!(check(x, y, z));
320             let result_1: [ScalarResult; LANES] = fv(x.into(), y.into(), z.into()).into();
321             let result_2: [ScalarResult; LANES] = {
322                 let mut result = [ScalarResult::default(); LANES];
323                 for ((i1, (i2, i3)), o) in
324                     x.iter().zip(y.iter().zip(z.iter())).zip(result.iter_mut())
325                 {
326                     *o = fs(*i1, *i2, *i3);
327                 }
328                 result
329             };
330             crate::prop_assert_biteq!(result_1, result_2);
331             Ok(())
332         },
333     );
334 }
335
336 /// Expand a const-generic test into separate tests for each possible lane count.
337 #[macro_export]
338 macro_rules! test_lanes {
339     {
340         $(fn $test:ident<const $lanes:ident: usize>() $body:tt)*
341     } => {
342         $(
343             mod $test {
344                 use super::*;
345
346                 fn implementation<const $lanes: usize>()
347                 where
348                     core_simd::LaneCount<$lanes>: core_simd::SupportedLaneCount,
349                 $body
350
351                 #[cfg(target_arch = "wasm32")]
352                 wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser);
353
354                 #[test]
355                 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
356                 fn lanes_1() {
357                     implementation::<1>();
358                 }
359
360                 #[test]
361                 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
362                 fn lanes_2() {
363                     implementation::<2>();
364                 }
365
366                 #[test]
367                 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
368                 fn lanes_4() {
369                     implementation::<4>();
370                 }
371
372                 #[test]
373                 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
374                 #[cfg(not(miri))] // Miri intrinsic implementations are uniform and larger tests are sloooow
375                 fn lanes_8() {
376                     implementation::<8>();
377                 }
378
379                 #[test]
380                 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
381                 #[cfg(not(miri))] // Miri intrinsic implementations are uniform and larger tests are sloooow
382                 fn lanes_16() {
383                     implementation::<16>();
384                 }
385
386                 #[test]
387                 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
388                 #[cfg(not(miri))] // Miri intrinsic implementations are uniform and larger tests are sloooow
389                 fn lanes_32() {
390                     implementation::<32>();
391                 }
392
393                 #[test]
394                 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
395                 #[cfg(not(miri))] // Miri intrinsic implementations are uniform and larger tests are sloooow
396                 fn lanes_64() {
397                     implementation::<64>();
398                 }
399             }
400         )*
401     }
402 }
403
404 /// Expand a const-generic `#[should_panic]` test into separate tests for each possible lane count.
405 #[macro_export]
406 macro_rules! test_lanes_panic {
407     {
408         $(fn $test:ident<const $lanes:ident: usize>() $body:tt)*
409     } => {
410         $(
411             mod $test {
412                 use super::*;
413
414                 fn implementation<const $lanes: usize>()
415                 where
416                     core_simd::LaneCount<$lanes>: core_simd::SupportedLaneCount,
417                 $body
418
419                 #[test]
420                 #[should_panic]
421                 fn lanes_1() {
422                     implementation::<1>();
423                 }
424
425                 #[test]
426                 #[should_panic]
427                 fn lanes_2() {
428                     implementation::<2>();
429                 }
430
431                 #[test]
432                 #[should_panic]
433                 fn lanes_4() {
434                     implementation::<4>();
435                 }
436
437                 #[test]
438                 #[should_panic]
439                 fn lanes_8() {
440                     implementation::<8>();
441                 }
442
443                 #[test]
444                 #[should_panic]
445                 fn lanes_16() {
446                     implementation::<16>();
447                 }
448
449                 #[test]
450                 #[should_panic]
451                 fn lanes_32() {
452                     implementation::<32>();
453                 }
454
455                 #[test]
456                 #[should_panic]
457                 fn lanes_64() {
458                     implementation::<64>();
459                 }
460             }
461         )*
462     }
463 }