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