1const std = @import("std");
2const builtin = @import("builtin");
3const mem = std.mem;
4const math = std.math;
5const expect = std.testing.expect;
6const expectEqual = std.testing.expectEqual;
7const expectApproxEqRel = std.testing.expectApproxEqRel;
8const Vector = std.meta.Vector;
9
10test "implicit cast vector to array - bool" {
11    const S = struct {
12        fn doTheTest() !void {
13            const a: Vector(4, bool) = [_]bool{ true, false, true, false };
14            const result_array: [4]bool = a;
15            try expect(mem.eql(bool, &result_array, &[4]bool{ true, false, true, false }));
16        }
17    };
18    try S.doTheTest();
19    comptime try S.doTheTest();
20}
21
22test "vector wrap operators" {
23    const S = struct {
24        fn doTheTest() !void {
25            var v: Vector(4, i32) = [4]i32{ 2147483647, -2, 30, 40 };
26            var x: Vector(4, i32) = [4]i32{ 1, 2147483647, 3, 4 };
27            try expect(mem.eql(i32, &@as([4]i32, v +% x), &[4]i32{ -2147483648, 2147483645, 33, 44 }));
28            try expect(mem.eql(i32, &@as([4]i32, v -% x), &[4]i32{ 2147483646, 2147483647, 27, 36 }));
29            try expect(mem.eql(i32, &@as([4]i32, v *% x), &[4]i32{ 2147483647, 2, 90, 160 }));
30            var z: Vector(4, i32) = [4]i32{ 1, 2, 3, -2147483648 };
31            try expect(mem.eql(i32, &@as([4]i32, -%z), &[4]i32{ -1, -2, -3, -2147483648 }));
32        }
33    };
34    try S.doTheTest();
35    comptime try S.doTheTest();
36}
37
38test "vector bin compares with mem.eql" {
39    const S = struct {
40        fn doTheTest() !void {
41            var v: Vector(4, i32) = [4]i32{ 2147483647, -2, 30, 40 };
42            var x: Vector(4, i32) = [4]i32{ 1, 2147483647, 30, 4 };
43            try expect(mem.eql(bool, &@as([4]bool, v == x), &[4]bool{ false, false, true, false }));
44            try expect(mem.eql(bool, &@as([4]bool, v != x), &[4]bool{ true, true, false, true }));
45            try expect(mem.eql(bool, &@as([4]bool, v < x), &[4]bool{ false, true, false, false }));
46            try expect(mem.eql(bool, &@as([4]bool, v > x), &[4]bool{ true, false, false, true }));
47            try expect(mem.eql(bool, &@as([4]bool, v <= x), &[4]bool{ false, true, true, false }));
48            try expect(mem.eql(bool, &@as([4]bool, v >= x), &[4]bool{ true, false, true, true }));
49        }
50    };
51    try S.doTheTest();
52    comptime try S.doTheTest();
53}
54
55test "vector int operators" {
56    const S = struct {
57        fn doTheTest() !void {
58            var v: Vector(4, i32) = [4]i32{ 10, 20, 30, 40 };
59            var x: Vector(4, i32) = [4]i32{ 1, 2, 3, 4 };
60            try expect(mem.eql(i32, &@as([4]i32, v + x), &[4]i32{ 11, 22, 33, 44 }));
61            try expect(mem.eql(i32, &@as([4]i32, v - x), &[4]i32{ 9, 18, 27, 36 }));
62            try expect(mem.eql(i32, &@as([4]i32, v * x), &[4]i32{ 10, 40, 90, 160 }));
63            try expect(mem.eql(i32, &@as([4]i32, -v), &[4]i32{ -10, -20, -30, -40 }));
64        }
65    };
66    try S.doTheTest();
67    comptime try S.doTheTest();
68}
69
70test "vector float operators" {
71    const S = struct {
72        fn doTheTest() !void {
73            var v: Vector(4, f32) = [4]f32{ 10, 20, 30, 40 };
74            var x: Vector(4, f32) = [4]f32{ 1, 2, 3, 4 };
75            try expect(mem.eql(f32, &@as([4]f32, v + x), &[4]f32{ 11, 22, 33, 44 }));
76            try expect(mem.eql(f32, &@as([4]f32, v - x), &[4]f32{ 9, 18, 27, 36 }));
77            try expect(mem.eql(f32, &@as([4]f32, v * x), &[4]f32{ 10, 40, 90, 160 }));
78            try expect(mem.eql(f32, &@as([4]f32, -x), &[4]f32{ -1, -2, -3, -4 }));
79        }
80    };
81    try S.doTheTest();
82    comptime try S.doTheTest();
83}
84
85test "vector bit operators" {
86    const S = struct {
87        fn doTheTest() !void {
88            var v: Vector(4, u8) = [4]u8{ 0b10101010, 0b10101010, 0b10101010, 0b10101010 };
89            var x: Vector(4, u8) = [4]u8{ 0b11110000, 0b00001111, 0b10101010, 0b01010101 };
90            try expect(mem.eql(u8, &@as([4]u8, v ^ x), &[4]u8{ 0b01011010, 0b10100101, 0b00000000, 0b11111111 }));
91            try expect(mem.eql(u8, &@as([4]u8, v | x), &[4]u8{ 0b11111010, 0b10101111, 0b10101010, 0b11111111 }));
92            try expect(mem.eql(u8, &@as([4]u8, v & x), &[4]u8{ 0b10100000, 0b00001010, 0b10101010, 0b00000000 }));
93        }
94    };
95    try S.doTheTest();
96    comptime try S.doTheTest();
97}
98
99test "implicit cast vector to array" {
100    const S = struct {
101        fn doTheTest() !void {
102            var a: Vector(4, i32) = [_]i32{ 1, 2, 3, 4 };
103            var result_array: [4]i32 = a;
104            result_array = a;
105            try expect(mem.eql(i32, &result_array, &[4]i32{ 1, 2, 3, 4 }));
106        }
107    };
108    try S.doTheTest();
109    comptime try S.doTheTest();
110}
111
112test "array to vector" {
113    var foo: f32 = 3.14;
114    var arr = [4]f32{ foo, 1.5, 0.0, 0.0 };
115    var vec: Vector(4, f32) = arr;
116    _ = vec;
117}
118
119test "vector casts of sizes not divisible by 8" {
120    const S = struct {
121        fn doTheTest() !void {
122            {
123                var v: Vector(4, u3) = [4]u3{ 5, 2, 3, 0 };
124                var x: [4]u3 = v;
125                try expect(mem.eql(u3, &x, &@as([4]u3, v)));
126            }
127            {
128                var v: Vector(4, u2) = [4]u2{ 1, 2, 3, 0 };
129                var x: [4]u2 = v;
130                try expect(mem.eql(u2, &x, &@as([4]u2, v)));
131            }
132            {
133                var v: Vector(4, u1) = [4]u1{ 1, 0, 1, 0 };
134                var x: [4]u1 = v;
135                try expect(mem.eql(u1, &x, &@as([4]u1, v)));
136            }
137            {
138                var v: Vector(4, bool) = [4]bool{ false, false, true, false };
139                var x: [4]bool = v;
140                try expect(mem.eql(bool, &x, &@as([4]bool, v)));
141            }
142        }
143    };
144    try S.doTheTest();
145    comptime try S.doTheTest();
146}
147
148test "vector @splat" {
149    const S = struct {
150        fn testForT(comptime N: comptime_int, v: anytype) !void {
151            const T = @TypeOf(v);
152            var vec = @splat(N, v);
153            try expectEqual(Vector(N, T), @TypeOf(vec));
154            var as_array = @as([N]T, vec);
155            for (as_array) |elem| try expectEqual(v, elem);
156        }
157        fn doTheTest() !void {
158            // Splats with multiple-of-8 bit types that fill a 128bit vector.
159            try testForT(16, @as(u8, 0xEE));
160            try testForT(8, @as(u16, 0xBEEF));
161            try testForT(4, @as(u32, 0xDEADBEEF));
162            try testForT(2, @as(u64, 0xCAFEF00DDEADBEEF));
163
164            try testForT(8, @as(f16, 3.1415));
165            try testForT(4, @as(f32, 3.1415));
166            try testForT(2, @as(f64, 3.1415));
167
168            // Same but fill more than 128 bits.
169            try testForT(16 * 2, @as(u8, 0xEE));
170            try testForT(8 * 2, @as(u16, 0xBEEF));
171            try testForT(4 * 2, @as(u32, 0xDEADBEEF));
172            try testForT(2 * 2, @as(u64, 0xCAFEF00DDEADBEEF));
173
174            try testForT(8 * 2, @as(f16, 3.1415));
175            try testForT(4 * 2, @as(f32, 3.1415));
176            try testForT(2 * 2, @as(f64, 3.1415));
177        }
178    };
179    try S.doTheTest();
180    comptime try S.doTheTest();
181}
182
183test "load vector elements via comptime index" {
184    const S = struct {
185        fn doTheTest() !void {
186            var v: Vector(4, i32) = [_]i32{ 1, 2, 3, undefined };
187            try expect(v[0] == 1);
188            try expect(v[1] == 2);
189            try expect(loadv(&v[2]) == 3);
190        }
191        fn loadv(ptr: anytype) i32 {
192            return ptr.*;
193        }
194    };
195
196    try S.doTheTest();
197    comptime try S.doTheTest();
198}
199
200test "store vector elements via comptime index" {
201    const S = struct {
202        fn doTheTest() !void {
203            var v: Vector(4, i32) = [_]i32{ 1, 5, 3, undefined };
204
205            v[2] = 42;
206            try expect(v[1] == 5);
207            v[3] = -364;
208            try expect(v[2] == 42);
209            try expect(-364 == v[3]);
210
211            storev(&v[0], 100);
212            try expect(v[0] == 100);
213        }
214        fn storev(ptr: anytype, x: i32) void {
215            ptr.* = x;
216        }
217    };
218
219    try S.doTheTest();
220    comptime try S.doTheTest();
221}
222
223test "load vector elements via runtime index" {
224    const S = struct {
225        fn doTheTest() !void {
226            var v: Vector(4, i32) = [_]i32{ 1, 2, 3, undefined };
227            var i: u32 = 0;
228            try expect(v[i] == 1);
229            i += 1;
230            try expect(v[i] == 2);
231            i += 1;
232            try expect(v[i] == 3);
233        }
234    };
235
236    try S.doTheTest();
237    comptime try S.doTheTest();
238}
239
240test "store vector elements via runtime index" {
241    const S = struct {
242        fn doTheTest() !void {
243            var v: Vector(4, i32) = [_]i32{ 1, 5, 3, undefined };
244            var i: u32 = 2;
245            v[i] = 1;
246            try expect(v[1] == 5);
247            try expect(v[2] == 1);
248            i += 1;
249            v[i] = -364;
250            try expect(-364 == v[3]);
251        }
252    };
253
254    try S.doTheTest();
255    comptime try S.doTheTest();
256}
257
258test "initialize vector which is a struct field" {
259    const Vec4Obj = struct {
260        data: Vector(4, f32),
261    };
262
263    const S = struct {
264        fn doTheTest() !void {
265            var foo = Vec4Obj{
266                .data = [_]f32{ 1, 2, 3, 4 },
267            };
268            _ = foo;
269        }
270    };
271    try S.doTheTest();
272    comptime try S.doTheTest();
273}
274
275test "vector comparison operators" {
276    const S = struct {
277        fn doTheTest() !void {
278            {
279                const v1: Vector(4, bool) = [_]bool{ true, false, true, false };
280                const v2: Vector(4, bool) = [_]bool{ false, true, false, true };
281                try expectEqual(@splat(4, true), v1 == v1);
282                try expectEqual(@splat(4, false), v1 == v2);
283                try expectEqual(@splat(4, true), v1 != v2);
284                try expectEqual(@splat(4, false), v2 != v2);
285            }
286            {
287                const v1 = @splat(4, @as(u32, 0xc0ffeeee));
288                const v2: Vector(4, c_uint) = v1;
289                const v3 = @splat(4, @as(u32, 0xdeadbeef));
290                try expectEqual(@splat(4, true), v1 == v2);
291                try expectEqual(@splat(4, false), v1 == v3);
292                try expectEqual(@splat(4, true), v1 != v3);
293                try expectEqual(@splat(4, false), v1 != v2);
294            }
295            {
296                // Comptime-known LHS/RHS
297                var v1: @Vector(4, u32) = [_]u32{ 2, 1, 2, 1 };
298                const v2 = @splat(4, @as(u32, 2));
299                const v3: @Vector(4, bool) = [_]bool{ true, false, true, false };
300                try expectEqual(v3, v1 == v2);
301                try expectEqual(v3, v2 == v1);
302            }
303        }
304    };
305    try S.doTheTest();
306    comptime try S.doTheTest();
307}
308
309test "vector division operators" {
310    const S = struct {
311        fn doTheTestDiv(comptime T: type, x: Vector(4, T), y: Vector(4, T)) !void {
312            if (!comptime std.meta.trait.isSignedInt(T)) {
313                const d0 = x / y;
314                for (@as([4]T, d0)) |v, i| {
315                    try expectEqual(x[i] / y[i], v);
316                }
317            }
318            const d1 = @divExact(x, y);
319            for (@as([4]T, d1)) |v, i| {
320                try expectEqual(@divExact(x[i], y[i]), v);
321            }
322            const d2 = @divFloor(x, y);
323            for (@as([4]T, d2)) |v, i| {
324                try expectEqual(@divFloor(x[i], y[i]), v);
325            }
326            const d3 = @divTrunc(x, y);
327            for (@as([4]T, d3)) |v, i| {
328                try expectEqual(@divTrunc(x[i], y[i]), v);
329            }
330        }
331
332        fn doTheTestMod(comptime T: type, x: Vector(4, T), y: Vector(4, T)) !void {
333            if ((!comptime std.meta.trait.isSignedInt(T)) and @typeInfo(T) != .Float) {
334                const r0 = x % y;
335                for (@as([4]T, r0)) |v, i| {
336                    try expectEqual(x[i] % y[i], v);
337                }
338            }
339            const r1 = @mod(x, y);
340            for (@as([4]T, r1)) |v, i| {
341                try expectEqual(@mod(x[i], y[i]), v);
342            }
343            const r2 = @rem(x, y);
344            for (@as([4]T, r2)) |v, i| {
345                try expectEqual(@rem(x[i], y[i]), v);
346            }
347        }
348
349        fn doTheTest() !void {
350            // https://github.com/ziglang/zig/issues/4952
351            if (builtin.target.os.tag != .windows) {
352                try doTheTestDiv(f16, [4]f16{ 4.0, -4.0, 4.0, -4.0 }, [4]f16{ 1.0, 2.0, -1.0, -2.0 });
353            }
354
355            try doTheTestDiv(f32, [4]f32{ 4.0, -4.0, 4.0, -4.0 }, [4]f32{ 1.0, 2.0, -1.0, -2.0 });
356            try doTheTestDiv(f64, [4]f64{ 4.0, -4.0, 4.0, -4.0 }, [4]f64{ 1.0, 2.0, -1.0, -2.0 });
357
358            // https://github.com/ziglang/zig/issues/4952
359            if (builtin.target.os.tag != .windows) {
360                try doTheTestMod(f16, [4]f16{ 4.0, -4.0, 4.0, -4.0 }, [4]f16{ 1.0, 2.0, 0.5, 3.0 });
361            }
362            try doTheTestMod(f32, [4]f32{ 4.0, -4.0, 4.0, -4.0 }, [4]f32{ 1.0, 2.0, 0.5, 3.0 });
363            try doTheTestMod(f64, [4]f64{ 4.0, -4.0, 4.0, -4.0 }, [4]f64{ 1.0, 2.0, 0.5, 3.0 });
364
365            try doTheTestDiv(i8, [4]i8{ 4, -4, 4, -4 }, [4]i8{ 1, 2, -1, -2 });
366            try doTheTestDiv(i16, [4]i16{ 4, -4, 4, -4 }, [4]i16{ 1, 2, -1, -2 });
367            try doTheTestDiv(i32, [4]i32{ 4, -4, 4, -4 }, [4]i32{ 1, 2, -1, -2 });
368            try doTheTestDiv(i64, [4]i64{ 4, -4, 4, -4 }, [4]i64{ 1, 2, -1, -2 });
369
370            try doTheTestMod(i8, [4]i8{ 4, -4, 4, -4 }, [4]i8{ 1, 2, 4, 8 });
371            try doTheTestMod(i16, [4]i16{ 4, -4, 4, -4 }, [4]i16{ 1, 2, 4, 8 });
372            try doTheTestMod(i32, [4]i32{ 4, -4, 4, -4 }, [4]i32{ 1, 2, 4, 8 });
373            try doTheTestMod(i64, [4]i64{ 4, -4, 4, -4 }, [4]i64{ 1, 2, 4, 8 });
374
375            try doTheTestDiv(u8, [4]u8{ 1, 2, 4, 8 }, [4]u8{ 1, 1, 2, 4 });
376            try doTheTestDiv(u16, [4]u16{ 1, 2, 4, 8 }, [4]u16{ 1, 1, 2, 4 });
377            try doTheTestDiv(u32, [4]u32{ 1, 2, 4, 8 }, [4]u32{ 1, 1, 2, 4 });
378            try doTheTestDiv(u64, [4]u64{ 1, 2, 4, 8 }, [4]u64{ 1, 1, 2, 4 });
379
380            try doTheTestMod(u8, [4]u8{ 1, 2, 4, 8 }, [4]u8{ 1, 1, 2, 4 });
381            try doTheTestMod(u16, [4]u16{ 1, 2, 4, 8 }, [4]u16{ 1, 1, 2, 4 });
382            try doTheTestMod(u32, [4]u32{ 1, 2, 4, 8 }, [4]u32{ 1, 1, 2, 4 });
383            try doTheTestMod(u64, [4]u64{ 1, 2, 4, 8 }, [4]u64{ 1, 1, 2, 4 });
384        }
385    };
386
387    try S.doTheTest();
388    comptime try S.doTheTest();
389}
390
391test "vector bitwise not operator" {
392    const S = struct {
393        fn doTheTestNot(comptime T: type, x: Vector(4, T)) !void {
394            var y = ~x;
395            for (@as([4]T, y)) |v, i| {
396                try expectEqual(~x[i], v);
397            }
398        }
399        fn doTheTest() !void {
400            try doTheTestNot(u8, [_]u8{ 0, 2, 4, 255 });
401            try doTheTestNot(u16, [_]u16{ 0, 2, 4, 255 });
402            try doTheTestNot(u32, [_]u32{ 0, 2, 4, 255 });
403            try doTheTestNot(u64, [_]u64{ 0, 2, 4, 255 });
404
405            try doTheTestNot(u8, [_]u8{ 0, 2, 4, 255 });
406            try doTheTestNot(u16, [_]u16{ 0, 2, 4, 255 });
407            try doTheTestNot(u32, [_]u32{ 0, 2, 4, 255 });
408            try doTheTestNot(u64, [_]u64{ 0, 2, 4, 255 });
409        }
410    };
411
412    try S.doTheTest();
413    comptime try S.doTheTest();
414}
415
416test "vector shift operators" {
417    const S = struct {
418        fn doTheTestShift(x: anytype, y: anytype) !void {
419            const N = @typeInfo(@TypeOf(x)).Array.len;
420            const TX = @typeInfo(@TypeOf(x)).Array.child;
421            const TY = @typeInfo(@TypeOf(y)).Array.child;
422
423            var xv = @as(Vector(N, TX), x);
424            var yv = @as(Vector(N, TY), y);
425
426            var z0 = xv >> yv;
427            for (@as([N]TX, z0)) |v, i| {
428                try expectEqual(x[i] >> y[i], v);
429            }
430            var z1 = xv << yv;
431            for (@as([N]TX, z1)) |v, i| {
432                try expectEqual(x[i] << y[i], v);
433            }
434        }
435        fn doTheTestShiftExact(x: anytype, y: anytype, dir: enum { Left, Right }) !void {
436            const N = @typeInfo(@TypeOf(x)).Array.len;
437            const TX = @typeInfo(@TypeOf(x)).Array.child;
438            const TY = @typeInfo(@TypeOf(y)).Array.child;
439
440            var xv = @as(Vector(N, TX), x);
441            var yv = @as(Vector(N, TY), y);
442
443            var z = if (dir == .Left) @shlExact(xv, yv) else @shrExact(xv, yv);
444            for (@as([N]TX, z)) |v, i| {
445                const check = if (dir == .Left) x[i] << y[i] else x[i] >> y[i];
446                try expectEqual(check, v);
447            }
448        }
449        fn doTheTest() !void {
450            try doTheTestShift([_]u8{ 0, 2, 4, math.maxInt(u8) }, [_]u3{ 2, 0, 2, 7 });
451            try doTheTestShift([_]u16{ 0, 2, 4, math.maxInt(u16) }, [_]u4{ 2, 0, 2, 15 });
452            try doTheTestShift([_]u24{ 0, 2, 4, math.maxInt(u24) }, [_]u5{ 2, 0, 2, 23 });
453            try doTheTestShift([_]u32{ 0, 2, 4, math.maxInt(u32) }, [_]u5{ 2, 0, 2, 31 });
454            try doTheTestShift([_]u64{ 0xfe, math.maxInt(u64) }, [_]u6{ 0, 63 });
455
456            try doTheTestShift([_]i8{ 0, 2, 4, math.maxInt(i8) }, [_]u3{ 2, 0, 2, 7 });
457            try doTheTestShift([_]i16{ 0, 2, 4, math.maxInt(i16) }, [_]u4{ 2, 0, 2, 7 });
458            try doTheTestShift([_]i24{ 0, 2, 4, math.maxInt(i24) }, [_]u5{ 2, 0, 2, 7 });
459            try doTheTestShift([_]i32{ 0, 2, 4, math.maxInt(i32) }, [_]u5{ 2, 0, 2, 7 });
460            try doTheTestShift([_]i64{ 0xfe, math.maxInt(i64) }, [_]u6{ 0, 63 });
461
462            try doTheTestShiftExact([_]u8{ 0, 1, 1 << 7, math.maxInt(u8) ^ 1 }, [_]u3{ 4, 0, 7, 1 }, .Right);
463            try doTheTestShiftExact([_]u16{ 0, 1, 1 << 15, math.maxInt(u16) ^ 1 }, [_]u4{ 4, 0, 15, 1 }, .Right);
464            try doTheTestShiftExact([_]u24{ 0, 1, 1 << 23, math.maxInt(u24) ^ 1 }, [_]u5{ 4, 0, 23, 1 }, .Right);
465            try doTheTestShiftExact([_]u32{ 0, 1, 1 << 31, math.maxInt(u32) ^ 1 }, [_]u5{ 4, 0, 31, 1 }, .Right);
466            try doTheTestShiftExact([_]u64{ 1 << 63, 1 }, [_]u6{ 63, 0 }, .Right);
467
468            try doTheTestShiftExact([_]u8{ 0, 1, 1, math.maxInt(u8) ^ (1 << 7) }, [_]u3{ 4, 0, 7, 1 }, .Left);
469            try doTheTestShiftExact([_]u16{ 0, 1, 1, math.maxInt(u16) ^ (1 << 15) }, [_]u4{ 4, 0, 15, 1 }, .Left);
470            try doTheTestShiftExact([_]u24{ 0, 1, 1, math.maxInt(u24) ^ (1 << 23) }, [_]u5{ 4, 0, 23, 1 }, .Left);
471            try doTheTestShiftExact([_]u32{ 0, 1, 1, math.maxInt(u32) ^ (1 << 31) }, [_]u5{ 4, 0, 31, 1 }, .Left);
472            try doTheTestShiftExact([_]u64{ 1 << 63, 1 }, [_]u6{ 0, 63 }, .Left);
473        }
474    };
475
476    switch (builtin.target.cpu.arch) {
477        .i386,
478        .aarch64,
479        .aarch64_be,
480        .aarch64_32,
481        .arm,
482        .armeb,
483        .thumb,
484        .thumbeb,
485        .mips,
486        .mipsel,
487        .mips64,
488        .mips64el,
489        .riscv64,
490        .sparcv9,
491        => {
492            // LLVM miscompiles on this architecture
493            // https://github.com/ziglang/zig/issues/4951
494            return error.SkipZigTest;
495        },
496        else => {},
497    }
498
499    try S.doTheTest();
500    comptime try S.doTheTest();
501}
502
503test "vector reduce operation" {
504    const S = struct {
505        fn doTheTestReduce(comptime op: std.builtin.ReduceOp, x: anytype, expected: anytype) !void {
506            const N = @typeInfo(@TypeOf(x)).Array.len;
507            const TX = @typeInfo(@TypeOf(x)).Array.child;
508
509            var r = @reduce(op, @as(Vector(N, TX), x));
510            switch (@typeInfo(TX)) {
511                .Int, .Bool => try expectEqual(expected, r),
512                .Float => {
513                    const expected_nan = math.isNan(expected);
514                    const got_nan = math.isNan(r);
515
516                    if (expected_nan and got_nan) {
517                        // Do this check explicitly as two NaN values are never
518                        // equal.
519                    } else {
520                        try expectApproxEqRel(expected, r, math.sqrt(math.epsilon(TX)));
521                    }
522                },
523                else => unreachable,
524            }
525        }
526        fn doTheTest() !void {
527            try doTheTestReduce(.Add, [4]i16{ -9, -99, -999, -9999 }, @as(i32, -11106));
528            try doTheTestReduce(.Add, [4]u16{ 9, 99, 999, 9999 }, @as(u32, 11106));
529            try doTheTestReduce(.Add, [4]i32{ -9, -99, -999, -9999 }, @as(i32, -11106));
530            try doTheTestReduce(.Add, [4]u32{ 9, 99, 999, 9999 }, @as(u32, 11106));
531            try doTheTestReduce(.Add, [4]i64{ -9, -99, -999, -9999 }, @as(i64, -11106));
532            try doTheTestReduce(.Add, [4]u64{ 9, 99, 999, 9999 }, @as(u64, 11106));
533            try doTheTestReduce(.Add, [4]i128{ -9, -99, -999, -9999 }, @as(i128, -11106));
534            try doTheTestReduce(.Add, [4]u128{ 9, 99, 999, 9999 }, @as(u128, 11106));
535            try doTheTestReduce(.Add, [4]f16{ -1.9, 5.1, -60.3, 100.0 }, @as(f16, 42.9));
536            try doTheTestReduce(.Add, [4]f32{ -1.9, 5.1, -60.3, 100.0 }, @as(f32, 42.9));
537            try doTheTestReduce(.Add, [4]f64{ -1.9, 5.1, -60.3, 100.0 }, @as(f64, 42.9));
538
539            try doTheTestReduce(.And, [4]bool{ true, false, true, true }, @as(bool, false));
540            try doTheTestReduce(.And, [4]u1{ 1, 0, 1, 1 }, @as(u1, 0));
541            try doTheTestReduce(.And, [4]u16{ 0xffff, 0xff55, 0xaaff, 0x1010 }, @as(u16, 0x10));
542            try doTheTestReduce(.And, [4]u32{ 0xffffffff, 0xffff5555, 0xaaaaffff, 0x10101010 }, @as(u32, 0x1010));
543            try doTheTestReduce(.And, [4]u64{ 0xffffffff, 0xffff5555, 0xaaaaffff, 0x10101010 }, @as(u64, 0x1010));
544
545            try doTheTestReduce(.Min, [4]i16{ -1, 2, 3, 4 }, @as(i16, -1));
546            try doTheTestReduce(.Min, [4]u16{ 1, 2, 3, 4 }, @as(u16, 1));
547            try doTheTestReduce(.Min, [4]i32{ 1234567, -386, 0, 3 }, @as(i32, -386));
548            try doTheTestReduce(.Min, [4]u32{ 99, 9999, 9, 99999 }, @as(u32, 9));
549
550            // LLVM 11 ERROR: Cannot select type
551            // https://github.com/ziglang/zig/issues/7138
552            if (builtin.target.cpu.arch != .aarch64) {
553                try doTheTestReduce(.Min, [4]i64{ 1234567, -386, 0, 3 }, @as(i64, -386));
554                try doTheTestReduce(.Min, [4]u64{ 99, 9999, 9, 99999 }, @as(u64, 9));
555            }
556
557            try doTheTestReduce(.Min, [4]i128{ 1234567, -386, 0, 3 }, @as(i128, -386));
558            try doTheTestReduce(.Min, [4]u128{ 99, 9999, 9, 99999 }, @as(u128, 9));
559            try doTheTestReduce(.Min, [4]f16{ -10.3, 10.0e9, 13.0, -100.0 }, @as(f16, -100.0));
560            try doTheTestReduce(.Min, [4]f32{ -10.3, 10.0e9, 13.0, -100.0 }, @as(f32, -100.0));
561            try doTheTestReduce(.Min, [4]f64{ -10.3, 10.0e9, 13.0, -100.0 }, @as(f64, -100.0));
562
563            try doTheTestReduce(.Max, [4]i16{ -1, 2, 3, 4 }, @as(i16, 4));
564            try doTheTestReduce(.Max, [4]u16{ 1, 2, 3, 4 }, @as(u16, 4));
565            try doTheTestReduce(.Max, [4]i32{ 1234567, -386, 0, 3 }, @as(i32, 1234567));
566            try doTheTestReduce(.Max, [4]u32{ 99, 9999, 9, 99999 }, @as(u32, 99999));
567
568            // LLVM 11 ERROR: Cannot select type
569            // https://github.com/ziglang/zig/issues/7138
570            if (builtin.target.cpu.arch != .aarch64) {
571                try doTheTestReduce(.Max, [4]i64{ 1234567, -386, 0, 3 }, @as(i64, 1234567));
572                try doTheTestReduce(.Max, [4]u64{ 99, 9999, 9, 99999 }, @as(u64, 99999));
573            }
574
575            try doTheTestReduce(.Max, [4]i128{ 1234567, -386, 0, 3 }, @as(i128, 1234567));
576            try doTheTestReduce(.Max, [4]u128{ 99, 9999, 9, 99999 }, @as(u128, 99999));
577            try doTheTestReduce(.Max, [4]f16{ -10.3, 10.0e9, 13.0, -100.0 }, @as(f16, 10.0e9));
578            try doTheTestReduce(.Max, [4]f32{ -10.3, 10.0e9, 13.0, -100.0 }, @as(f32, 10.0e9));
579            try doTheTestReduce(.Max, [4]f64{ -10.3, 10.0e9, 13.0, -100.0 }, @as(f64, 10.0e9));
580
581            try doTheTestReduce(.Mul, [4]i16{ -1, 2, 3, 4 }, @as(i16, -24));
582            try doTheTestReduce(.Mul, [4]u16{ 1, 2, 3, 4 }, @as(u16, 24));
583            try doTheTestReduce(.Mul, [4]i32{ -9, -99, -999, 999 }, @as(i32, -889218891));
584            try doTheTestReduce(.Mul, [4]u32{ 1, 2, 3, 4 }, @as(u32, 24));
585            try doTheTestReduce(.Mul, [4]i64{ 9, 99, 999, 9999 }, @as(i64, 8900199891));
586            try doTheTestReduce(.Mul, [4]u64{ 9, 99, 999, 9999 }, @as(u64, 8900199891));
587            try doTheTestReduce(.Mul, [4]i128{ -9, -99, -999, 9999 }, @as(i128, -8900199891));
588            try doTheTestReduce(.Mul, [4]u128{ 9, 99, 999, 9999 }, @as(u128, 8900199891));
589            try doTheTestReduce(.Mul, [4]f16{ -1.9, 5.1, -60.3, 100.0 }, @as(f16, 58430.7));
590            try doTheTestReduce(.Mul, [4]f32{ -1.9, 5.1, -60.3, 100.0 }, @as(f32, 58430.7));
591            try doTheTestReduce(.Mul, [4]f64{ -1.9, 5.1, -60.3, 100.0 }, @as(f64, 58430.7));
592
593            try doTheTestReduce(.Or, [4]bool{ false, true, false, false }, @as(bool, true));
594            try doTheTestReduce(.Or, [4]u1{ 0, 1, 0, 0 }, @as(u1, 1));
595            try doTheTestReduce(.Or, [4]u16{ 0xff00, 0xff00, 0xf0, 0xf }, ~@as(u16, 0));
596            try doTheTestReduce(.Or, [4]u32{ 0xffff0000, 0xff00, 0xf0, 0xf }, ~@as(u32, 0));
597            try doTheTestReduce(.Or, [4]u64{ 0xffff0000, 0xff00, 0xf0, 0xf }, @as(u64, 0xffffffff));
598            try doTheTestReduce(.Or, [4]u128{ 0xffff0000, 0xff00, 0xf0, 0xf }, @as(u128, 0xffffffff));
599
600            try doTheTestReduce(.Xor, [4]bool{ true, true, true, false }, @as(bool, true));
601            try doTheTestReduce(.Xor, [4]u1{ 1, 1, 1, 0 }, @as(u1, 1));
602            try doTheTestReduce(.Xor, [4]u16{ 0x0000, 0x3333, 0x8888, 0x4444 }, ~@as(u16, 0));
603            try doTheTestReduce(.Xor, [4]u32{ 0x00000000, 0x33333333, 0x88888888, 0x44444444 }, ~@as(u32, 0));
604            try doTheTestReduce(.Xor, [4]u64{ 0x00000000, 0x33333333, 0x88888888, 0x44444444 }, @as(u64, 0xffffffff));
605            try doTheTestReduce(.Xor, [4]u128{ 0x00000000, 0x33333333, 0x88888888, 0x44444444 }, @as(u128, 0xffffffff));
606
607            // Test the reduction on vectors containing NaNs.
608            const f16_nan = math.nan(f16);
609            const f32_nan = math.nan(f32);
610            const f64_nan = math.nan(f64);
611
612            try doTheTestReduce(.Add, [4]f16{ -1.9, 5.1, f16_nan, 100.0 }, f16_nan);
613            try doTheTestReduce(.Add, [4]f32{ -1.9, 5.1, f32_nan, 100.0 }, f32_nan);
614            try doTheTestReduce(.Add, [4]f64{ -1.9, 5.1, f64_nan, 100.0 }, f64_nan);
615
616            // LLVM 11 ERROR: Cannot select type
617            // https://github.com/ziglang/zig/issues/7138
618            if (false) {
619                try doTheTestReduce(.Min, [4]f16{ -1.9, 5.1, f16_nan, 100.0 }, f16_nan);
620                try doTheTestReduce(.Min, [4]f32{ -1.9, 5.1, f32_nan, 100.0 }, f32_nan);
621                try doTheTestReduce(.Min, [4]f64{ -1.9, 5.1, f64_nan, 100.0 }, f64_nan);
622
623                try doTheTestReduce(.Max, [4]f16{ -1.9, 5.1, f16_nan, 100.0 }, f16_nan);
624                try doTheTestReduce(.Max, [4]f32{ -1.9, 5.1, f32_nan, 100.0 }, f32_nan);
625                try doTheTestReduce(.Max, [4]f64{ -1.9, 5.1, f64_nan, 100.0 }, f64_nan);
626            }
627
628            try doTheTestReduce(.Mul, [4]f16{ -1.9, 5.1, f16_nan, 100.0 }, f16_nan);
629            try doTheTestReduce(.Mul, [4]f32{ -1.9, 5.1, f32_nan, 100.0 }, f32_nan);
630            try doTheTestReduce(.Mul, [4]f64{ -1.9, 5.1, f64_nan, 100.0 }, f64_nan);
631        }
632    };
633
634    try S.doTheTest();
635    comptime try S.doTheTest();
636}
637
638test "mask parameter of @shuffle is comptime scope" {
639    const __v4hi = std.meta.Vector(4, i16);
640    var v4_a = __v4hi{ 0, 0, 0, 0 };
641    var v4_b = __v4hi{ 0, 0, 0, 0 };
642    var shuffled: __v4hi = @shuffle(i16, v4_a, v4_b, std.meta.Vector(4, i32){
643        std.zig.c_translation.shuffleVectorIndex(0, @typeInfo(@TypeOf(v4_a)).Vector.len),
644        std.zig.c_translation.shuffleVectorIndex(0, @typeInfo(@TypeOf(v4_a)).Vector.len),
645        std.zig.c_translation.shuffleVectorIndex(0, @typeInfo(@TypeOf(v4_a)).Vector.len),
646        std.zig.c_translation.shuffleVectorIndex(0, @typeInfo(@TypeOf(v4_a)).Vector.len),
647    });
648    _ = shuffled;
649}
650
651test "saturating add" {
652    const S = struct {
653        fn doTheTest() !void {
654            const u8x3 = std.meta.Vector(3, u8);
655            try expectEqual(u8x3{ 255, 255, 255 }, (u8x3{ 255, 254, 1 } +| u8x3{ 1, 2, 255 }));
656            const i8x3 = std.meta.Vector(3, i8);
657            try expectEqual(i8x3{ 127, 127, 127 }, (i8x3{ 127, 126, 1 } +| i8x3{ 1, 2, 127 }));
658        }
659    };
660    try S.doTheTest();
661    comptime try S.doTheTest();
662}
663
664test "saturating subtraction" {
665    const S = struct {
666        fn doTheTest() !void {
667            const u8x3 = std.meta.Vector(3, u8);
668            try expectEqual(u8x3{ 0, 0, 0 }, (u8x3{ 0, 0, 0 } -| u8x3{ 255, 255, 255 }));
669        }
670    };
671    try S.doTheTest();
672    comptime try S.doTheTest();
673}
674
675test "saturating multiplication" {
676    // TODO: once #9660 has been solved, remove this line
677    if (builtin.target.cpu.arch == .wasm32) return error.SkipZigTest;
678
679    const S = struct {
680        fn doTheTest() !void {
681            const u8x3 = std.meta.Vector(3, u8);
682            try expectEqual(u8x3{ 255, 255, 255 }, (u8x3{ 2, 2, 2 } *| u8x3{ 255, 255, 255 }));
683        }
684    };
685
686    try S.doTheTest();
687    comptime try S.doTheTest();
688}
689
690test "saturating shift-left" {
691    const S = struct {
692        fn doTheTest() !void {
693            const u8x3 = std.meta.Vector(3, u8);
694            try expectEqual(u8x3{ 255, 255, 255 }, (u8x3{ 255, 255, 255 } <<| u8x3{ 1, 1, 1 }));
695        }
696    };
697    try S.doTheTest();
698    comptime try S.doTheTest();
699}
700