| 1 | const std = @import("std"); |
| 2 | const builtin = @import("builtin"); |
| 3 | const mem = std.mem; |
| 4 | const expect = std.testing.expect; |
| 5 | const expectEqual = std.testing.expectEqual; |
| 6 | |
| 7 | test "@shuffle int" { |
| 8 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 9 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 10 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 11 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 12 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 13 | |
| 14 | const S = struct { |
| 15 | fn doTheTest() !void { |
| 16 | var v: @Vector(4, i32) = [4]i32{ 2147483647, -2, 30, 40 }; |
| 17 | _ = &v; |
| 18 | var x: @Vector(4, i32) = [4]i32{ 1, 2147483647, 3, 4 }; |
| 19 | _ = &x; |
| 20 | const mask = [4]i32{ 0, ~@as(i32, 2), 3, ~@as(i32, 3) }; |
| 21 | var res = @shuffle(i32, v, x, mask); |
| 22 | try expect(mem.eql(i32, &@as([4]i32, res), &[4]i32{ 2147483647, 3, 40, 4 })); |
| 23 | |
| 24 | // Implicit cast from array (of mask) |
| 25 | res = @shuffle(i32, v, x, [4]i32{ 0, ~@as(i32, 2), 3, ~@as(i32, 3) }); |
| 26 | try expect(mem.eql(i32, &@as([4]i32, res), &[4]i32{ 2147483647, 3, 40, 4 })); |
| 27 | |
| 28 | // Undefined |
| 29 | const mask2 = [4]i32{ 3, 1, 2, 0 }; |
| 30 | res = @shuffle(i32, v, undefined, mask2); |
| 31 | try expect(mem.eql(i32, &@as([4]i32, res), &[4]i32{ 40, -2, 30, 2147483647 })); |
| 32 | |
| 33 | // Upcasting of b |
| 34 | var v2: @Vector(2, i32) = [2]i32{ 2147483647, undefined }; |
| 35 | _ = &v2; |
| 36 | const mask3 = [4]i32{ ~@as(i32, 0), 2, ~@as(i32, 0), 3 }; |
| 37 | res = @shuffle(i32, x, v2, mask3); |
| 38 | try expect(mem.eql(i32, &@as([4]i32, res), &[4]i32{ 2147483647, 3, 2147483647, 4 })); |
| 39 | |
| 40 | // Upcasting of a |
| 41 | var v3: @Vector(2, i32) = [2]i32{ 2147483647, -2 }; |
| 42 | _ = &v3; |
| 43 | const mask4 = [4]i32{ 0, ~@as(i32, 2), 1, ~@as(i32, 3) }; |
| 44 | res = @shuffle(i32, v3, x, mask4); |
| 45 | try expect(mem.eql(i32, &@as([4]i32, res), &[4]i32{ 2147483647, 3, -2, 4 })); |
| 46 | } |
| 47 | }; |
| 48 | try S.doTheTest(); |
| 49 | try comptime S.doTheTest(); |
| 50 | } |
| 51 | |
| 52 | test "@shuffle int strange sizes" { |
| 53 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 54 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 55 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 56 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 57 | try comptime testShuffle(2, 2, 2); |
| 58 | try testShuffle(2, 2, 2); |
| 59 | try comptime testShuffle(4, 4, 4); |
| 60 | try testShuffle(4, 4, 4); |
| 61 | try comptime testShuffle(7, 4, 4); |
| 62 | try testShuffle(7, 4, 4); |
| 63 | try comptime testShuffle(8, 6, 4); |
| 64 | try testShuffle(8, 6, 4); |
| 65 | try comptime testShuffle(2, 7, 5); |
| 66 | try testShuffle(2, 7, 5); |
| 67 | try comptime testShuffle(13, 16, 12); |
| 68 | try testShuffle(13, 16, 12); |
| 69 | try comptime testShuffle(19, 3, 17); |
| 70 | try testShuffle(19, 3, 17); |
| 71 | try comptime testShuffle(1, 10, 1); |
| 72 | try testShuffle(1, 10, 1); |
| 73 | } |
| 74 | |
| 75 | fn testShuffle( |
| 76 | comptime x_len: comptime_int, |
| 77 | comptime a_len: comptime_int, |
| 78 | comptime b_len: comptime_int, |
| 79 | ) !void { |
| 80 | const T = i32; |
| 81 | const XT = @Vector(x_len, T); |
| 82 | const AT = @Vector(a_len, T); |
| 83 | const BT = @Vector(b_len, T); |
| 84 | |
| 85 | const a_elems = comptime blk: { |
| 86 | var elems: [a_len]T = undefined; |
| 87 | for (&elems, 0..) |*elem, i| elem.* = @intCast(100 + i); |
| 88 | break :blk elems; |
| 89 | }; |
| 90 | var a: AT = a_elems; |
| 91 | _ = &a; |
| 92 | |
| 93 | const b_elems = comptime blk: { |
| 94 | var elems: [b_len]T = undefined; |
| 95 | for (&elems, 0..) |*elem, i| elem.* = @intCast(1000 + i); |
| 96 | break :blk elems; |
| 97 | }; |
| 98 | var b: BT = b_elems; |
| 99 | _ = &b; |
| 100 | |
| 101 | const mask_seed: []const i32 = &.{ -14, -31, 23, 1, 21, 13, 17, -21, -10, -27, -16, -5, 15, 14, -2, 26, 2, -31, -24, -16 }; |
| 102 | |
| 103 | const mask = comptime blk: { |
| 104 | var elems: [x_len]i32 = undefined; |
| 105 | for (&elems, 0..) |*elem, i| { |
| 106 | const mask_val = mask_seed[i]; |
| 107 | if (mask_val >= 0) { |
| 108 | elem.* = @mod(mask_val, a_len); |
| 109 | } else { |
| 110 | elem.* = @mod(mask_val, -b_len); |
| 111 | } |
| 112 | } |
| 113 | |
| 114 | break :blk elems; |
| 115 | }; |
| 116 | |
| 117 | const x: XT = @shuffle(T, a, b, mask); |
| 118 | |
| 119 | const x_elems: [x_len]T = x; |
| 120 | for (mask, x_elems) |m, x_elem| { |
| 121 | if (m >= 0) { |
| 122 | // Element from A |
| 123 | try expectEqual(x_elem, a_elems[@intCast(m)]); |
| 124 | } else { |
| 125 | // Element from B |
| 126 | try expectEqual(x_elem, b_elems[@intCast(~m)]); |
| 127 | } |
| 128 | } |
| 129 | } |
| 130 | |
| 131 | test "@shuffle bool 1" { |
| 132 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 133 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 134 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 135 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 136 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 137 | const S = struct { |
| 138 | fn doTheTest() !void { |
| 139 | var x: @Vector(4, bool) = [4]bool{ false, true, false, true }; |
| 140 | _ = &x; |
| 141 | var v: @Vector(2, bool) = [2]bool{ true, false }; |
| 142 | _ = &v; |
| 143 | const mask = [4]i32{ 0, ~@as(i32, 1), 1, 2 }; |
| 144 | const res = @shuffle(bool, x, v, mask); |
| 145 | try expect(mem.eql(bool, &@as([4]bool, res), &[4]bool{ false, false, true, false })); |
| 146 | } |
| 147 | }; |
| 148 | try S.doTheTest(); |
| 149 | try comptime S.doTheTest(); |
| 150 | } |
| 151 | |
| 152 | test "@shuffle bool 2" { |
| 153 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 154 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 155 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 156 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 157 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 158 | |
| 159 | const S = struct { |
| 160 | fn doTheTest() !void { |
| 161 | var x: @Vector(3, bool) = [3]bool{ false, true, false }; |
| 162 | _ = &x; |
| 163 | var v: @Vector(2, bool) = [2]bool{ true, false }; |
| 164 | _ = &v; |
| 165 | const mask = [4]i32{ 0, ~@as(i32, 1), 1, 2 }; |
| 166 | const res = @shuffle(bool, x, v, mask); |
| 167 | try expect(mem.eql(bool, &@as([4]bool, res), &[4]bool{ false, false, true, false })); |
| 168 | } |
| 169 | }; |
| 170 | try S.doTheTest(); |
| 171 | try comptime S.doTheTest(); |
| 172 | } |
| 173 | |
| 174 | test "@shuffle u0" { |
| 175 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 176 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 177 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 178 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 179 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 180 | |
| 181 | const S = struct { |
| 182 | fn doTheTest() !void { |
| 183 | var v: @Vector(4, u0) = @splat(0); |
| 184 | const mask = @Vector(4, i32){ undefined, 0, -1, 3 }; |
| 185 | _ = .{ &v, &mask }; |
| 186 | const res = @shuffle(u0, v, v, mask); |
| 187 | comptime if (!std.mem.eql(u0, &@as([4]u0, res), &[4]u0{ 0, 0, 0, 0 })) unreachable; |
| 188 | } |
| 189 | }; |
| 190 | try S.doTheTest(); |
| 191 | try comptime S.doTheTest(); |
| 192 | } |