]> git.lizzy.rs Git - rust.git/blob - tests/run-pass/portable-simd.rs
implement simd bitmask intrinsics
[rust.git] / tests / run-pass / portable-simd.rs
1 #![feature(portable_simd, platform_intrinsics)]
2 use std::simd::*;
3
4 fn simd_ops_f32() {
5     let a = f32x4::splat(10.0);
6     let b = f32x4::from_array([1.0, 2.0, 3.0, -4.0]);
7     assert_eq!(-b, f32x4::from_array([-1.0, -2.0, -3.0, 4.0]));
8     assert_eq!(a + b, f32x4::from_array([11.0, 12.0, 13.0, 6.0]));
9     assert_eq!(a - b, f32x4::from_array([9.0, 8.0, 7.0, 14.0]));
10     assert_eq!(a * b, f32x4::from_array([10.0, 20.0, 30.0, -40.0]));
11     assert_eq!(b / a, f32x4::from_array([0.1, 0.2, 0.3, -0.4]));
12     assert_eq!(a / f32x4::splat(2.0), f32x4::splat(5.0));
13     assert_eq!(a % b, f32x4::from_array([0.0, 0.0, 1.0, 2.0]));
14     assert_eq!(b.abs(), f32x4::from_array([1.0, 2.0, 3.0, 4.0]));
15     assert_eq!(a.max(b * f32x4::splat(4.0)), f32x4::from_array([10.0, 10.0, 12.0, 10.0]));
16     assert_eq!(a.min(b * f32x4::splat(4.0)), f32x4::from_array([4.0, 8.0, 10.0, -16.0]));
17
18     assert_eq!(a.mul_add(b, a), (a*b)+a);
19     assert_eq!(b.mul_add(b, a), (b*b)+a);
20     assert_eq!((a*a).sqrt(), a);
21     assert_eq!((b*b).sqrt(), b.abs());
22
23     assert_eq!(a.lanes_eq(f32x4::splat(5.0) * b), Mask::from_array([false, true, false, false]));
24     assert_eq!(a.lanes_ne(f32x4::splat(5.0) * b), Mask::from_array([true, false, true, true]));
25     assert_eq!(a.lanes_le(f32x4::splat(5.0) * b), Mask::from_array([false, true, true, false]));
26     assert_eq!(a.lanes_lt(f32x4::splat(5.0) * b), Mask::from_array([false, false, true, false]));
27     assert_eq!(a.lanes_ge(f32x4::splat(5.0) * b), Mask::from_array([true, true, false, true]));
28     assert_eq!(a.lanes_gt(f32x4::splat(5.0) * b), Mask::from_array([true, false, false, true]));
29
30     assert_eq!(a.reduce_sum(), 40.0);
31     assert_eq!(b.reduce_sum(), 2.0);
32     assert_eq!(a.reduce_product(), 100.0 * 100.0);
33     assert_eq!(b.reduce_product(), -24.0);
34     assert_eq!(a.reduce_max(), 10.0);
35     assert_eq!(b.reduce_max(), 3.0);
36     assert_eq!(a.reduce_min(), 10.0);
37     assert_eq!(b.reduce_min(), -4.0);
38
39     assert_eq!(
40         f32x2::from_array([0.0, f32::NAN]).max(f32x2::from_array([f32::NAN, 0.0])),
41         f32x2::from_array([0.0, 0.0])
42     );
43     assert_eq!(f32x2::from_array([0.0, f32::NAN]).reduce_max(), 0.0);
44     assert_eq!(f32x2::from_array([f32::NAN, 0.0]).reduce_max(), 0.0);
45     assert_eq!(
46         f32x2::from_array([0.0, f32::NAN]).min(f32x2::from_array([f32::NAN, 0.0])),
47         f32x2::from_array([0.0, 0.0])
48     );
49     assert_eq!(f32x2::from_array([0.0, f32::NAN]).reduce_min(), 0.0);
50     assert_eq!(f32x2::from_array([f32::NAN, 0.0]).reduce_min(), 0.0);
51 }
52
53 fn simd_ops_f64() {
54     let a = f64x4::splat(10.0);
55     let b = f64x4::from_array([1.0, 2.0, 3.0, -4.0]);
56     assert_eq!(-b, f64x4::from_array([-1.0, -2.0, -3.0, 4.0]));
57     assert_eq!(a + b, f64x4::from_array([11.0, 12.0, 13.0, 6.0]));
58     assert_eq!(a - b, f64x4::from_array([9.0, 8.0, 7.0, 14.0]));
59     assert_eq!(a * b, f64x4::from_array([10.0, 20.0, 30.0, -40.0]));
60     assert_eq!(b / a, f64x4::from_array([0.1, 0.2, 0.3, -0.4]));
61     assert_eq!(a / f64x4::splat(2.0), f64x4::splat(5.0));
62     assert_eq!(a % b, f64x4::from_array([0.0, 0.0, 1.0, 2.0]));
63     assert_eq!(b.abs(), f64x4::from_array([1.0, 2.0, 3.0, 4.0]));
64     assert_eq!(a.max(b * f64x4::splat(4.0)), f64x4::from_array([10.0, 10.0, 12.0, 10.0]));
65     assert_eq!(a.min(b * f64x4::splat(4.0)), f64x4::from_array([4.0, 8.0, 10.0, -16.0]));
66
67     assert_eq!(a.mul_add(b, a), (a*b)+a);
68     assert_eq!(b.mul_add(b, a), (b*b)+a);
69     assert_eq!((a*a).sqrt(), a);
70     assert_eq!((b*b).sqrt(), b.abs());
71
72     assert_eq!(a.lanes_eq(f64x4::splat(5.0) * b), Mask::from_array([false, true, false, false]));
73     assert_eq!(a.lanes_ne(f64x4::splat(5.0) * b), Mask::from_array([true, false, true, true]));
74     assert_eq!(a.lanes_le(f64x4::splat(5.0) * b), Mask::from_array([false, true, true, false]));
75     assert_eq!(a.lanes_lt(f64x4::splat(5.0) * b), Mask::from_array([false, false, true, false]));
76     assert_eq!(a.lanes_ge(f64x4::splat(5.0) * b), Mask::from_array([true, true, false, true]));
77     assert_eq!(a.lanes_gt(f64x4::splat(5.0) * b), Mask::from_array([true, false, false, true]));
78
79     assert_eq!(a.reduce_sum(), 40.0);
80     assert_eq!(b.reduce_sum(), 2.0);
81     assert_eq!(a.reduce_product(), 100.0 * 100.0);
82     assert_eq!(b.reduce_product(), -24.0);
83     assert_eq!(a.reduce_max(), 10.0);
84     assert_eq!(b.reduce_max(), 3.0);
85     assert_eq!(a.reduce_min(), 10.0);
86     assert_eq!(b.reduce_min(), -4.0);
87
88     assert_eq!(
89         f64x2::from_array([0.0, f64::NAN]).max(f64x2::from_array([f64::NAN, 0.0])),
90         f64x2::from_array([0.0, 0.0])
91     );
92     assert_eq!(f64x2::from_array([0.0, f64::NAN]).reduce_max(), 0.0);
93     assert_eq!(f64x2::from_array([f64::NAN, 0.0]).reduce_max(), 0.0);
94     assert_eq!(
95         f64x2::from_array([0.0, f64::NAN]).min(f64x2::from_array([f64::NAN, 0.0])),
96         f64x2::from_array([0.0, 0.0])
97     );
98     assert_eq!(f64x2::from_array([0.0, f64::NAN]).reduce_min(), 0.0);
99     assert_eq!(f64x2::from_array([f64::NAN, 0.0]).reduce_min(), 0.0);
100 }
101
102 fn simd_ops_i32() {
103     let a = i32x4::splat(10);
104     let b = i32x4::from_array([1, 2, 3, -4]);
105     assert_eq!(-b, i32x4::from_array([-1, -2, -3, 4]));
106     assert_eq!(a + b, i32x4::from_array([11, 12, 13, 6]));
107     assert_eq!(a - b, i32x4::from_array([9, 8, 7, 14]));
108     assert_eq!(a * b, i32x4::from_array([10, 20, 30, -40]));
109     assert_eq!(a / b, i32x4::from_array([10, 5, 3, -2]));
110     assert_eq!(a / i32x4::splat(2), i32x4::splat(5));
111     assert_eq!(i32x2::splat(i32::MIN) / i32x2::splat(-1), i32x2::splat(i32::MIN));
112     assert_eq!(a % b, i32x4::from_array([0, 0, 1, 2]));
113     assert_eq!(i32x2::splat(i32::MIN) % i32x2::splat(-1), i32x2::splat(0));
114     assert_eq!(b.abs(), i32x4::from_array([1, 2, 3, 4]));
115     assert_eq!(a.max(b * i32x4::splat(4)), i32x4::from_array([10, 10, 12, 10]));
116     assert_eq!(a.min(b * i32x4::splat(4)), i32x4::from_array([4, 8, 10, -16]));
117
118     assert_eq!(
119         i8x4::from_array([i8::MAX, -23, 23, i8::MIN]).saturating_add(i8x4::from_array([
120             1,
121             i8::MIN,
122             i8::MAX,
123             28
124         ])),
125         i8x4::from_array([i8::MAX, i8::MIN, i8::MAX, -100])
126     );
127     assert_eq!(
128         i8x4::from_array([i8::MAX, -28, 27, 42]).saturating_sub(i8x4::from_array([
129             1,
130             i8::MAX,
131             i8::MAX,
132             -80
133         ])),
134         i8x4::from_array([126, i8::MIN, -100, 122])
135     );
136     assert_eq!(
137         u8x4::from_array([u8::MAX, 0, 23, 42]).saturating_add(u8x4::from_array([
138             1,
139             1,
140             u8::MAX,
141             200
142         ])),
143         u8x4::from_array([u8::MAX, 1, u8::MAX, 242])
144     );
145     assert_eq!(
146         u8x4::from_array([u8::MAX, 0, 23, 42]).saturating_sub(u8x4::from_array([
147             1,
148             1,
149             u8::MAX,
150             200
151         ])),
152         u8x4::from_array([254, 0, 0, 0])
153     );
154
155     assert_eq!(!b, i32x4::from_array([!1, !2, !3, !-4]));
156     assert_eq!(b << i32x4::splat(2), i32x4::from_array([4, 8, 12, -16]));
157     assert_eq!(b >> i32x4::splat(1), i32x4::from_array([0, 1, 1, -2]));
158     assert_eq!(b & i32x4::splat(2), i32x4::from_array([0, 2, 2, 0]));
159     assert_eq!(b | i32x4::splat(2), i32x4::from_array([3, 2, 3, -2]));
160     assert_eq!(b ^ i32x4::splat(2), i32x4::from_array([3, 0, 1, -2]));
161
162     assert_eq!(a.lanes_eq(i32x4::splat(5) * b), Mask::from_array([false, true, false, false]));
163     assert_eq!(a.lanes_ne(i32x4::splat(5) * b), Mask::from_array([true, false, true, true]));
164     assert_eq!(a.lanes_le(i32x4::splat(5) * b), Mask::from_array([false, true, true, false]));
165     assert_eq!(a.lanes_lt(i32x4::splat(5) * b), Mask::from_array([false, false, true, false]));
166     assert_eq!(a.lanes_ge(i32x4::splat(5) * b), Mask::from_array([true, true, false, true]));
167     assert_eq!(a.lanes_gt(i32x4::splat(5) * b), Mask::from_array([true, false, false, true]));
168
169     assert_eq!(a.reduce_sum(), 40);
170     assert_eq!(b.reduce_sum(), 2);
171     assert_eq!(a.reduce_product(), 100 * 100);
172     assert_eq!(b.reduce_product(), -24);
173     assert_eq!(a.reduce_max(), 10);
174     assert_eq!(b.reduce_max(), 3);
175     assert_eq!(a.reduce_min(), 10);
176     assert_eq!(b.reduce_min(), -4);
177
178     assert_eq!(a.reduce_and(), 10);
179     assert_eq!(b.reduce_and(), 0);
180     assert_eq!(a.reduce_or(), 10);
181     assert_eq!(b.reduce_or(), -1);
182     assert_eq!(a.reduce_xor(), 0);
183     assert_eq!(b.reduce_xor(), -4);
184 }
185
186 fn simd_mask() {
187     let intmask = Mask::from_int(i32x4::from_array([0, -1, 0, 0]));
188     assert_eq!(intmask, Mask::from_array([false, true, false, false]));
189     assert_eq!(intmask.to_array(), [false, true, false, false]);
190
191     let values = [
192         true, false, false, true, false, false, true, false, true, true, false, false, false, true,
193         false, true,
194     ];
195     let mask = Mask::<i64, 16>::from_array(values);
196     let bitmask = mask.to_bitmask();
197     assert_eq!(bitmask, 0b1010001101001001);
198     assert_eq!(Mask::<i64, 16>::from_bitmask(bitmask), mask);
199
200     let values = [false, false, false, true];
201     let mask = Mask::<i64, 4>::from_array(values);
202     let bitmask = mask.to_bitmask();
203     assert_eq!(bitmask, 0b1000);
204     assert_eq!(Mask::<i64, 4>::from_bitmask(bitmask), mask);
205 }
206
207 fn simd_cast() {
208     // between integer types
209     assert_eq!(i32x4::from_array([1, 2, 3, -4]), i16x4::from_array([1, 2, 3, -4]).cast());
210     assert_eq!(i16x4::from_array([1, 2, 3, -4]), i32x4::from_array([1, 2, 3, -4]).cast());
211     assert_eq!(i32x4::from_array([1, -1, 3, 4]), u64x4::from_array([1, u64::MAX, 3, 4]).cast());
212
213     // float -> int
214     assert_eq!(
215         i8x4::from_array([127, -128, 127, -128]),
216         f32x4::from_array([127.99, -128.99, 999.0, -999.0]).cast()
217     );
218     assert_eq!(
219         i32x4::from_array([0, 1, -1, 2147483520]),
220         f32x4::from_array([
221             -0.0,
222             /*0x1.19999ap+0*/ f32::from_bits(0x3f8ccccd),
223             /*-0x1.19999ap+0*/ f32::from_bits(0xbf8ccccd),
224             2147483520.0
225         ])
226         .cast()
227     );
228     assert_eq!(
229         i32x8::from_array([i32::MAX, i32::MIN, i32::MAX, i32::MIN, i32::MAX, i32::MIN, 0, 0]),
230         f32x8::from_array([
231             2147483648.0f32,
232             -2147483904.0f32,
233             f32::MAX,
234             f32::MIN,
235             f32::INFINITY,
236             f32::NEG_INFINITY,
237             f32::NAN,
238             -f32::NAN,
239         ])
240         .cast()
241     );
242
243     // int -> float
244     assert_eq!(
245         f32x4::from_array([
246             -2147483648.0,
247             /*0x1.26580cp+30*/ f32::from_bits(0x4e932c06),
248             16777220.0,
249             -16777220.0,
250         ]),
251         i32x4::from_array([-2147483647i32, 1234567890i32, 16777219i32, -16777219i32]).cast()
252     );
253
254     // float -> float
255     assert_eq!(
256         f32x4::from_array([f32::INFINITY, f32::INFINITY, f32::NEG_INFINITY, f32::NEG_INFINITY]),
257         f64x4::from_array([f64::MAX, f64::INFINITY, f64::MIN, f64::NEG_INFINITY]).cast()
258     );
259
260     // unchecked casts
261     unsafe {
262         assert_eq!(
263             i32x4::from_array([0, 1, -1, 2147483520]),
264             f32x4::from_array([
265                 -0.0,
266                 /*0x1.19999ap+0*/ f32::from_bits(0x3f8ccccd),
267                 /*-0x1.19999ap+0*/ f32::from_bits(0xbf8ccccd),
268                 2147483520.0
269             ])
270             .to_int_unchecked()
271         );
272         assert_eq!(
273             u64x4::from_array([0, 10000000000000000, u64::MAX - 2047, 9223372036854775808]),
274             f64x4::from_array([
275                 -0.99999999999,
276                 1e16,
277                 (u64::MAX - 1024) as f64,
278                 9223372036854775808.0
279             ])
280             .to_int_unchecked()
281         );
282     }
283 }
284
285 fn simd_swizzle() {
286     use Which::*;
287
288     let a = f32x4::splat(10.0);
289     let b = f32x4::from_array([1.0, 2.0, 3.0, -4.0]);
290
291     assert_eq!(simd_swizzle!(b, [3, 0, 0, 2]), f32x4::from_array([-4.0, 1.0, 1.0, 3.0]));
292     assert_eq!(simd_swizzle!(b, [1, 2]), f32x2::from_array([2.0, 3.0]));
293     assert_eq!(simd_swizzle!(b, a, [First(3), Second(0)]), f32x2::from_array([-4.0, 10.0]));
294 }
295
296 fn simd_gather_scatter() {
297     let mut vec: Vec<i16> = vec![10, 11, 12, 13, 14, 15, 16, 17, 18];
298     let idxs = Simd::from_array([9, 3, 0, 17]);
299     let result = Simd::gather_or_default(&vec, idxs); // Note the lane that is out-of-bounds.
300     assert_eq!(result, Simd::from_array([0, 13, 10, 0]));
301
302     let idxs = Simd::from_array([9, 3, 0, 0]);
303     Simd::from_array([-27, 82, -41, 124]).scatter(&mut vec, idxs);
304     assert_eq!(vec, vec![124, 11, 12, 82, 14, 15, 16, 17, 18]);
305 }
306
307 fn simd_round() {
308     assert_eq!(
309         f32x4::from_array([0.9, 1.001, 2.0, -4.5]).ceil(),
310         f32x4::from_array([1.0, 2.0, 2.0, -4.0])
311     );
312     assert_eq!(
313         f32x4::from_array([0.9, 1.001, 2.0, -4.5]).floor(),
314         f32x4::from_array([0.0, 1.0, 2.0, -5.0])
315     );
316     assert_eq!(
317         f32x4::from_array([0.9, 1.001, 2.0, -4.5]).round(),
318         f32x4::from_array([1.0, 1.0, 2.0, -5.0])
319     );
320     assert_eq!(
321         f32x4::from_array([0.9, 1.001, 2.0, -4.5]).trunc(),
322         f32x4::from_array([0.0, 1.0, 2.0, -4.0])
323     );
324
325     assert_eq!(
326         f64x4::from_array([0.9, 1.001, 2.0, -4.5]).ceil(),
327         f64x4::from_array([1.0, 2.0, 2.0, -4.0])
328     );
329     assert_eq!(
330         f64x4::from_array([0.9, 1.001, 2.0, -4.5]).floor(),
331         f64x4::from_array([0.0, 1.0, 2.0, -5.0])
332     );
333     assert_eq!(
334         f64x4::from_array([0.9, 1.001, 2.0, -4.5]).round(),
335         f64x4::from_array([1.0, 1.0, 2.0, -5.0])
336     );
337     assert_eq!(
338         f64x4::from_array([0.9, 1.001, 2.0, -4.5]).trunc(),
339         f64x4::from_array([0.0, 1.0, 2.0, -4.0])
340     );
341 }
342
343 fn simd_intrinsics() {
344     extern "platform-intrinsic" {
345         fn simd_eq<T, U>(x: T, y: T) -> U;
346         fn simd_reduce_any<T>(x: T) -> bool;
347         fn simd_reduce_all<T>(x: T) -> bool;
348         fn simd_select<M, T>(m: M, yes: T, no: T) -> T;
349     }
350     unsafe {
351         // Make sure simd_eq returns all-1 for `true`
352         let a = i32x4::splat(10);
353         let b = i32x4::from_array([1, 2, 10, 4]);
354         let c: i32x4 = simd_eq(a, b);
355         assert_eq!(c, i32x4::from_array([0, 0, -1, 0]));
356
357         assert!(!simd_reduce_any(i32x4::splat(0)));
358         assert!(simd_reduce_any(i32x4::splat(-1)));
359         assert!(simd_reduce_any(i32x2::from_array([0, -1])));
360         assert!(!simd_reduce_all(i32x4::splat(0)));
361         assert!(simd_reduce_all(i32x4::splat(-1)));
362         assert!(!simd_reduce_all(i32x2::from_array([0, -1])));
363
364         assert_eq!(
365             simd_select(i8x4::from_array([0, -1, -1, 0]), a, b),
366             i32x4::from_array([1, 10, 10, 4])
367         );
368         assert_eq!(
369             simd_select(i8x4::from_array([0, -1, -1, 0]), b, a),
370             i32x4::from_array([10, 2, 10, 10])
371         );
372     }
373 }
374
375 fn main() {
376     simd_mask();
377     simd_ops_f32();
378     simd_ops_f64();
379     simd_ops_i32();
380     simd_cast();
381     simd_swizzle();
382     simd_gather_scatter();
383     simd_round();
384     simd_intrinsics();
385 }