1 use lazy_static::lazy_static;
2 use lightbeam::{translate, ExecutableModule};
3 use quickcheck::quickcheck;
4
translate_wat(wat: &str) -> ExecutableModule5 fn translate_wat(wat: &str) -> ExecutableModule {
6 let wasm = wat::parse_str(wat).unwrap();
7 let compiled = translate(&wasm).unwrap();
8 compiled
9 }
10
11 mod op32 {
12 use super::{lazy_static, quickcheck, translate_wat, ExecutableModule};
13
14 macro_rules! binop_test {
15 ($op:ident, $func:expr) => {
16 mod $op {
17 use super::{lazy_static, quickcheck, translate_wat, ExecutableModule};
18 use std::sync::Once;
19
20 const OP: &str = stringify!($op);
21
22 lazy_static! {
23 static ref AS_PARAMS: ExecutableModule = translate_wat(&format!(
24 "(module (func (param i32) (param i32) (result i32)
25 (i32.{op} (get_local 0) (get_local 1))))",
26 op = OP
27 ));
28 }
29
30 quickcheck! {
31 fn as_params(a: i32, b: i32) -> bool {
32 AS_PARAMS.execute_func::<(i32, i32), i32>(0, (a, b)) == Ok($func(a, b))
33 }
34
35 fn lit_lit(a: i32, b: i32) -> bool {
36 let translated = translate_wat(&format!("
37 (module (func (result i32)
38 (i32.{op} (i32.const {left}) (i32.const {right}))))
39 ", op = OP, left = a, right = b));
40 static ONCE: Once = Once::new();
41 ONCE.call_once(|| translated.disassemble());
42
43 translated.execute_func::<(), i32>(0, ()) == Ok($func(a, b))
44 }
45
46 fn lit_reg(a: i32, b: i32) -> bool {
47 let translated = translate_wat(&format!("
48 (module (func (param i32) (result i32)
49 (i32.{op} (i32.const {left}) (get_local 0))))
50 ", op = OP, left = a));
51 static ONCE: Once = Once::new();
52 ONCE.call_once(|| translated.disassemble());
53
54 translated.execute_func::<(i32,), i32>(0, (b,)) == Ok($func(a, b))
55 }
56
57 fn reg_lit(a: i32, b: i32) -> bool {
58 let translated = translate_wat(&format!("
59 (module (func (param i32) (result i32)
60 (i32.{op} (get_local 0) (i32.const {right}))))
61 ", op = OP, right = b));
62 static ONCE: Once = Once::new();
63 ONCE.call_once(|| translated.disassemble());
64
65 translated.execute_func::<(i32,), i32>(0, (a,)) == Ok($func(a, b))
66 }
67 }
68 }
69 };
70 }
71
72 macro_rules! unop_test {
73 ($name:ident, $func:expr) => {
74 mod $name {
75 use super::{lazy_static, quickcheck, translate_wat, ExecutableModule};
76 use std::sync::Once;
77
78 lazy_static! {
79 static ref AS_PARAM: ExecutableModule = translate_wat(concat!(
80 "(module (func (param i32) (result i32)
81 (i32.",
82 stringify!($name),
83 " (get_local 0))))"
84 ),);
85 }
86
87 quickcheck! {
88 fn as_param(a: u32) -> bool {
89 AS_PARAM.execute_func::<(u32,), u32>(0, (a,)) == Ok($func(a))
90 }
91
92 fn lit(a: u32) -> bool {
93 let translated = translate_wat(&format!(concat!("
94 (module (func (result i32)
95 (i32.",stringify!($name)," (i32.const {val}))))
96 "), val = a));
97 static ONCE: Once = Once::new();
98 ONCE.call_once(|| translated.disassemble());
99
100 translated.execute_func::<(), u32>(0, ()) == Ok($func(a))
101 }
102 }
103 }
104 };
105 }
106
107 unop_test!(clz, u32::leading_zeros);
108 unop_test!(ctz, u32::trailing_zeros);
109 unop_test!(popcnt, u32::count_ones);
110 unop_test!(eqz, |a: u32| if a == 0 { 1 } else { 0 });
111
112 binop_test!(add, i32::wrapping_add);
113 binop_test!(sub, i32::wrapping_sub);
114 binop_test!(and, std::ops::BitAnd::bitand);
115 binop_test!(or, std::ops::BitOr::bitor);
116 binop_test!(xor, std::ops::BitXor::bitxor);
117 binop_test!(mul, i32::wrapping_mul);
118 binop_test!(eq, |a, b| if a == b { 1 } else { 0 });
119 binop_test!(ne, |a, b| if a != b { 1 } else { 0 });
120 binop_test!(lt_u, |a, b| if (a as u32) < (b as u32) { 1 } else { 0 });
121 binop_test!(le_u, |a, b| if (a as u32) <= (b as u32) { 1 } else { 0 });
122 binop_test!(gt_u, |a, b| if (a as u32) > (b as u32) { 1 } else { 0 });
123 binop_test!(ge_u, |a, b| if (a as u32) >= (b as u32) { 1 } else { 0 });
124 binop_test!(lt_s, |a, b| if a < b { 1 } else { 0 });
125 binop_test!(le_s, |a, b| if a <= b { 1 } else { 0 });
126 binop_test!(gt_s, |a, b| if a > b { 1 } else { 0 });
127 binop_test!(ge_s, |a, b| if a >= b { 1 } else { 0 });
128 binop_test!(shl, |a, b| (a as i32).wrapping_shl(b as _));
129 binop_test!(shr_s, |a, b| (a as i32).wrapping_shr(b as _));
130 binop_test!(shr_u, |a, b| (a as u32).wrapping_shr(b as _) as i32);
131 binop_test!(rotl, |a, b| (a as u32).rotate_left(b as _) as i32);
132 binop_test!(rotr, |a, b| (a as u32).rotate_right(b as _) as i32);
133 }
134
135 mod op64 {
136 use super::{lazy_static, quickcheck, translate_wat, ExecutableModule};
137
138 macro_rules! binop_test {
139 ($op:ident, $func:expr) => {
140 binop_test!($op, $func, i64);
141 };
142 ($op:ident, $func:expr, $retty:ident) => {
143 mod $op {
144 use super::{translate_wat, ExecutableModule, quickcheck, lazy_static};
145
146 const RETTY: &str = stringify!($retty);
147 const OP: &str = stringify!($op);
148
149 lazy_static! {
150 static ref AS_PARAMS: ExecutableModule = translate_wat(&format!("
151 (module (func (param i64) (param i64) (result {retty})
152 (i64.{op} (get_local 0) (get_local 1))))
153 ", retty = RETTY, op = OP));
154 }
155
156 quickcheck! {
157 fn as_params(a: i64, b: i64) -> bool {
158 AS_PARAMS.execute_func::<(i64, i64), $retty>(0, (a, b)) == Ok($func(a, b) as $retty)
159 }
160
161 fn lit_lit(a: i64, b: i64) -> bool {
162 translate_wat(&format!("
163 (module (func (result {retty})
164 (i64.{op} (i64.const {left}) (i64.const {right}))))
165 ", retty = RETTY, op = OP, left = a, right = b)).execute_func::<(), $retty>(0, ()) == Ok($func(a, b) as $retty)
166 }
167
168 fn lit_reg(a: i64, b: i64) -> bool {
169 use std::sync::Once;
170
171 let translated = translate_wat(&format!("
172 (module (func (param i64) (result {retty})
173 (i64.{op} (i64.const {left}) (get_local 0))))
174 ", retty = RETTY, op = OP, left = a));
175 static ONCE: Once = Once::new();
176 ONCE.call_once(|| translated.disassemble());
177
178 translated.execute_func::<(i64,), $retty>(0, (b,)) == Ok($func(a, b) as $retty)
179 }
180
181 fn reg_lit(a: i64, b: i64) -> bool {
182 use std::sync::Once;
183
184 let translated = translate_wat(&format!("
185 (module (func (param i64) (result {retty})
186 (i64.{op} (get_local 0) (i64.const {right}))))
187 ", retty = RETTY, op = OP, right = b));
188 static ONCE: Once = Once::new();
189 ONCE.call_once(|| translated.disassemble());
190
191 translated.execute_func::<(i64,), $retty>(0, (a,)) == Ok($func(a, b) as $retty)
192 }
193 }
194 }
195 };
196 }
197
198 macro_rules! unop_test {
199 ($name:ident, $func:expr) => {
200 unop_test!($name, $func, i64);
201 };
202 ($name:ident, $func:expr, $out_ty:ty) => {
203 mod $name {
204 use super::{lazy_static, quickcheck, translate_wat, ExecutableModule};
205 use std::sync::Once;
206
207 lazy_static! {
208 static ref AS_PARAM: ExecutableModule = translate_wat(concat!(
209 "(module (func (param i64) (result ",
210 stringify!($out_ty),
211 ")
212 (i64.",
213 stringify!($name),
214 " (get_local 0))))"
215 ),);
216 }
217
218 quickcheck! {
219 fn as_param(a: u64) -> bool {
220 AS_PARAM.execute_func::<(u64,), $out_ty>(0, (a,)) == Ok($func(a))
221 }
222
223 fn lit(a: u64) -> bool {
224 let translated = translate_wat(&format!(concat!("
225 (module (func (result ",stringify!($out_ty),")
226 (i64.",stringify!($name)," (i64.const {val}))))
227 "), val = a));
228 static ONCE: Once = Once::new();
229 ONCE.call_once(|| translated.disassemble());
230
231 translated.execute_func::<(), $out_ty>(0, ()) == Ok($func(a))
232 }
233 }
234 }
235 };
236 }
237
238 unop_test!(clz, |a: u64| a.leading_zeros() as _);
239 unop_test!(ctz, |a: u64| a.trailing_zeros() as _);
240 unop_test!(popcnt, |a: u64| a.count_ones() as _);
241 unop_test!(eqz, |a: u64| if a == 0 { 1 } else { 0 }, i32);
242
243 binop_test!(add, i64::wrapping_add);
244 binop_test!(sub, i64::wrapping_sub);
245 binop_test!(and, std::ops::BitAnd::bitand);
246 binop_test!(or, std::ops::BitOr::bitor);
247 binop_test!(xor, std::ops::BitXor::bitxor);
248 binop_test!(mul, i64::wrapping_mul);
249 binop_test!(eq, |a, b| if a == b { 1 } else { 0 }, i32);
250 binop_test!(ne, |a, b| if a != b { 1 } else { 0 }, i32);
251 binop_test!(
252 lt_u,
253 |a, b| if (a as u64) < (b as u64) { 1 } else { 0 },
254 i32
255 );
256 binop_test!(
257 le_u,
258 |a, b| if (a as u64) <= (b as u64) { 1 } else { 0 },
259 i32
260 );
261 binop_test!(
262 gt_u,
263 |a, b| if (a as u64) > (b as u64) { 1 } else { 0 },
264 i32
265 );
266 binop_test!(
267 ge_u,
268 |a, b| if (a as u64) >= (b as u64) { 1 } else { 0 },
269 i32
270 );
271 binop_test!(lt_s, |a, b| if a < b { 1 } else { 0 }, i32);
272 binop_test!(le_s, |a, b| if a <= b { 1 } else { 0 }, i32);
273 binop_test!(gt_s, |a, b| if a > b { 1 } else { 0 }, i32);
274 binop_test!(ge_s, |a, b| if a >= b { 1 } else { 0 }, i32);
275 binop_test!(shl, |a, b| (a as i64).wrapping_shl(b as _));
276 binop_test!(shr_s, |a, b| (a as i64).wrapping_shr(b as _));
277 binop_test!(shr_u, |a, b| (a as u64).wrapping_shr(b as _) as i64);
278 binop_test!(rotl, |a, b| (a as u64).rotate_left(b as _) as i64);
279 binop_test!(rotr, |a, b| (a as u64).rotate_right(b as _) as i64);
280 }
281
282 mod opf32 {
283 use super::{lazy_static, quickcheck, translate_wat, ExecutableModule};
284
285 macro_rules! binop_test {
286 ($op:ident, $func:expr) => {
287 binop_test!($op, $func, f32);
288 };
289 ($op:ident, $func:expr, $retty:ident) => {
290 mod $op {
291 use super::{translate_wat, ExecutableModule, quickcheck, lazy_static};
292
293 const RETTY: &str = stringify!($retty);
294 const OP: &str = stringify!($op);
295
296 lazy_static! {
297 static ref AS_PARAMS: ExecutableModule = translate_wat(&format!("
298 (module (func (param f32) (param f32) (result {retty})
299 (f32.{op} (get_local 0) (get_local 1))))
300 ", retty = RETTY, op = OP));
301 }
302
303 quickcheck! {
304 fn as_params(a: f32, b: f32) -> bool {
305 AS_PARAMS.execute_func::<(f32, f32), $retty>(0, (a, b)) == Ok($func(a, b) as $retty)
306 }
307
308 fn lit_lit(a: f32, b: f32) -> bool {
309 translate_wat(&format!("
310 (module (func (result {retty})
311 (f32.{op} (f32.const {left}) (f32.const {right}))))
312 ", retty = RETTY, op = OP, left = a, right = b)).execute_func::<(), $retty>(0, ()) == Ok($func(a, b) as $retty)
313 }
314
315 fn lit_reg(a: f32, b: f32) -> bool {
316 use std::sync::Once;
317
318 let translated = translate_wat(&format!("
319 (module (func (param f32) (result {retty})
320 (f32.{op} (f32.const {left}) (get_local 0))))
321 ", retty = RETTY, op = OP, left = a));
322 static ONCE: Once = Once::new();
323 ONCE.call_once(|| translated.disassemble());
324
325 translated.execute_func::<(f32,), $retty>(0, (b,)) == Ok($func(a, b) as $retty)
326 }
327
328 fn reg_lit(a: f32, b: f32) -> bool {
329 use std::sync::Once;
330
331 let translated = translate_wat(&format!("
332 (module (func (param f32) (result {retty})
333 (f32.{op} (get_local 0) (f32.const {right}))))
334 ", retty = RETTY, op = OP, right = b));
335 static ONCE: Once = Once::new();
336 ONCE.call_once(|| translated.disassemble());
337
338 translated.execute_func::<(f32,), $retty>(0, (a,)) == Ok($func(a, b) as $retty)
339 }
340 }
341 }
342 };
343 }
344
345 macro_rules! unop_test {
346 ($name:ident, $func:expr) => {
347 unop_test!($name, $func, f32);
348 };
349 ($name:ident, $func:expr, $out_ty:ty) => {
350 mod $name {
351 use super::{lazy_static, quickcheck, translate_wat, ExecutableModule};
352 use std::sync::Once;
353
354 lazy_static! {
355 static ref AS_PARAM: ExecutableModule = translate_wat(concat!(
356 "(module (func (param f32) (result ",
357 stringify!($out_ty),
358 ")
359 (f32.",
360 stringify!($name),
361 " (get_local 0))))"
362 ),);
363 }
364
365 quickcheck! {
366 fn as_param(a: f32) -> bool {
367 static ONCE: Once = Once::new();
368 ONCE.call_once(|| AS_PARAM.disassemble());
369 AS_PARAM.execute_func::<(f32,), $out_ty>(0, (a,)) == Ok($func(a))
370 }
371
372 fn lit(a: f32) -> bool {
373 let translated = translate_wat(&format!(concat!("
374 (module (func (result ",stringify!($out_ty),")
375 (f32.",stringify!($name)," (f32.const {val}))))
376 "), val = a));
377 static ONCE: Once = Once::new();
378 ONCE.call_once(|| translated.disassemble());
379
380 translated.execute_func::<(), $out_ty>(0, ()) == Ok($func(a))
381 }
382 }
383 }
384 };
385 }
386
387 binop_test!(add, |a, b| a + b);
388 binop_test!(mul, |a, b| a * b);
389 binop_test!(sub, |a, b| a - b);
390 binop_test!(gt, |a, b| a > b, i32);
391 binop_test!(lt, |a, b| a < b, i32);
392 binop_test!(ge, |a, b| a >= b, i32);
393 binop_test!(le, |a, b| a <= b, i32);
394
395 unop_test!(neg, |a: f32| -a);
396 unop_test!(abs, |a: f32| a.abs());
397 }
398
399 mod opf64 {
400 use super::{lazy_static, quickcheck, translate_wat, ExecutableModule};
401
402 macro_rules! binop_test {
403 ($op:ident, $func:expr) => {
404 binop_test!($op, $func, f64);
405 };
406 ($op:ident, $func:expr, $retty:ident) => {
407 mod $op {
408 use super::{translate_wat, ExecutableModule, quickcheck, lazy_static};
409
410 const RETTY: &str = stringify!($retty);
411 const OP: &str = stringify!($op);
412
413 lazy_static! {
414 static ref AS_PARAMS: ExecutableModule = translate_wat(&format!("
415 (module (func (param f64) (param f64) (result {retty})
416 (f64.{op} (get_local 0) (get_local 1))))
417 ", retty = RETTY, op = OP));
418 }
419
420 quickcheck! {
421 fn as_params(a: f64, b: f64) -> bool {
422 AS_PARAMS.execute_func::<(f64, f64), $retty>(0, (a, b)) == Ok($func(a, b) as $retty)
423 }
424
425 fn lit_lit(a: f64, b: f64) -> bool {
426 translate_wat(&format!("
427 (module (func (result {retty})
428 (f64.{op} (f64.const {left}) (f64.const {right}))))
429 ", retty = RETTY, op = OP, left = a, right = b)).execute_func::<(), $retty>(0, ()) == Ok($func(a, b) as $retty)
430 }
431
432 fn lit_reg(a: f64, b: f64) -> bool {
433 use std::sync::Once;
434
435 let translated = translate_wat(&format!("
436 (module (func (param f64) (result {retty})
437 (f64.{op} (f64.const {left}) (get_local 0))))
438 ", retty = RETTY, op = OP, left = a));
439 static ONCE: Once = Once::new();
440 ONCE.call_once(|| translated.disassemble());
441
442 translated.execute_func::<(f64,), $retty>(0, (b,)) == Ok($func(a, b) as $retty)
443 }
444
445 fn reg_lit(a: f64, b: f64) -> bool {
446 use std::sync::Once;
447
448 let translated = translate_wat(&format!("
449 (module (func (param f64) (result {retty})
450 (f64.{op} (get_local 0) (f64.const {right}))))
451 ", retty = RETTY, op = OP, right = b));
452 static ONCE: Once = Once::new();
453 ONCE.call_once(|| translated.disassemble());
454
455 translated.execute_func::<(f64,), $retty>(0, (a,)) == Ok($func(a, b) as $retty)
456 }
457 }
458 }
459 };
460 }
461
462 macro_rules! unop_test {
463 ($name:ident, $func:expr) => {
464 unop_test!($name, $func, f64);
465 };
466 ($name:ident, $func:expr, $out_ty:ty) => {
467 mod $name {
468 use super::{lazy_static, quickcheck, translate_wat, ExecutableModule};
469 use std::sync::Once;
470
471 lazy_static! {
472 static ref AS_PARAM: ExecutableModule = translate_wat(concat!(
473 "(module (func (param f64) (result ",
474 stringify!($out_ty),
475 ")
476 (f64.",
477 stringify!($name),
478 " (get_local 0))))"
479 ),);
480 }
481
482 quickcheck! {
483 fn as_param(a: f64) -> bool {
484 static ONCE: Once = Once::new();
485 ONCE.call_once(|| AS_PARAM.disassemble());
486 AS_PARAM.execute_func::<(f64,), $out_ty>(0, (a,)) == Ok($func(a))
487 }
488
489 fn lit(a: f64) -> bool {
490 let translated = translate_wat(&format!(concat!("
491 (module (func (result ",stringify!($out_ty),")
492 (f64.",stringify!($name)," (f64.const {val}))))
493 "), val = a));
494 static ONCE: Once = Once::new();
495 ONCE.call_once(|| translated.disassemble());
496
497 translated.execute_func::<(), $out_ty>(0, ()) == Ok($func(a))
498 }
499 }
500 }
501 };
502 }
503
504 binop_test!(add, |a, b| a + b);
505 binop_test!(mul, |a, b| a * b);
506 binop_test!(sub, |a, b| a - b);
507 binop_test!(gt, |a, b| a > b, i32);
508 binop_test!(lt, |a, b| a < b, i32);
509 binop_test!(ge, |a, b| a >= b, i32);
510 binop_test!(le, |a, b| a <= b, i32);
511
512 unop_test!(neg, |a: f64| -a);
513 unop_test!(abs, |a: f64| a.abs());
514 }
515
516 quickcheck! {
517 fn if_then_else(a: u32, b: u32) -> bool {
518 const CODE: &str = r#"
519 (module
520 (func (param i32) (param i32) (result i32)
521 (if (result i32)
522 (i32.eq
523 (get_local 0)
524 (get_local 1)
525 )
526 (then (get_local 0))
527 (else (get_local 1))
528 )
529 )
530 )
531 "#;
532
533 lazy_static! {
534 static ref TRANSLATED: ExecutableModule = {let out = translate_wat(CODE); out.disassemble(); out};
535 }
536
537 let out = TRANSLATED.execute_func::<(u32, u32), u32>(0, (a, b));
538
539 out == Ok(if a == b { a } else { b })
540 }
541 }
542
543 quickcheck! {
544 #[test]
545 fn literals(a: i32, b: i64, c: i32, d: i64) -> bool {
546 let code = format!(r#"
547 (module
548 (func (result i32)
549 (i32.const {})
550 )
551 (func (result i64)
552 (i64.const {})
553 )
554 (func (result f32)
555 (f32.const {})
556 )
557 (func (result f64)
558 (f64.const {})
559 )
560 )
561 "#, a, b, c, d);
562
563 let translated = translate_wat(&code);
564
565 assert_eq!(translated.execute_func::<(), i32>(0, ()), Ok(a));
566 assert_eq!(translated.execute_func::<(), i64>(1, ()), Ok(b));
567 assert_eq!(translated.execute_func::<(), f32>(2, ()), Ok(c as _));
568 assert_eq!(translated.execute_func::<(), f64>(3, ()), Ok(d as _));
569
570 true
571 }
572 }
573
574 quickcheck! {
575 #[test]
576 fn params(a: i32, b: i64, c: i32, d: i64) -> bool {
577 let code = r#"
578 (module
579 (func (param i32) (param i64) (param f32) (param f64) (result i32)
580 (get_local 0)
581 )
582 (func (param i32) (param i64) (param f32) (param f64) (result i64)
583 (get_local 1)
584 )
585 (func (param i32) (param i64) (param f32) (param f64) (result f32)
586 (get_local 2)
587 )
588 (func (param i32) (param i64) (param f32) (param f64) (result f64)
589 (get_local 3)
590 )
591 )
592 "#;
593
594 let c = c as f32;
595 let d = d as f64;
596
597 let translated = translate_wat(&code);
598
599 assert_eq!(translated.execute_func::<(i32, i64, f32, f64), i32>(0, (a, b, c, d)), Ok(a));
600 assert_eq!(translated.execute_func::<(i32, i64, f32, f64), i64>(1, (a, b, c, d)), Ok(b));
601 assert_eq!(translated.execute_func::<(i32, i64, f32, f64), f32>(2, (a, b, c, d)), Ok(c));
602 assert_eq!(translated.execute_func::<(i32, i64, f32, f64), f64>(3, (a, b, c, d)), Ok(d));
603
604 true
605 }
606 }
607
608 macro_rules! test_select {
609 ($name:ident, $ty:ident) => {
610 mod $name {
611 use super::{lazy_static, quickcheck, translate_wat, ExecutableModule};
612 use std::sync::Once;
613
614 lazy_static! {
615 static ref AS_PARAMS: ExecutableModule = translate_wat(&format!(
616 "
617 (module
618 (func (param {ty}) (param {ty}) (param i32) (result {ty})
619 (select (get_local 0) (get_local 1) (get_local 2))
620 )
621 )",
622 ty = stringify!($ty)
623 ));
624 }
625
626 quickcheck! {
627 fn as_param(cond: bool, then: $ty, else_: $ty) -> bool {
628 let icond: i32 = if cond { 1 } else { 0 };
629 AS_PARAMS.execute_func::<($ty, $ty, i32), $ty>(0, (then, else_, icond)) ==
630 Ok(if cond { then } else { else_ })
631 }
632
633 fn lit(cond: bool, then: $ty, else_: $ty) -> bool {
634 let icond: i32 = if cond { 1 } else { 0 };
635 let translated = translate_wat(&format!("
636 (module (func (param {ty}) (param {ty}) (result {ty})
637 (select (get_local 0) (get_local 1) (i32.const {val}))))
638 ",
639 val = icond,
640 ty = stringify!($ty)
641 ));
642 static ONCE: Once = Once::new();
643 ONCE.call_once(|| translated.disassemble());
644
645 translated.execute_func::<($ty, $ty), $ty>(0, (then, else_)) ==
646 Ok(if cond { then } else { else_ })
647 }
648 }
649 }
650 };
651 }
652
653 test_select!(select32, i32);
654 test_select!(select64, i64);
655