zig/test/behavior/vector.zig
mlugg 2a4e06bcb3 Sema: rewrite comptime arithmetic
This commit reworks how Sema handles arithmetic on comptime-known
values, fixing many bugs in the process.

The general pattern is that arithmetic on comptime-known values is now
handled by the new namespace `Sema.arith`. Functions handling comptime
arithmetic no longer live on `Value`; this is because some of them can
emit compile errors, so some *can't* go on `Value`. Only semantic
analysis should really be doing arithmetic on `Value`s anyway, so it
makes sense for it to integrate more tightly with `Sema`.

This commit also implements more coherent rules surrounding how
`undefined` interacts with comptime and mixed-comptime-runtime
arithmetic. The rules are as follows.

* If an operation cannot trigger Illegal Behavior, and any operand is
  `undefined`, the result is `undefined`. This includes operations like
  `0 *| undef`, where the LHS logically *could* be used to determine a
  defined result. This is partly to simplify the language, but mostly to
  permit codegen backends to represent `undefined` values as completely
  invalid states.

* If an operation *can* trigger Illegal Behvaior, and any operand is
  `undefined`, then Illegal Behavior results. This occurs even if the
  operand in question isn't the one that "decides" illegal behavior; for
  instance, `undef / 1` is undefined. This is for the same reasons as
  described above.

* An operation which would trigger Illegal Behavior, when evaluated at
  comptime, instead triggers a compile error. Additionally, if one
  operand is comptime-known undef, such that the other (runtime-known)
  operand isn't needed to determine that Illegal Behavior would occur,
  the compile error is triggered.

* The only situation in which an operation with one comptime-known
  operand has a comptime-known result is if that operand is undefined,
  in which case the result is either undefined or a compile error per
  the above rules. This could potentially be loosened in future (for
  instance, `0 * rt` could be comptime-known 0 with a runtime assertion
  that `rt` is not undefined), but at least for now, defining it more
  conservatively simplifies the language and allows us to easily change
  this in future if desired.

This commit fixes many bugs regarding the handling of `undefined`,
particularly in vectors. Along with a collection of smaller tests, two
very large test cases are added to check arithmetic on `undefined`.

The operations which have been rewritten in this PR are:

* `+`, `+%`, `+|`, `@addWithOverflow`
* `-`, `-%`, `-|`, `@subWithOverflow`
* `*`, `*%`, `*|`, `@mulWithOverflow`
* `/`, `@divFloor`, `@divTrunc`, `@divExact`
* `%`, `@rem`, `@mod`

Other arithmetic operations are currently unchanged.

Resolves: #22743
Resolves: #22745
Resolves: #22748
Resolves: #22749
Resolves: #22914
2025-03-16 08:17:50 +00:00

