const std = @import("std"); const builtin = @import("builtin"); const mem = std.mem; const math = std.math; const assert = std.debug.assert; const expect = std.testing.expect; const expectEqual = std.testing.expectEqual; test "implicit cast vector to array - bool" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { const a: @Vector(4, bool) = [_]bool{ true, false, true, false }; const result_array: [4]bool = a; try expect(mem.eql(bool, &result_array, &[4]bool{ true, false, true, false })); } }; try S.doTheTest(); try comptime S.doTheTest(); } test "vector wrap operators" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64 and !comptime std.Target.x86.featureSetHas(builtin.cpu.features, .sse4_1)) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { var v: @Vector(4, i32) = [4]i32{ 2147483647, -2, 30, 40 }; var x: @Vector(4, i32) = [4]i32{ 1, 2147483647, 3, 4 }; try expect(mem.eql(i32, &@as([4]i32, v +% x), &[4]i32{ -2147483648, 2147483645, 33, 44 })); try expect(mem.eql(i32, &@as([4]i32, v -% x), &[4]i32{ 2147483646, 2147483647, 27, 36 })); try expect(mem.eql(i32, &@as([4]i32, v *% x), &[4]i32{ 2147483647, 2, 90, 160 })); var z: @Vector(4, i32) = [4]i32{ 1, 2, 3, -2147483648 }; try expect(mem.eql(i32, &@as([4]i32, -%z), &[4]i32{ -1, -2, -3, -2147483648 })); } }; try S.doTheTest(); try comptime S.doTheTest(); } test "vector bin compares with mem.eql" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { var v: @Vector(4, i32) = [4]i32{ 2147483647, -2, 30, 40 }; var x: @Vector(4, i32) = [4]i32{ 1, 2147483647, 30, 4 }; try expect(mem.eql(bool, &@as([4]bool, v == x), &[4]bool{ false, false, true, false })); try expect(mem.eql(bool, &@as([4]bool, v != x), &[4]bool{ true, true, false, true })); try expect(mem.eql(bool, &@as([4]bool, v < x), &[4]bool{ false, true, false, false })); try expect(mem.eql(bool, &@as([4]bool, v > x), &[4]bool{ true, false, false, true })); try expect(mem.eql(bool, &@as([4]bool, v <= x), &[4]bool{ false, true, true, false })); try expect(mem.eql(bool, &@as([4]bool, v >= x), &[4]bool{ true, false, true, true })); } }; try S.doTheTest(); try comptime S.doTheTest(); } test "vector int operators" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { var v: @Vector(4, i32) = [4]i32{ 10, 20, 30, 40 }; var x: @Vector(4, i32) = [4]i32{ 1, 2, 3, 4 }; try expect(mem.eql(i32, &@as([4]i32, v + x), &[4]i32{ 11, 22, 33, 44 })); try expect(mem.eql(i32, &@as([4]i32, v - x), &[4]i32{ 9, 18, 27, 36 })); try expect(mem.eql(i32, &@as([4]i32, v * x), &[4]i32{ 10, 40, 90, 160 })); try expect(mem.eql(i32, &@as([4]i32, -v), &[4]i32{ -10, -20, -30, -40 })); } }; try S.doTheTest(); try comptime S.doTheTest(); } test "vector float operators" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest; inline for ([_]type{ f16, f32, f64, f80, f128 }) |T| { const S = struct { fn doTheTest() !void { var v: @Vector(4, T) = [4]T{ 10, 20, 30, 40 }; var x: @Vector(4, T) = [4]T{ 1, 2, 3, 4 }; try expect(mem.eql(T, &@as([4]T, v + x), &[4]T{ 11, 22, 33, 44 })); try expect(mem.eql(T, &@as([4]T, v - x), &[4]T{ 9, 18, 27, 36 })); try expect(mem.eql(T, &@as([4]T, v * x), &[4]T{ 10, 40, 90, 160 })); try expect(mem.eql(T, &@as([4]T, -x), &[4]T{ -1, -2, -3, -4 })); } }; try S.doTheTest(); try comptime S.doTheTest(); } } test "vector bit operators" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { var v: @Vector(4, u8) = [4]u8{ 0b10101010, 0b10101010, 0b10101010, 0b10101010 }; var x: @Vector(4, u8) = [4]u8{ 0b11110000, 0b00001111, 0b10101010, 0b01010101 }; try expect(mem.eql(u8, &@as([4]u8, v ^ x), &[4]u8{ 0b01011010, 0b10100101, 0b00000000, 0b11111111 })); try expect(mem.eql(u8, &@as([4]u8, v | x), &[4]u8{ 0b11111010, 0b10101111, 0b10101010, 0b11111111 })); try expect(mem.eql(u8, &@as([4]u8, v & x), &[4]u8{ 0b10100000, 0b00001010, 0b10101010, 0b00000000 })); } }; try S.doTheTest(); try comptime S.doTheTest(); } test "implicit cast vector to array" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { var a: @Vector(4, i32) = [_]i32{ 1, 2, 3, 4 }; var result_array: [4]i32 = a; result_array = a; try expect(mem.eql(i32, &result_array, &[4]i32{ 1, 2, 3, 4 })); } }; try S.doTheTest(); try comptime S.doTheTest(); } test "array to vector" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { var foo: f32 = 3.14; var arr = [4]f32{ foo, 1.5, 0.0, 0.0 }; var vec: @Vector(4, f32) = arr; try expect(mem.eql(f32, &@as([4]f32, vec), &arr)); } }; try S.doTheTest(); try comptime S.doTheTest(); } test "array vector coercion - odd sizes" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; const S = struct { fn doTheTest() !void { var foo1: i48 = 124578; var vec1: @Vector(2, i48) = [2]i48{ foo1, 1 }; var arr1: [2]i48 = vec1; try expect(vec1[0] == foo1 and vec1[1] == 1); try expect(arr1[0] == foo1 and arr1[1] == 1); var foo2: u4 = 5; var vec2: @Vector(2, u4) = [2]u4{ foo2, 1 }; var arr2: [2]u4 = vec2; try expect(vec2[0] == foo2 and vec2[1] == 1); try expect(arr2[0] == foo2 and arr2[1] == 1); var foo3: u13 = 13; var vec3: @Vector(3, u13) = [3]u13{ foo3, 0, 1 }; var arr3: [3]u13 = vec3; try expect(vec3[0] == foo3 and vec3[1] == 0 and vec3[2] == 1); try expect(arr3[0] == foo3 and arr3[1] == 0 and arr3[2] == 1); var arr4 = [4:0]u24{ foo3, foo2, 0, 1 }; var vec4: @Vector(4, u24) = arr4; try expect(vec4[0] == foo3 and vec4[1] == foo2 and vec4[2] == 0 and vec4[3] == 1); } }; try S.doTheTest(); try comptime S.doTheTest(); } test "array to vector with element type coercion" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64 and !comptime std.Target.x86.featureSetHas(builtin.cpu.features, .f16c)) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { var foo: f16 = 3.14; var arr32 = [4]f32{ foo, 1.5, 0.0, 0.0 }; var vec: @Vector(4, f32) = [4]f16{ foo, 1.5, 0.0, 0.0 }; try std.testing.expect(std.mem.eql(f32, &@as([4]f32, vec), &arr32)); } }; try S.doTheTest(); try comptime S.doTheTest(); } test "peer type resolution with coercible element types" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { var b: @Vector(2, u8) = .{ 1, 2 }; var a: @Vector(2, u16) = .{ 2, 1 }; var t: bool = true; var c = if (t) a else b; try std.testing.expect(@TypeOf(c) == @Vector(2, u16)); } }; try comptime S.doTheTest(); } test "tuple to vector" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .aarch64) { // Regressed with LLVM 14: // https://github.com/ziglang/zig/issues/12012 return error.SkipZigTest; } const S = struct { fn doTheTest() !void { const Vec3 = @Vector(3, i32); var v: Vec3 = .{ 1, 0, 0 }; for ([_]Vec3{ .{ 0, 1, 0 }, .{ 0, 0, 1 } }) |it| { v += it; } try std.testing.expectEqual(v, Vec3{ 1, 1, 1 }); try std.testing.expectEqual(v, .{ 1, 1, 1 }); } }; try S.doTheTest(); try comptime S.doTheTest(); } test "vector casts of sizes not divisible by 8" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { { var v: @Vector(4, u3) = [4]u3{ 5, 2, 3, 0 }; var x: [4]u3 = v; try expect(mem.eql(u3, &x, &@as([4]u3, v))); } { var v: @Vector(4, u2) = [4]u2{ 1, 2, 3, 0 }; var x: [4]u2 = v; try expect(mem.eql(u2, &x, &@as([4]u2, v))); } { var v: @Vector(4, u1) = [4]u1{ 1, 0, 1, 0 }; var x: [4]u1 = v; try expect(mem.eql(u1, &x, &@as([4]u1, v))); } { var v: @Vector(4, bool) = [4]bool{ false, false, true, false }; var x: [4]bool = v; try expect(mem.eql(bool, &x, &@as([4]bool, v))); } } }; try S.doTheTest(); try comptime S.doTheTest(); } test "vector @splat" { if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .macos) { // LLVM 15 regression: https://github.com/ziglang/zig/issues/12827 return error.SkipZigTest; } const S = struct { fn testForT(comptime N: comptime_int, v: anytype) !void { const T = @TypeOf(v); var vec: @Vector(N, T) = @splat(v); var as_array = @as([N]T, vec); for (as_array) |elem| try expect(v == elem); } fn doTheTest() !void { // Splats with multiple-of-8 bit types that fill a 128bit vector. try testForT(16, @as(u8, 0xEE)); try testForT(8, @as(u16, 0xBEEF)); try testForT(4, @as(u32, 0xDEADBEEF)); try testForT(2, @as(u64, 0xCAFEF00DDEADBEEF)); try testForT(8, @as(f16, 3.1415)); try testForT(4, @as(f32, 3.1415)); try testForT(2, @as(f64, 3.1415)); // Same but fill more than 128 bits. try testForT(16 * 2, @as(u8, 0xEE)); try testForT(8 * 2, @as(u16, 0xBEEF)); try testForT(4 * 2, @as(u32, 0xDEADBEEF)); try testForT(2 * 2, @as(u64, 0xCAFEF00DDEADBEEF)); try testForT(8 * 2, @as(f16, 3.1415)); try testForT(4 * 2, @as(f32, 3.1415)); try testForT(2 * 2, @as(f64, 3.1415)); } }; try S.doTheTest(); try comptime S.doTheTest(); } test "load vector elements via comptime index" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { var v: @Vector(4, i32) = [_]i32{ 1, 2, 3, undefined }; try expect(v[0] == 1); try expect(v[1] == 2); try expect(loadv(&v[2]) == 3); } fn loadv(ptr: anytype) i32 { return ptr.*; } }; try S.doTheTest(); try comptime S.doTheTest(); } test "store vector elements via comptime index" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { var v: @Vector(4, i32) = [_]i32{ 1, 5, 3, undefined }; v[2] = 42; try expect(v[1] == 5); v[3] = -364; try expect(v[2] == 42); try expect(-364 == v[3]); storev(&v[0], 100); try expect(v[0] == 100); } fn storev(ptr: anytype, x: i32) void { ptr.* = x; } }; try S.doTheTest(); try comptime S.doTheTest(); } test "load vector elements via runtime index" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { var v: @Vector(4, i32) = [_]i32{ 1, 2, 3, undefined }; var i: u32 = 0; try expect(v[i] == 1); i += 1; try expect(v[i] == 2); i += 1; try expect(v[i] == 3); } }; try S.doTheTest(); try comptime S.doTheTest(); } test "store vector elements via runtime index" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { var v: @Vector(4, i32) = [_]i32{ 1, 5, 3, undefined }; var i: u32 = 2; v[i] = 1; try expect(v[1] == 5); try expect(v[2] == 1); i += 1; v[i] = -364; try expect(-364 == v[3]); } }; try S.doTheTest(); try comptime S.doTheTest(); } test "initialize vector which is a struct field" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const Vec4Obj = struct { data: @Vector(4, f32), }; const S = struct { fn doTheTest() !void { var foo = Vec4Obj{ .data = [_]f32{ 1, 2, 3, 4 }, }; _ = foo; } }; try S.doTheTest(); try comptime S.doTheTest(); } test "vector comparison operators" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { { const V = @Vector(4, bool); var v1: V = [_]bool{ true, false, true, false }; var v2: V = [_]bool{ false, true, false, true }; try expect(mem.eql(bool, &@as([4]bool, @as(V, @splat(true))), &@as([4]bool, v1 == v1))); try expect(mem.eql(bool, &@as([4]bool, @as(V, @splat(false))), &@as([4]bool, v1 == v2))); try expect(mem.eql(bool, &@as([4]bool, @as(V, @splat(true))), &@as([4]bool, v1 != v2))); try expect(mem.eql(bool, &@as([4]bool, @as(V, @splat(false))), &@as([4]bool, v2 != v2))); } { const V = @Vector(4, bool); var v1: @Vector(4, u32) = @splat(0xc0ffeeee); var v2: @Vector(4, c_uint) = v1; var v3: @Vector(4, u32) = @splat(0xdeadbeef); try expect(mem.eql(bool, &@as([4]bool, @as(V, @splat(true))), &@as([4]bool, v1 == v2))); try expect(mem.eql(bool, &@as([4]bool, @as(V, @splat(false))), &@as([4]bool, v1 == v3))); try expect(mem.eql(bool, &@as([4]bool, @as(V, @splat(true))), &@as([4]bool, v1 != v3))); try expect(mem.eql(bool, &@as([4]bool, @as(V, @splat(false))), &@as([4]bool, v1 != v2))); } { // Comptime-known LHS/RHS var v1: @Vector(4, u32) = [_]u32{ 2, 1, 2, 1 }; const v2: @Vector(4, u32) = @splat(2); const v3: @Vector(4, bool) = [_]bool{ true, false, true, false }; try expect(mem.eql(bool, &@as([4]bool, v3), &@as([4]bool, v1 == v2))); try expect(mem.eql(bool, &@as([4]bool, v3), &@as([4]bool, v2 == v1))); } } }; try S.doTheTest(); try comptime S.doTheTest(); } test "vector division operators" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_llvm and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { fn doTheTestDiv(comptime T: type, x: @Vector(4, T), y: @Vector(4, T)) !void { if (!comptime std.meta.trait.isSignedInt(T)) { const d0 = x / y; for (@as([4]T, d0), 0..) |v, i| { try expect(x[i] / y[i] == v); } } const d1 = @divExact(x, y); for (@as([4]T, d1), 0..) |v, i| { try expect(@divExact(x[i], y[i]) == v); } const d2 = @divFloor(x, y); for (@as([4]T, d2), 0..) |v, i| { try expect(@divFloor(x[i], y[i]) == v); } const d3 = @divTrunc(x, y); for (@as([4]T, d3), 0..) |v, i| { try expect(@divTrunc(x[i], y[i]) == v); } } fn doTheTestMod(comptime T: type, x: @Vector(4, T), y: @Vector(4, T)) !void { if ((!comptime std.meta.trait.isSignedInt(T)) and @typeInfo(T) != .Float) { const r0 = x % y; for (@as([4]T, r0), 0..) |v, i| { try expect(x[i] % y[i] == v); } } const r1 = @mod(x, y); for (@as([4]T, r1), 0..) |v, i| { try expect(@mod(x[i], y[i]) == v); } const r2 = @rem(x, y); for (@as([4]T, r2), 0..) |v, i| { try expect(@rem(x[i], y[i]) == v); } } fn doTheTest() !void { try doTheTestDiv(f16, [4]f16{ 4.0, -4.0, 4.0, -4.0 }, [4]f16{ 1.0, 2.0, -1.0, -2.0 }); try doTheTestDiv(f32, [4]f32{ 4.0, -4.0, 4.0, -4.0 }, [4]f32{ 1.0, 2.0, -1.0, -2.0 }); try doTheTestDiv(f64, [4]f64{ 4.0, -4.0, 4.0, -4.0 }, [4]f64{ 1.0, 2.0, -1.0, -2.0 }); try doTheTestMod(f16, [4]f16{ 4.0, -4.0, 4.0, -4.0 }, [4]f16{ 1.0, 2.0, 0.5, 3.0 }); try doTheTestMod(f32, [4]f32{ 4.0, -4.0, 4.0, -4.0 }, [4]f32{ 1.0, 2.0, 0.5, 3.0 }); try doTheTestMod(f64, [4]f64{ 4.0, -4.0, 4.0, -4.0 }, [4]f64{ 1.0, 2.0, 0.5, 3.0 }); try doTheTestDiv(i8, [4]i8{ 4, -4, 4, -4 }, [4]i8{ 1, 2, -1, -2 }); try doTheTestDiv(i16, [4]i16{ 4, -4, 4, -4 }, [4]i16{ 1, 2, -1, -2 }); try doTheTestDiv(i32, [4]i32{ 4, -4, 4, -4 }, [4]i32{ 1, 2, -1, -2 }); try doTheTestDiv(i64, [4]i64{ 4, -4, 4, -4 }, [4]i64{ 1, 2, -1, -2 }); try doTheTestMod(i8, [4]i8{ 4, -4, 4, -4 }, [4]i8{ 1, 2, 4, 8 }); try doTheTestMod(i16, [4]i16{ 4, -4, 4, -4 }, [4]i16{ 1, 2, 4, 8 }); try doTheTestMod(i32, [4]i32{ 4, -4, 4, -4 }, [4]i32{ 1, 2, 4, 8 }); try doTheTestMod(i64, [4]i64{ 4, -4, 4, -4 }, [4]i64{ 1, 2, 4, 8 }); try doTheTestDiv(u8, [4]u8{ 1, 2, 4, 8 }, [4]u8{ 1, 1, 2, 4 }); try doTheTestDiv(u16, [4]u16{ 1, 2, 4, 8 }, [4]u16{ 1, 1, 2, 4 }); try doTheTestDiv(u32, [4]u32{ 1, 2, 4, 8 }, [4]u32{ 1, 1, 2, 4 }); try doTheTestDiv(u64, [4]u64{ 1, 2, 4, 8 }, [4]u64{ 1, 1, 2, 4 }); try doTheTestMod(u8, [4]u8{ 1, 2, 4, 8 }, [4]u8{ 1, 1, 2, 4 }); try doTheTestMod(u16, [4]u16{ 1, 2, 4, 8 }, [4]u16{ 1, 1, 2, 4 }); try doTheTestMod(u32, [4]u32{ 1, 2, 4, 8 }, [4]u32{ 1, 1, 2, 4 }); try doTheTestMod(u64, [4]u64{ 1, 2, 4, 8 }, [4]u64{ 1, 1, 2, 4 }); } }; try S.doTheTest(); try comptime S.doTheTest(); } test "vector bitwise not operator" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { fn doTheTestNot(comptime T: type, x: @Vector(4, T)) !void { var y = ~x; for (@as([4]T, y), 0..) |v, i| { try expect(~x[i] == v); } } fn doTheTest() !void { try doTheTestNot(u8, [_]u8{ 0, 2, 4, 255 }); try doTheTestNot(u16, [_]u16{ 0, 2, 4, 255 }); try doTheTestNot(u32, [_]u32{ 0, 2, 4, 255 }); try doTheTestNot(u64, [_]u64{ 0, 2, 4, 255 }); try doTheTestNot(u8, [_]u8{ 0, 2, 4, 255 }); try doTheTestNot(u16, [_]u16{ 0, 2, 4, 255 }); try doTheTestNot(u32, [_]u32{ 0, 2, 4, 255 }); try doTheTestNot(u64, [_]u64{ 0, 2, 4, 255 }); } }; try S.doTheTest(); try comptime S.doTheTest(); } test "vector shift operators" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { fn doTheTestShift(x: anytype, y: anytype) !void { const N = @typeInfo(@TypeOf(x)).Array.len; const TX = @typeInfo(@TypeOf(x)).Array.child; const TY = @typeInfo(@TypeOf(y)).Array.child; var xv = @as(@Vector(N, TX), x); var yv = @as(@Vector(N, TY), y); var z0 = xv >> yv; for (@as([N]TX, z0), 0..) |v, i| { try expect(x[i] >> y[i] == v); } var z1 = xv << yv; for (@as([N]TX, z1), 0..) |v, i| { try expect(x[i] << y[i] == v); } } fn doTheTestShiftExact(x: anytype, y: anytype, dir: enum { Left, Right }) !void { const N = @typeInfo(@TypeOf(x)).Array.len; const TX = @typeInfo(@TypeOf(x)).Array.child; const TY = @typeInfo(@TypeOf(y)).Array.child; var xv = @as(@Vector(N, TX), x); var yv = @as(@Vector(N, TY), y); var z = if (dir == .Left) @shlExact(xv, yv) else @shrExact(xv, yv); for (@as([N]TX, z), 0..) |v, i| { const check = if (dir == .Left) x[i] << y[i] else x[i] >> y[i]; try expect(check == v); } } fn doTheTest() !void { try doTheTestShift([_]u8{ 0, 2, 4, math.maxInt(u8) }, [_]u3{ 2, 0, 2, 7 }); try doTheTestShift([_]u16{ 0, 2, 4, math.maxInt(u16) }, [_]u4{ 2, 0, 2, 15 }); try doTheTestShift([_]u24{ 0, 2, 4, math.maxInt(u24) }, [_]u5{ 2, 0, 2, 23 }); try doTheTestShift([_]u32{ 0, 2, 4, math.maxInt(u32) }, [_]u5{ 2, 0, 2, 31 }); try doTheTestShift([_]u64{ 0xfe, math.maxInt(u64) }, [_]u6{ 0, 63 }); try doTheTestShift([_]i8{ 0, 2, 4, math.maxInt(i8) }, [_]u3{ 2, 0, 2, 7 }); try doTheTestShift([_]i16{ 0, 2, 4, math.maxInt(i16) }, [_]u4{ 2, 0, 2, 7 }); try doTheTestShift([_]i24{ 0, 2, 4, math.maxInt(i24) }, [_]u5{ 2, 0, 2, 7 }); try doTheTestShift([_]i32{ 0, 2, 4, math.maxInt(i32) }, [_]u5{ 2, 0, 2, 7 }); try doTheTestShift([_]i64{ 0xfe, math.maxInt(i64) }, [_]u6{ 0, 63 }); try doTheTestShiftExact([_]u8{ 0, 1, 1 << 7, math.maxInt(u8) ^ 1 }, [_]u3{ 4, 0, 7, 1 }, .Right); try doTheTestShiftExact([_]u16{ 0, 1, 1 << 15, math.maxInt(u16) ^ 1 }, [_]u4{ 4, 0, 15, 1 }, .Right); try doTheTestShiftExact([_]u24{ 0, 1, 1 << 23, math.maxInt(u24) ^ 1 }, [_]u5{ 4, 0, 23, 1 }, .Right); try doTheTestShiftExact([_]u32{ 0, 1, 1 << 31, math.maxInt(u32) ^ 1 }, [_]u5{ 4, 0, 31, 1 }, .Right); try doTheTestShiftExact([_]u64{ 1 << 63, 1 }, [_]u6{ 63, 0 }, .Right); try doTheTestShiftExact([_]u8{ 0, 1, 1, math.maxInt(u8) ^ (1 << 7) }, [_]u3{ 4, 0, 7, 1 }, .Left); try doTheTestShiftExact([_]u16{ 0, 1, 1, math.maxInt(u16) ^ (1 << 15) }, [_]u4{ 4, 0, 15, 1 }, .Left); try doTheTestShiftExact([_]u24{ 0, 1, 1, math.maxInt(u24) ^ (1 << 23) }, [_]u5{ 4, 0, 23, 1 }, .Left); try doTheTestShiftExact([_]u32{ 0, 1, 1, math.maxInt(u32) ^ (1 << 31) }, [_]u5{ 4, 0, 31, 1 }, .Left); try doTheTestShiftExact([_]u64{ 1 << 63, 1 }, [_]u6{ 0, 63 }, .Left); } }; switch (builtin.target.cpu.arch) { .x86, .aarch64, .aarch64_be, .aarch64_32, .arm, .armeb, .thumb, .thumbeb, .mips, .mipsel, .mips64, .mips64el, .riscv64, .sparc64, => { // LLVM miscompiles on this architecture // https://github.com/ziglang/zig/issues/4951 return error.SkipZigTest; }, else => {}, } try S.doTheTest(); try comptime S.doTheTest(); } test "vector reduce operation" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest; const S = struct { fn testReduce(comptime op: std.builtin.ReduceOp, x: anytype, expected: anytype) !void { const N = @typeInfo(@TypeOf(x)).Array.len; const TX = @typeInfo(@TypeOf(x)).Array.child; var r = @reduce(op, @as(@Vector(N, TX), x)); switch (@typeInfo(TX)) { .Int, .Bool => try expect(expected == r), .Float => { const expected_nan = math.isNan(expected); const got_nan = math.isNan(r); if (expected_nan and got_nan) { // Do this check explicitly as two NaN values are never // equal. } else { const F = @TypeOf(expected); const tolerance = @sqrt(math.floatEps(TX)); try expect(std.math.approxEqRel(F, expected, r, tolerance)); } }, else => unreachable, } } fn doTheTest() !void { try testReduce(.Add, [4]i16{ -9, -99, -999, -9999 }, @as(i32, -11106)); try testReduce(.Add, [4]u16{ 9, 99, 999, 9999 }, @as(u32, 11106)); try testReduce(.Add, [4]i32{ -9, -99, -999, -9999 }, @as(i32, -11106)); try testReduce(.Add, [4]u32{ 9, 99, 999, 9999 }, @as(u32, 11106)); try testReduce(.Add, [4]i64{ -9, -99, -999, -9999 }, @as(i64, -11106)); try testReduce(.Add, [4]u64{ 9, 99, 999, 9999 }, @as(u64, 11106)); try testReduce(.Add, [4]i128{ -9, -99, -999, -9999 }, @as(i128, -11106)); try testReduce(.Add, [4]u128{ 9, 99, 999, 9999 }, @as(u128, 11106)); try testReduce(.Add, [4]f16{ -1.9, 5.1, -60.3, 100.0 }, @as(f16, 42.9)); try testReduce(.Add, [4]f32{ -1.9, 5.1, -60.3, 100.0 }, @as(f32, 42.9)); try testReduce(.Add, [4]f64{ -1.9, 5.1, -60.3, 100.0 }, @as(f64, 42.9)); try testReduce(.And, [4]bool{ true, false, true, true }, @as(bool, false)); try testReduce(.And, [4]u1{ 1, 0, 1, 1 }, @as(u1, 0)); try testReduce(.And, [4]u16{ 0xffff, 0xff55, 0xaaff, 0x1010 }, @as(u16, 0x10)); try testReduce(.And, [4]u32{ 0xffffffff, 0xffff5555, 0xaaaaffff, 0x10101010 }, @as(u32, 0x1010)); try testReduce(.And, [4]u64{ 0xffffffff, 0xffff5555, 0xaaaaffff, 0x10101010 }, @as(u64, 0x1010)); try testReduce(.Min, [4]i16{ -1, 2, 3, 4 }, @as(i16, -1)); try testReduce(.Min, [4]u16{ 1, 2, 3, 4 }, @as(u16, 1)); try testReduce(.Min, [4]i32{ 1234567, -386, 0, 3 }, @as(i32, -386)); try testReduce(.Min, [4]u32{ 99, 9999, 9, 99999 }, @as(u32, 9)); // LLVM 11 ERROR: Cannot select type // https://github.com/ziglang/zig/issues/7138 if (builtin.zig_backend != .stage2_llvm or builtin.target.cpu.arch != .aarch64) { try testReduce(.Min, [4]i64{ 1234567, -386, 0, 3 }, @as(i64, -386)); try testReduce(.Min, [4]u64{ 99, 9999, 9, 99999 }, @as(u64, 9)); } try testReduce(.Min, [4]i128{ 1234567, -386, 0, 3 }, @as(i128, -386)); try testReduce(.Min, [4]u128{ 99, 9999, 9, 99999 }, @as(u128, 9)); try testReduce(.Min, [4]f16{ -10.3, 10.0e9, 13.0, -100.0 }, @as(f16, -100.0)); try testReduce(.Min, [4]f32{ -10.3, 10.0e9, 13.0, -100.0 }, @as(f32, -100.0)); try testReduce(.Min, [4]f64{ -10.3, 10.0e9, 13.0, -100.0 }, @as(f64, -100.0)); try testReduce(.Max, [4]i16{ -1, 2, 3, 4 }, @as(i16, 4)); try testReduce(.Max, [4]u16{ 1, 2, 3, 4 }, @as(u16, 4)); try testReduce(.Max, [4]i32{ 1234567, -386, 0, 3 }, @as(i32, 1234567)); try testReduce(.Max, [4]u32{ 99, 9999, 9, 99999 }, @as(u32, 99999)); // LLVM 11 ERROR: Cannot select type // https://github.com/ziglang/zig/issues/7138 if (builtin.zig_backend != .stage2_llvm or builtin.target.cpu.arch != .aarch64) { try testReduce(.Max, [4]i64{ 1234567, -386, 0, 3 }, @as(i64, 1234567)); try testReduce(.Max, [4]u64{ 99, 9999, 9, 99999 }, @as(u64, 99999)); } try testReduce(.Max, [4]i128{ 1234567, -386, 0, 3 }, @as(i128, 1234567)); try testReduce(.Max, [4]u128{ 99, 9999, 9, 99999 }, @as(u128, 99999)); try testReduce(.Max, [4]f16{ -10.3, 10.0e9, 13.0, -100.0 }, @as(f16, 10.0e9)); try testReduce(.Max, [4]f32{ -10.3, 10.0e9, 13.0, -100.0 }, @as(f32, 10.0e9)); try testReduce(.Max, [4]f64{ -10.3, 10.0e9, 13.0, -100.0 }, @as(f64, 10.0e9)); try testReduce(.Mul, [4]i16{ -1, 2, 3, 4 }, @as(i16, -24)); try testReduce(.Mul, [4]u16{ 1, 2, 3, 4 }, @as(u16, 24)); try testReduce(.Mul, [4]i32{ -9, -99, -999, 999 }, @as(i32, -889218891)); try testReduce(.Mul, [4]u32{ 1, 2, 3, 4 }, @as(u32, 24)); try testReduce(.Mul, [4]i64{ 9, 99, 999, 9999 }, @as(i64, 8900199891)); try testReduce(.Mul, [4]u64{ 9, 99, 999, 9999 }, @as(u64, 8900199891)); try testReduce(.Mul, [4]i128{ -9, -99, -999, 9999 }, @as(i128, -8900199891)); try testReduce(.Mul, [4]u128{ 9, 99, 999, 9999 }, @as(u128, 8900199891)); try testReduce(.Mul, [4]f16{ -1.9, 5.1, -60.3, 100.0 }, @as(f16, 58430.7)); try testReduce(.Mul, [4]f32{ -1.9, 5.1, -60.3, 100.0 }, @as(f32, 58430.7)); try testReduce(.Mul, [4]f64{ -1.9, 5.1, -60.3, 100.0 }, @as(f64, 58430.7)); try testReduce(.Or, [4]bool{ false, true, false, false }, @as(bool, true)); try testReduce(.Or, [4]u1{ 0, 1, 0, 0 }, @as(u1, 1)); try testReduce(.Or, [4]u16{ 0xff00, 0xff00, 0xf0, 0xf }, ~@as(u16, 0)); try testReduce(.Or, [4]u32{ 0xffff0000, 0xff00, 0xf0, 0xf }, ~@as(u32, 0)); try testReduce(.Or, [4]u64{ 0xffff0000, 0xff00, 0xf0, 0xf }, @as(u64, 0xffffffff)); try testReduce(.Or, [4]u128{ 0xffff0000, 0xff00, 0xf0, 0xf }, @as(u128, 0xffffffff)); try testReduce(.Xor, [4]bool{ true, true, true, false }, @as(bool, true)); try testReduce(.Xor, [4]u1{ 1, 1, 1, 0 }, @as(u1, 1)); try testReduce(.Xor, [4]u16{ 0x0000, 0x3333, 0x8888, 0x4444 }, ~@as(u16, 0)); try testReduce(.Xor, [4]u32{ 0x00000000, 0x33333333, 0x88888888, 0x44444444 }, ~@as(u32, 0)); try testReduce(.Xor, [4]u64{ 0x00000000, 0x33333333, 0x88888888, 0x44444444 }, @as(u64, 0xffffffff)); try testReduce(.Xor, [4]u128{ 0x00000000, 0x33333333, 0x88888888, 0x44444444 }, @as(u128, 0xffffffff)); // Test the reduction on vectors containing NaNs. const f16_nan = math.nan(f16); const f32_nan = math.nan(f32); const f64_nan = math.nan(f64); try testReduce(.Add, [4]f16{ -1.9, 5.1, f16_nan, 100.0 }, f16_nan); try testReduce(.Add, [4]f32{ -1.9, 5.1, f32_nan, 100.0 }, f32_nan); try testReduce(.Add, [4]f64{ -1.9, 5.1, f64_nan, 100.0 }, f64_nan); // LLVM 11 ERROR: Cannot select type // https://github.com/ziglang/zig/issues/7138 if (builtin.zig_backend != .stage2_llvm) { try testReduce(.Min, [4]f16{ -1.9, 5.1, f16_nan, 100.0 }, @as(f16, -1.9)); try testReduce(.Min, [4]f32{ -1.9, 5.1, f32_nan, 100.0 }, @as(f32, -1.9)); try testReduce(.Min, [4]f64{ -1.9, 5.1, f64_nan, 100.0 }, @as(f64, -1.9)); try testReduce(.Max, [4]f16{ -1.9, 5.1, f16_nan, 100.0 }, @as(f16, 100.0)); try testReduce(.Max, [4]f32{ -1.9, 5.1, f32_nan, 100.0 }, @as(f32, 100.0)); try testReduce(.Max, [4]f64{ -1.9, 5.1, f64_nan, 100.0 }, @as(f64, 100.0)); } try testReduce(.Mul, [4]f16{ -1.9, 5.1, f16_nan, 100.0 }, f16_nan); try testReduce(.Mul, [4]f32{ -1.9, 5.1, f32_nan, 100.0 }, f32_nan); try testReduce(.Mul, [4]f64{ -1.9, 5.1, f64_nan, 100.0 }, f64_nan); } }; try S.doTheTest(); try comptime S.doTheTest(); } test "vector @reduce comptime" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO const V = @Vector(4, i32); const value = V{ 1, -1, 1, -1 }; const result = value > @as(V, @splat(0)); // result is { true, false, true, false }; try comptime expect(@TypeOf(result) == @Vector(4, bool)); const is_all_true = @reduce(.And, result); try comptime expect(@TypeOf(is_all_true) == bool); try expect(is_all_true == false); } test "mask parameter of @shuffle is comptime scope" { if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const __v4hi = @Vector(4, i16); var v4_a = __v4hi{ 0, 0, 0, 0 }; var v4_b = __v4hi{ 0, 0, 0, 0 }; var shuffled: __v4hi = @shuffle(i16, v4_a, v4_b, @Vector(4, i32){ std.zig.c_translation.shuffleVectorIndex(0, @typeInfo(@TypeOf(v4_a)).Vector.len), std.zig.c_translation.shuffleVectorIndex(0, @typeInfo(@TypeOf(v4_a)).Vector.len), std.zig.c_translation.shuffleVectorIndex(0, @typeInfo(@TypeOf(v4_a)).Vector.len), std.zig.c_translation.shuffleVectorIndex(0, @typeInfo(@TypeOf(v4_a)).Vector.len), }); _ = shuffled; } test "saturating add" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { { // Broken out to avoid https://github.com/ziglang/zig/issues/11251 const u8x3 = @Vector(3, u8); var lhs = u8x3{ 255, 254, 1 }; var rhs = u8x3{ 1, 2, 255 }; var result = lhs +| rhs; const expected = u8x3{ 255, 255, 255 }; try expect(mem.eql(u8, &@as([3]u8, expected), &@as([3]u8, result))); } { // Broken out to avoid https://github.com/ziglang/zig/issues/11251 const i8x3 = @Vector(3, i8); var lhs = i8x3{ 127, 126, 1 }; var rhs = i8x3{ 1, 2, 127 }; var result = lhs +| rhs; const expected = i8x3{ 127, 127, 127 }; try expect(mem.eql(i8, &@as([3]i8, expected), &@as([3]i8, result))); } } }; try S.doTheTest(); try comptime S.doTheTest(); } test "saturating subtraction" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { // Broken out to avoid https://github.com/ziglang/zig/issues/11251 const u8x3 = @Vector(3, u8); var lhs = u8x3{ 0, 0, 0 }; var rhs = u8x3{ 255, 255, 255 }; var result = lhs -| rhs; const expected = u8x3{ 0, 0, 0 }; try expect(mem.eql(u8, &@as([3]u8, expected), &@as([3]u8, result))); } }; try S.doTheTest(); try comptime S.doTheTest(); } test "saturating multiplication" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO: once #9660 has been solved, remove this line if (builtin.target.cpu.arch == .wasm32) return error.SkipZigTest; const S = struct { fn doTheTest() !void { // Broken out to avoid https://github.com/ziglang/zig/issues/11251 const u8x3 = @Vector(3, u8); var lhs = u8x3{ 2, 2, 2 }; var rhs = u8x3{ 255, 255, 255 }; var result = lhs *| rhs; const expected = u8x3{ 255, 255, 255 }; try expect(mem.eql(u8, &@as([3]u8, expected), &@as([3]u8, result))); } }; try S.doTheTest(); try comptime S.doTheTest(); } test "saturating shift-left" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { // Broken out to avoid https://github.com/ziglang/zig/issues/11251 const u8x3 = @Vector(3, u8); var lhs = u8x3{ 1, 1, 1 }; var rhs = u8x3{ 255, 255, 255 }; var result = lhs <<| rhs; const expected = u8x3{ 255, 255, 255 }; try expect(mem.eql(u8, &@as([3]u8, expected), &@as([3]u8, result))); } }; try S.doTheTest(); try comptime S.doTheTest(); } test "multiplication-assignment operator with an array operand" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { var x: @Vector(3, i32) = .{ 1, 2, 3 }; x *= [_]i32{ 4, 5, 6 }; try expect(x[0] == 4); try expect(x[1] == 10); try expect(x[2] == 18); } }; try S.doTheTest(); try comptime S.doTheTest(); } test "@addWithOverflow" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { { var lhs = @Vector(4, u8){ 250, 250, 250, 250 }; var rhs = @Vector(4, u8){ 0, 5, 6, 10 }; var overflow = @addWithOverflow(lhs, rhs)[1]; var expected: @Vector(4, u1) = .{ 0, 0, 1, 1 }; try expectEqual(expected, overflow); } { var lhs = @Vector(4, i8){ -125, -125, 125, 125 }; var rhs = @Vector(4, i8){ -3, -4, 2, 3 }; var overflow = @addWithOverflow(lhs, rhs)[1]; var expected: @Vector(4, u1) = .{ 0, 1, 0, 1 }; try expectEqual(expected, overflow); } { var lhs = @Vector(4, u1){ 0, 0, 1, 1 }; var rhs = @Vector(4, u1){ 0, 1, 0, 1 }; var overflow = @addWithOverflow(lhs, rhs)[1]; var expected: @Vector(4, u1) = .{ 0, 0, 0, 1 }; try expectEqual(expected, overflow); } { var lhs = @Vector(4, u0){ 0, 0, 0, 0 }; var rhs = @Vector(4, u0){ 0, 0, 0, 0 }; var overflow = @addWithOverflow(lhs, rhs)[1]; var expected: @Vector(4, u1) = .{ 0, 0, 0, 0 }; try expectEqual(expected, overflow); } } }; try S.doTheTest(); try comptime S.doTheTest(); } test "@subWithOverflow" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { { var lhs = @Vector(2, u8){ 5, 5 }; var rhs = @Vector(2, u8){ 5, 6 }; var overflow = @subWithOverflow(lhs, rhs)[1]; var expected: @Vector(2, u1) = .{ 0, 1 }; try expectEqual(expected, overflow); } { var lhs = @Vector(4, i8){ -120, -120, 120, 120 }; var rhs = @Vector(4, i8){ 8, 9, -7, -8 }; var overflow = @subWithOverflow(lhs, rhs)[1]; var expected: @Vector(4, u1) = .{ 0, 1, 0, 1 }; try expectEqual(expected, overflow); } } }; try S.doTheTest(); try comptime S.doTheTest(); } test "@mulWithOverflow" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { var lhs = @Vector(4, u8){ 10, 10, 10, 10 }; var rhs = @Vector(4, u8){ 25, 26, 0, 30 }; var overflow = @mulWithOverflow(lhs, rhs)[1]; var expected: @Vector(4, u1) = .{ 0, 1, 0, 1 }; try expectEqual(expected, overflow); } }; try S.doTheTest(); try comptime S.doTheTest(); } test "@shlWithOverflow" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { var lhs = @Vector(4, u8){ 0, 1, 8, 255 }; var rhs = @Vector(4, u3){ 7, 7, 7, 7 }; var overflow = @shlWithOverflow(lhs, rhs)[1]; var expected: @Vector(4, u1) = .{ 0, 0, 1, 1 }; try expectEqual(expected, overflow); } }; try S.doTheTest(); try comptime S.doTheTest(); } test "alignment of vectors" { try expect(@alignOf(@Vector(2, u8)) == 2); try expect(@alignOf(@Vector(2, u1)) == 1); try expect(@alignOf(@Vector(1, u1)) == 1); try expect(@alignOf(@Vector(2, u16)) == 4); } test "loading the second vector from a slice of vectors" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; @setRuntimeSafety(false); var small_bases = [2]@Vector(2, u8){ @Vector(2, u8){ 0, 1 }, @Vector(2, u8){ 2, 3 }, }; var a: []const @Vector(2, u8) = &small_bases; var a4 = a[1][1]; try expect(a4 == 3); } test "array of vectors is copied" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const Vec3 = @Vector(3, i32); var points = [_]Vec3{ Vec3{ 404, -588, -901 }, Vec3{ 528, -643, 409 }, Vec3{ -838, 591, 734 }, Vec3{ 390, -675, -793 }, Vec3{ -537, -823, -458 }, Vec3{ -485, -357, 347 }, Vec3{ -345, -311, 381 }, Vec3{ -661, -816, -575 }, }; var points2: [20]Vec3 = undefined; points2[0..points.len].* = points; try std.testing.expectEqual(points2[6], Vec3{ -345, -311, 381 }); } test "byte vector initialized in inline function" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (comptime builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .x86_64 and builtin.cpu.features.isEnabled(@intFromEnum(std.Target.x86.Feature.avx512f))) { // TODO https://github.com/ziglang/zig/issues/13279 return error.SkipZigTest; } const S = struct { fn boolx4(e0: bool, e1: bool, e2: bool, e3: bool) @Vector(4, bool) { return .{ e0, e1, e2, e3 }; } fn all(vb: @Vector(4, bool)) bool { return @reduce(.And, vb); } }; try expect(S.all(S.boolx4(true, true, true, true))); } test "zero divisor" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO const zeros = @Vector(2, f32){ 0.0, 0.0 }; const ones = @Vector(2, f32){ 1.0, 1.0 }; const v1 = zeros / ones; const v2 = @divExact(zeros, ones); const v3 = @divTrunc(zeros, ones); const v4 = @divFloor(zeros, ones); _ = v1[0]; _ = v2[0]; _ = v3[0]; _ = v4[0]; } test "zero multiplicand" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const zeros = @Vector(2, u32){ 0.0, 0.0 }; var ones = @Vector(2, u32){ 1.0, 1.0 }; _ = (ones * zeros)[0]; _ = (zeros * zeros)[0]; _ = (zeros * ones)[0]; _ = (ones *| zeros)[0]; _ = (zeros *| zeros)[0]; _ = (zeros *| ones)[0]; _ = (ones *% zeros)[0]; _ = (zeros *% zeros)[0]; _ = (zeros *% ones)[0]; } test "@intCast to u0" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; var zeros = @Vector(2, u32){ 0, 0 }; const casted = @as(@Vector(2, u0), @intCast(zeros)); _ = casted[0]; } test "modRem with zero divisor" { comptime { var zeros = @Vector(2, u32){ 0, 0 }; const ones = @Vector(2, u32){ 1, 1 }; zeros %= ones; _ = zeros[0]; } } test "array operands to shuffle are coerced to vectors" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const mask = [5]i32{ -1, 0, 1, 2, 3 }; var a = [5]u32{ 3, 5, 7, 9, 0 }; var b = @shuffle(u32, a, @as(@Vector(5, u24), @splat(0)), mask); try expectEqual([_]u32{ 0, 3, 5, 7, 9 }, b); } test "load packed vector element" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO var x: @Vector(2, u15) = .{ 1, 4 }; try expect((&x[0]).* == 1); try expect((&x[1]).* == 4); } test "store packed vector element" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO var v = @Vector(4, u1){ 1, 1, 1, 1 }; try expectEqual(@Vector(4, u1){ 1, 1, 1, 1 }, v); var index: usize = 0; v[index] = 0; try expectEqual(@Vector(4, u1){ 0, 1, 1, 1 }, v); } test "store to vector in slice" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; var v = [_]@Vector(3, f32){ .{ 1, 1, 1 }, .{ 0, 0, 0 }, }; var s: []@Vector(3, f32) = &v; var i: usize = 1; s[i] = s[0]; try expectEqual(v[1], v[0]); } test "store vector with memset" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_llvm) { switch (builtin.target.cpu.arch) { .wasm32, .mips, .mipsel, .mips64, .mips64el, .riscv64, .powerpc, => { // LLVM 16 ERROR: "Converting bits to bytes lost precision" // https://github.com/ziglang/zig/issues/16177 return error.SkipZigTest; }, else => {}, } } var a: [5]@Vector(2, i1) = undefined; var b: [5]@Vector(2, u2) = undefined; var c: [5]@Vector(2, i4) = undefined; var d: [5]@Vector(2, u8) = undefined; var e: [5]@Vector(2, i9) = undefined; var ka = @Vector(2, i1){ -1, 0 }; var kb = @Vector(2, u2){ 0, 1 }; var kc = @Vector(2, i4){ 2, 3 }; var kd = @Vector(2, u8){ 4, 5 }; var ke = @Vector(2, i9){ 6, 7 }; @memset(&a, ka); @memset(&b, kb); @memset(&c, kc); @memset(&d, kd); @memset(&e, ke); try std.testing.expectEqual(ka, a[0]); try std.testing.expectEqual(kb, b[1]); try std.testing.expectEqual(kc, c[2]); try std.testing.expectEqual(kd, d[3]); try std.testing.expectEqual(ke, e[4]); } test "addition of vectors represented as strings" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const V = @Vector(3, u8); const foo: V = "foo".*; const bar: V = @typeName(u32).*; try expectEqual(V{ 219, 162, 161 }, foo + bar); } test "compare vectors with different element types" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO var a: @Vector(2, u8) = .{ 1, 2 }; var b: @Vector(2, u9) = .{ 3, 0 }; try expectEqual(@Vector(2, bool){ true, false }, a < b); } test "vector pointer is indexable" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO const V = @Vector(2, u32); const x: V = .{ 123, 456 }; comptime assert(@TypeOf(&(&x)[0]) == *const u32); // validate constness try expectEqual(@as(u32, 123), (&x)[0]); try expectEqual(@as(u32, 456), (&x)[1]); var y: V = .{ 123, 456 }; comptime assert(@TypeOf(&(&y)[0]) == *u32); // validate constness try expectEqual(@as(u32, 123), (&y)[0]); try expectEqual(@as(u32, 456), (&y)[1]); (&y)[0] = 100; (&y)[1] = 200; try expectEqual(@as(u32, 100), (&y)[0]); try expectEqual(@as(u32, 200), (&y)[1]); } test "boolean vector with 2 or more booleans" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO // TODO: try removing this after : if (!(builtin.os.tag == .linux and builtin.cpu.arch == .x86_64)) return; const vec1 = @Vector(2, bool){ true, true }; _ = vec1; const vec2 = @Vector(3, bool){ true, true, true }; _ = vec2; } test "bitcast to vector with different child type" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO const S = struct { fn doTheTest() !void { const VecA = @Vector(8, u16); const VecB = @Vector(4, u32); var vec_a = VecA{ 1, 1, 1, 1, 1, 1, 1, 1 }; var vec_b: VecB = @bitCast(vec_a); var vec_c: VecA = @bitCast(vec_b); try expectEqual(vec_a, vec_c); } }; // Originally reported at https://github.com/ziglang/zig/issues/8184 try S.doTheTest(); try comptime S.doTheTest(); }