1606 lines
70 KiB
Zig

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_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_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_riscv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64 and
!comptime std.Target.x86.featureSetHas(builtin.cpu.features, .sse4_1)) 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 }));
_ = .{ &v, &x, &z };
}
};
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_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_riscv64) return error.SkipZigTest;
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 };
_ = .{ &v, &x };
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_riscv64) return error.SkipZigTest;
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 };
_ = .{ &v, &x };
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_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 builtin.cpu.arch.isArm()) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .aarch64) {
// Triggers an assertion with LLVM 18:
// https://github.com/ziglang/zig/issues/20680
return error.SkipZigTest;
}
const S = struct {
fn doTheTest(T: type) !void {
var v: @Vector(4, T) = .{ 10, 20, 30, 40 };
var x: @Vector(4, T) = .{ 1, 2, 3, 4 };
_ = .{ &v, &x };
try expectEqual(v + x, .{ 11, 22, 33, 44 });
try expectEqual(v - x, .{ 9, 18, 27, 36 });
try expectEqual(v * x, .{ 10, 40, 90, 160 });
if (builtin.zig_backend != .stage2_riscv64) try expectEqual(-x, .{ -1, -2, -3, -4 });
}
};
try S.doTheTest(f32);
try comptime S.doTheTest(f32);
try S.doTheTest(f64);
try comptime S.doTheTest(f64);
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
try S.doTheTest(f16);
try comptime S.doTheTest(f16);
// https://github.com/llvm/llvm-project/issues/102870
if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
try S.doTheTest(f80);
try comptime S.doTheTest(f80);
try S.doTheTest(f128);
try comptime S.doTheTest(f128);
}
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_riscv64) return error.SkipZigTest;
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 };
_ = .{ &v, &x };
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_riscv64) return error.SkipZigTest;
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 };
_ = &a;
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;
_ = &foo;
const arr = [4]f32{ foo, 1.5, 0.0, 0.0 };
const 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_wasm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
const S = struct {
fn doTheTest() !void {
var foo1: i48 = 124578;
_ = &foo1;
const vec1: @Vector(2, i48) = [2]i48{ foo1, 1 };
const 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;
_ = &foo2;
const vec2: @Vector(2, u4) = [2]u4{ foo2, 1 };
const 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;
_ = &foo3;
const vec3: @Vector(3, u13) = [3]u13{ foo3, 0, 1 };
const 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);
const arr4 = [4:0]u24{ foo3, foo2, 0, 1 };
const 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_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_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
const S = struct {
fn doTheTest() !void {
var foo: f16 = 3.14;
_ = &foo;
const arr32 = [4]f32{ foo, 1.5, 0.0, 0.0 };
const 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_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 S = struct {
fn doTheTest() !void {
var b: @Vector(2, u8) = .{ 1, 2 };
var a: @Vector(2, u16) = .{ 2, 1 };
var t: bool = true;
_ = .{ &a, &b, &t };
const 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_riscv64) 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_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_riscv64) return error.SkipZigTest;
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 };
_ = &v;
const 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 };
_ = &v;
const 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 };
_ = &v;
const 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 };
_ = &v;
const 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_riscv64) return error.SkipZigTest;
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);
_ = &vec;
const 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
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
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
const S = struct {
fn doTheTest() !void {
var v: @Vector(4, i32) = [_]i32{ 1, 2, 3, undefined };
_ = &v;
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
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
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_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_riscv64) return error.SkipZigTest;
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 };
_ = .{ &v1, &v2 };
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);
_ = .{ &v1, &v2, &v3 };
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 };
_ = &v1;
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_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
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 {
const is_signed_int = switch (@typeInfo(T)) {
.int => |info| info.signedness == .signed,
else => false,
};
if (!is_signed_int) {
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 {
const is_signed_int = switch (@typeInfo(T)) {
.int => |info| info.signedness == .signed,
else => false,
};
if (!is_signed_int 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 comptime S.doTheTest();
if ((builtin.cpu.arch == .armeb or builtin.cpu.arch == .thumbeb) and builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/22060
try S.doTheTest();
}
test "vector bitwise not operator" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
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_riscv64) return error.SkipZigTest;
const S = struct {
fn doTheTestNot(comptime T: type, x: @Vector(4, T)) !void {
const 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_riscv64) return error.SkipZigTest;
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;
const xv = @as(@Vector(N, TX), x);
const yv = @as(@Vector(N, TY), y);
const z0 = xv >> yv;
for (@as([N]TX, z0), 0..) |v, i| {
try expect(x[i] >> y[i] == v);
}
const 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;
const xv = @as(@Vector(N, TX), x);
const yv = @as(@Vector(N, TY), y);
const 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);
}
};
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 builtin.cpu.arch.isArm()) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/21091
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;
const 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));
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));
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);
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 };
comptime assert(@TypeOf(result) == @Vector(4, bool));
const is_all_true = @reduce(.And, result);
comptime assert(@TypeOf(is_all_true) == bool);
try expect(is_all_true == false);
}
test "mask parameter of @shuffle is comptime scope" {
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_riscv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64 and
!comptime std.Target.x86.featureSetHas(builtin.cpu.features, .ssse3)) return error.SkipZigTest;
const __v4hi = @Vector(4, i16);
var v4_a = __v4hi{ 1, 2, 3, 4 };
var v4_b = __v4hi{ 5, 6, 7, 8 };
_ = .{ &v4_a, &v4_b };
const 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(2, @typeInfo(@TypeOf(v4_a)).vector.len),
std.zig.c_translation.shuffleVectorIndex(4, @typeInfo(@TypeOf(v4_a)).vector.len),
std.zig.c_translation.shuffleVectorIndex(6, @typeInfo(@TypeOf(v4_a)).vector.len),
});
try expect(shuffled[0] == 1);
try expect(shuffled[1] == 3);
try expect(shuffled[2] == 5);
try expect(shuffled[3] == 7);
}
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;
if (builtin.zig_backend == .stage2_riscv64) 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 };
_ = .{ &lhs, &rhs };
const 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 };
_ = .{ &lhs, &rhs };
const 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;
if (builtin.zig_backend == .stage2_riscv64) 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 };
_ = .{ &lhs, &rhs };
const 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;
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
// TODO: once #9660 has been solved, remove this line
if (builtin.target.cpu.arch.isWasm()) 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 };
_ = .{ &lhs, &rhs };
const 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;
if (builtin.zig_backend == .stage2_riscv64) 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 };
_ = .{ &lhs, &rhs };
const 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_riscv64) return error.SkipZigTest;
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_riscv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
if (builtin.cpu.arch == .aarch64_be and builtin.zig_backend == .stage2_llvm) 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 };
_ = .{ &lhs, &rhs };
const overflow = @addWithOverflow(lhs, rhs)[1];
const 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 };
_ = .{ &lhs, &rhs };
const overflow = @addWithOverflow(lhs, rhs)[1];
const 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 };
_ = .{ &lhs, &rhs };
const overflow = @addWithOverflow(lhs, rhs)[1];
const 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 };
_ = .{ &lhs, &rhs };
const overflow = @addWithOverflow(lhs, rhs)[1];
const expected: @Vector(4, u1) = .{ 0, 0, 0, 0 };
try expectEqual(expected, overflow);
}
}
};
try comptime S.doTheTest();
if ((builtin.cpu.arch == .armeb or builtin.cpu.arch == .thumbeb) and builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/22060
try 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_riscv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
if (builtin.cpu.arch == .aarch64_be and builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
const S = struct {
fn doTheTest() !void {
{
var lhs = @Vector(2, u8){ 5, 5 };
var rhs = @Vector(2, u8){ 5, 6 };
_ = .{ &lhs, &rhs };
const overflow = @subWithOverflow(lhs, rhs)[1];
const 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 };
_ = .{ &lhs, &rhs };
const overflow = @subWithOverflow(lhs, rhs)[1];
const expected: @Vector(4, u1) = .{ 0, 1, 0, 1 };
try expectEqual(expected, overflow);
}
}
};
try comptime S.doTheTest();
if ((builtin.cpu.arch == .armeb or builtin.cpu.arch == .thumbeb) and builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/22060
try 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_riscv64) return error.SkipZigTest;
if (builtin.cpu.arch == .aarch64_be and builtin.zig_backend == .stage2_llvm) 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 };
_ = .{ &lhs, &rhs };
const overflow = @mulWithOverflow(lhs, rhs)[1];
const expected: @Vector(4, u1) = .{ 0, 1, 0, 1 };
try expectEqual(expected, overflow);
}
};
try comptime S.doTheTest();
if ((builtin.cpu.arch == .armeb or builtin.cpu.arch == .thumbeb) and builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/22060
try 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_riscv64) return error.SkipZigTest;
if (builtin.cpu.arch == .aarch64_be and builtin.zig_backend == .stage2_llvm) 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 };
_ = .{ &lhs, &rhs };
const overflow = @shlWithOverflow(lhs, rhs)[1];
const 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)) == switch (builtin.zig_backend) {
else => 2,
.stage2_c => @alignOf(u8),
.stage2_x86_64 => 16,
});
try expect(@alignOf(@Vector(2, u1)) == switch (builtin.zig_backend) {
else => 1,
.stage2_c => @alignOf(u1),
.stage2_x86_64 => 16,
});
try expect(@alignOf(@Vector(1, u1)) == switch (builtin.zig_backend) {
else => 1,
.stage2_c => @alignOf(u1),
.stage2_x86_64 => 16,
});
try expect(@alignOf(@Vector(2, u16)) == switch (builtin.zig_backend) {
else => 4,
.stage2_c => @alignOf(u16),
.stage2_x86_64 => 16,
});
}
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 },
};
const a: []const @Vector(2, u8) = &small_bases;
const 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 },
};
_ = &points;
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_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_riscv64) return error.SkipZigTest;
if (builtin.cpu.arch == .aarch64_be and builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
if (comptime builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .x86_64 and
std.Target.x86.featureSetHas(builtin.cpu.features, .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_riscv64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
const zeros = @Vector(2, u32){ 0.0, 0.0 };
var ones = @Vector(2, u32){ 1.0, 1.0 };
_ = &ones;
_ = (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_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_riscv64) return error.SkipZigTest;
var zeros = @Vector(2, u32){ 0, 0 };
_ = &zeros;
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_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_x86_64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
const mask = [5]i32{ -1, 0, 1, 2, 3 };
var a = [5]u32{ 3, 5, 7, 9, 0 };
_ = &a;
const 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_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
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_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
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
if (builtin.cpu.arch == .aarch64_be and builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
var v = @Vector(4, u1){ 1, 1, 1, 1 };
try expectEqual(@Vector(4, u1){ 1, 1, 1, 1 }, v);
var index: usize = 0;
_ = &index;
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_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
var v = [_]@Vector(3, f32){
.{ 1, 1, 1 },
.{ 0, 0, 0 },
};
var s: []@Vector(3, f32) = &v;
var i: usize = 1;
_ = &i;
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_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_riscv64) return error.SkipZigTest;
if (builtin.cpu.arch == .aarch64_be and builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
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 };
_ = .{ &ka, &kb, &kc, &kd, &ke };
@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
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_riscv64) return error.SkipZigTest;
var a: @Vector(2, u8) = .{ 1, 2 };
var b: @Vector(2, u9) = .{ 3, 0 };
_ = .{ &a, &b };
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_sparc64) 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_sparc64) return error.SkipZigTest; // TODO
// TODO: try removing this after <https://github.com/ziglang/zig/issues/13782>:
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_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
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 };
_ = &vec_a;
const vec_b: VecB = @bitCast(vec_a);
const 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();
}
test "index into comptime-known vector is comptime-known" {
const vec: @Vector(2, f16) = [2]f16{ 1.5, 3.5 };
if (vec[0] != 1.5) @compileError("vec should be comptime");
}
test "arithmetic on zero-length vectors" {
if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
{
const a = @Vector(0, i32){};
const b = @Vector(0, i32){};
_ = a + b;
}
{
const a = @Vector(0, i32){};
const b = @Vector(0, i32){};
_ = a - b;
}
}
test "@reduce on bool vector" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
const a = @Vector(2, bool){ true, true };
const b = @Vector(1, bool){true};
try std.testing.expect(@reduce(.And, a));
try std.testing.expect(@reduce(.And, b));
}
test "bitcast vector to array of smaller vectors" {
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 u8x32 = @Vector(32, u8);
const u8x64 = @Vector(64, u8);
const S = struct {
fn doTheTest(input_vec: u8x64) !void {
try compare(@bitCast(input_vec));
}
fn compare(chunks: [2]u8x32) !void {
try expectEqual(@as(u8x32, @splat(1)), chunks[0]);
try expectEqual(@as(u8x32, @splat(2)), chunks[1]);
}
};
const input: u8x64 = @bitCast([2]u8x32{ @splat(1), @splat(2) });
try S.doTheTest(input);
}