x86_64: rewrite most of the remaining float ops

This commit is contained in:
Jacob Young 2025-02-04 06:33:36 -05:00
parent 39119088f9
commit fa9b0fa6d3
8 changed files with 16770 additions and 3225 deletions

View file

@ -450,7 +450,7 @@ pub fn build(b: *std.Build) !void {
.skip_non_native = skip_non_native, .skip_non_native = skip_non_native,
.skip_libc = skip_libc, .skip_libc = skip_libc,
.use_llvm = use_llvm, .use_llvm = use_llvm,
.max_rss = 1.25 * 1024 * 1024 * 1024, .max_rss = 2 * 1024 * 1024 * 1024,
})); }));
test_modules_step.dependOn(tests.addModuleTests(b, .{ test_modules_step.dependOn(tests.addModuleTests(b, .{

File diff suppressed because it is too large Load diff

View file

@ -177,7 +177,13 @@ pub const Condition = enum(u5) {
/// The immediate operand of vcvtps2ph. /// The immediate operand of vcvtps2ph.
pub const RoundMode = packed struct(u5) { pub const RoundMode = packed struct(u5) {
mode: enum(u4) { direction: Direction = .mxcsr,
precision: enum(u1) {
normal = 0b0,
inexact = 0b1,
} = .normal,
pub const Direction = enum(u4) {
/// Round to nearest (even) /// Round to nearest (even)
nearest = 0b0_00, nearest = 0b0_00,
/// Round down (toward -) /// Round down (toward -)
@ -188,11 +194,7 @@ pub const RoundMode = packed struct(u5) {
zero = 0b0_11, zero = 0b0_11,
/// Use current rounding mode of MXCSR.RC /// Use current rounding mode of MXCSR.RC
mxcsr = 0b1_00, mxcsr = 0b1_00,
} = .mxcsr, };
precision: enum(u1) {
normal = 0b0,
inexact = 0b1,
} = .normal,
pub fn imm(mode: RoundMode) Immediate { pub fn imm(mode: RoundMode) Immediate {
return .u(@as(@typeInfo(RoundMode).@"struct".backing_integer.?, @bitCast(mode))); return .u(@as(@typeInfo(RoundMode).@"struct".backing_integer.?, @bitCast(mode)));

View file

@ -19,7 +19,7 @@ pub const table = [_]Entry{
.{ .aad, .zi, &.{ .imm8 }, &.{ 0xd5 }, 0, .none, .@"32bit" }, .{ .aad, .zi, &.{ .imm8 }, &.{ 0xd5 }, 0, .none, .@"32bit" },
.{ .aam, .z, &.{ }, &.{ 0xd4, 0x0a }, 0, .none, .@"32bit" }, .{ .aam, .z, &.{ }, &.{ 0xd4, 0x0a }, 0, .none, .@"32bit" },
.{ .aam, .z, &.{ .imm8 }, &.{ 0xd4 }, 0, .none, .@"32bit" }, .{ .aam, .zi, &.{ .imm8 }, &.{ 0xd4 }, 0, .none, .@"32bit" },
.{ .aas, .z, &.{}, &.{ 0x3f }, 0, .none, .@"32bit" }, .{ .aas, .z, &.{}, &.{ 0x3f }, 0, .none, .@"32bit" },

View file

@ -156,7 +156,13 @@ test "cmp f128" {
} }
test "cmp f80/c_longdouble" { test "cmp f80/c_longdouble" {
if (true) 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_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
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;
try testCmp(f80); try testCmp(f80);
try comptime testCmp(f80); try comptime testCmp(f80);
@ -453,7 +459,7 @@ test "@sin with vectors" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) 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_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64) 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; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
try testSinWithVectors(); try testSinWithVectors();
@ -526,7 +532,7 @@ test "@cos with vectors" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) 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_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64) 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; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
try testCosWithVectors(); try testCosWithVectors();
@ -600,7 +606,7 @@ test "@tan with vectors" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) 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_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64) 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; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
try testTanWithVectors(); try testTanWithVectors();
@ -677,7 +683,7 @@ test "@exp with vectors" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) 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_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64) 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; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
try testExpWithVectors(); try testExpWithVectors();
@ -749,7 +755,7 @@ test "@exp2 with @vectors" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) 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_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64) 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; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
try testExp2WithVectors(); try testExp2WithVectors();
@ -822,7 +828,7 @@ test "@log with @vectors" {
if (builtin.zig_backend == .stage2_aarch64) 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_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) 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_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
{ {
@ -896,7 +902,7 @@ test "@log2 with vectors" {
if (builtin.zig_backend == .stage2_llvm and if (builtin.zig_backend == .stage2_llvm and
builtin.cpu.arch == .aarch64 and builtin.cpu.arch == .aarch64 and
builtin.os.tag == .windows) return error.SkipZigTest; builtin.os.tag == .windows) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
try testLog2WithVectors(); try testLog2WithVectors();
try comptime testLog2WithVectors(); try comptime testLog2WithVectors();
@ -967,7 +973,7 @@ test "@log10 with vectors" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO 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_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64) 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; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
try testLog10WithVectors(); try testLog10WithVectors();
@ -1188,8 +1194,7 @@ test "@floor with vectors" {
if (builtin.zig_backend == .stage2_arm) 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_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64 and if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
!comptime std.Target.x86.featureSetHas(builtin.cpu.features, .sse4_1)) return error.SkipZigTest;
try testFloorWithVectors(); try testFloorWithVectors();
try comptime testFloorWithVectors(); try comptime testFloorWithVectors();
@ -1286,8 +1291,7 @@ test "@ceil with vectors" {
if (builtin.zig_backend == .stage2_arm) 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_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64 and if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
!comptime std.Target.x86.featureSetHas(builtin.cpu.features, .sse4_1)) return error.SkipZigTest;
try testCeilWithVectors(); try testCeilWithVectors();
try comptime testCeilWithVectors(); try comptime testCeilWithVectors();
@ -1384,8 +1388,7 @@ test "@trunc with vectors" {
if (builtin.zig_backend == .stage2_arm) 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_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64 and if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
!comptime std.Target.x86.featureSetHas(builtin.cpu.features, .sse4_1)) return error.SkipZigTest;
try testTruncWithVectors(); try testTruncWithVectors();
try comptime testTruncWithVectors(); try comptime testTruncWithVectors();

View file

@ -2,16 +2,12 @@ const std = @import("std");
const builtin = @import("builtin"); const builtin = @import("builtin");
const expect = std.testing.expect; const expect = std.testing.expect;
const no_x86_64_hardware_fma_support = builtin.zig_backend == .stage2_x86_64 and
!std.Target.x86.featureSetHas(builtin.cpu.features, .fma);
test "@mulAdd" { test "@mulAdd" {
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
if (no_x86_64_hardware_fma_support) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) 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_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) 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;
try comptime testMulAdd(); try comptime testMulAdd();
try testMulAdd(); try testMulAdd();
@ -110,10 +106,10 @@ fn vector16() !void {
test "vector f16" { test "vector f16" {
if (builtin.zig_backend == .stage2_wasm) 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_arm) 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_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) 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; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
try comptime vector16(); try comptime vector16();
@ -135,11 +131,11 @@ fn vector32() !void {
test "vector f32" { test "vector f32" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
if (no_x86_64_hardware_fma_support) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) 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_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) 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;
try comptime vector32(); try comptime vector32();
try vector32(); try vector32();
@ -160,11 +156,11 @@ fn vector64() !void {
test "vector f64" { test "vector f64" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
if (no_x86_64_hardware_fma_support) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) 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_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) 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;
try comptime vector64(); try comptime vector64();
try vector64(); try vector64();
@ -184,12 +180,12 @@ fn vector80() !void {
test "vector f80" { test "vector f80" {
if (builtin.zig_backend == .stage2_wasm) 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_arm) 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_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) 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_spirv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) 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_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
try comptime vector80(); try comptime vector80();
@ -211,12 +207,12 @@ fn vector128() !void {
test "vector f128" { test "vector f128" {
if (builtin.zig_backend == .stage2_wasm) 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_arm) 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_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) 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_spirv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) 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_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
try comptime vector128(); try comptime vector128();

View file

@ -102,7 +102,7 @@ test "vector float operators" {
if (builtin.zig_backend == .stage2_sparc64) 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_spirv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64) 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_llvm and builtin.cpu.arch == .aarch64) { if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .aarch64) {
// Triggers an assertion with LLVM 18: // Triggers an assertion with LLVM 18:

View file

@ -37,6 +37,14 @@ inline fn splat(comptime Type: type, scalar: Scalar(Type)) Type {
.vector => @splat(scalar), .vector => @splat(scalar),
}; };
} }
// inline to avoid a runtime `@select`
inline fn select(cond: anytype, lhs: anytype, rhs: @TypeOf(lhs)) @TypeOf(lhs) {
return switch (@typeInfo(@TypeOf(cond))) {
.bool => if (cond) lhs else rhs,
.vector => @select(Scalar(@TypeOf(lhs)), cond, lhs, rhs),
else => @compileError(@typeName(@TypeOf(cond))),
};
}
fn sign(rhs: anytype) switch (@typeInfo(@TypeOf(rhs))) { fn sign(rhs: anytype) switch (@typeInfo(@TypeOf(rhs))) {
else => bool, else => bool,
.vector => |vector| @Vector(vector.len, bool), .vector => |vector| @Vector(vector.len, bool),
@ -84,65 +92,78 @@ fn boolOr(lhs: anytype, rhs: @TypeOf(lhs)) @TypeOf(lhs) {
@compileError("unsupported boolOr type: " ++ @typeName(@TypeOf(lhs))); @compileError("unsupported boolOr type: " ++ @typeName(@TypeOf(lhs)));
} }
const Compare = enum { strict, relaxed, approx, approx_int };
// noinline for a more helpful stack trace // noinline for a more helpful stack trace
noinline fn checkExpected(expected: anytype, actual: @TypeOf(expected), comptime strict: bool) !void { noinline fn checkExpected(expected: anytype, actual: @TypeOf(expected), comptime compare: Compare) !void {
const info = @typeInfo(@TypeOf(expected)); const Expected = @TypeOf(expected);
const unexpected = unexpected: switch (switch (info) { const unexpected = unexpected: switch (@typeInfo(Scalar(Expected))) {
else => info,
.vector => |vector| @typeInfo(vector.child),
}) {
else => expected != actual, else => expected != actual,
.float => { .float => switch (compare) {
.strict, .relaxed => {
const unequal = boolAnd(expected != actual, boolOr(expected == expected, actual == actual)); const unequal = boolAnd(expected != actual, boolOr(expected == expected, actual == actual));
break :unexpected switch (strict) { break :unexpected switch (compare) {
false => unequal, .strict => boolOr(unequal, sign(expected) != sign(actual)),
true => boolOr(unequal, sign(expected) != sign(actual)), .relaxed => unequal,
.approx, .approx_int => comptime unreachable,
}; };
}, },
.approx, .approx_int => {
const epsilon = math.floatEps(Scalar(Expected));
const tolerance = @sqrt(epsilon);
break :unexpected @abs(expected - actual) > @max(
@abs(expected) * splat(Expected, tolerance),
splat(Expected, switch (compare) {
.strict, .relaxed => comptime unreachable,
.approx => tolerance,
.approx_int => 1,
}),
);
},
},
}; };
if (switch (info) { if (switch (@typeInfo(Expected)) {
else => unexpected, else => unexpected,
.vector => @reduce(.Or, unexpected), .vector => @reduce(.Or, unexpected),
}) return error.Unexpected; }) return error.Unexpected;
} }
test checkExpected { test checkExpected {
if (checkExpected(nan(f16), nan(f16), true) == error.Unexpected) return error.Unexpected; if (checkExpected(nan(f16), nan(f16), .strict) == error.Unexpected) return error.Unexpected;
if (checkExpected(nan(f16), -nan(f16), true) != error.Unexpected) return error.Unexpected; if (checkExpected(nan(f16), -nan(f16), .strict) != error.Unexpected) return error.Unexpected;
if (checkExpected(@as(f16, 0.0), @as(f16, 0.0), true) == error.Unexpected) return error.Unexpected; if (checkExpected(@as(f16, 0.0), @as(f16, 0.0), .strict) == error.Unexpected) return error.Unexpected;
if (checkExpected(@as(f16, -0.0), @as(f16, -0.0), true) == error.Unexpected) return error.Unexpected; if (checkExpected(@as(f16, -0.0), @as(f16, -0.0), .strict) == error.Unexpected) return error.Unexpected;
if (checkExpected(@as(f16, -0.0), @as(f16, 0.0), true) != error.Unexpected) return error.Unexpected; if (checkExpected(@as(f16, -0.0), @as(f16, 0.0), .strict) != error.Unexpected) return error.Unexpected;
if (checkExpected(@as(f16, 0.0), @as(f16, -0.0), true) != error.Unexpected) return error.Unexpected; if (checkExpected(@as(f16, 0.0), @as(f16, -0.0), .strict) != error.Unexpected) return error.Unexpected;
if (checkExpected(nan(f32), nan(f32), true) == error.Unexpected) return error.Unexpected; if (checkExpected(nan(f32), nan(f32), .strict) == error.Unexpected) return error.Unexpected;
if (checkExpected(nan(f32), -nan(f32), true) != error.Unexpected) return error.Unexpected; if (checkExpected(nan(f32), -nan(f32), .strict) != error.Unexpected) return error.Unexpected;
if (checkExpected(@as(f32, 0.0), @as(f32, 0.0), true) == error.Unexpected) return error.Unexpected; if (checkExpected(@as(f32, 0.0), @as(f32, 0.0), .strict) == error.Unexpected) return error.Unexpected;
if (checkExpected(@as(f32, -0.0), @as(f32, -0.0), true) == error.Unexpected) return error.Unexpected; if (checkExpected(@as(f32, -0.0), @as(f32, -0.0), .strict) == error.Unexpected) return error.Unexpected;
if (checkExpected(@as(f32, -0.0), @as(f32, 0.0), true) != error.Unexpected) return error.Unexpected; if (checkExpected(@as(f32, -0.0), @as(f32, 0.0), .strict) != error.Unexpected) return error.Unexpected;
if (checkExpected(@as(f32, 0.0), @as(f32, -0.0), true) != error.Unexpected) return error.Unexpected; if (checkExpected(@as(f32, 0.0), @as(f32, -0.0), .strict) != error.Unexpected) return error.Unexpected;
if (checkExpected(nan(f64), nan(f64), true) == error.Unexpected) return error.Unexpected; if (checkExpected(nan(f64), nan(f64), .strict) == error.Unexpected) return error.Unexpected;
if (checkExpected(nan(f64), -nan(f64), true) != error.Unexpected) return error.Unexpected; if (checkExpected(nan(f64), -nan(f64), .strict) != error.Unexpected) return error.Unexpected;
if (checkExpected(@as(f64, 0.0), @as(f64, 0.0), true) == error.Unexpected) return error.Unexpected; if (checkExpected(@as(f64, 0.0), @as(f64, 0.0), .strict) == error.Unexpected) return error.Unexpected;
if (checkExpected(@as(f64, -0.0), @as(f64, -0.0), true) == error.Unexpected) return error.Unexpected; if (checkExpected(@as(f64, -0.0), @as(f64, -0.0), .strict) == error.Unexpected) return error.Unexpected;
if (checkExpected(@as(f64, -0.0), @as(f64, 0.0), true) != error.Unexpected) return error.Unexpected; if (checkExpected(@as(f64, -0.0), @as(f64, 0.0), .strict) != error.Unexpected) return error.Unexpected;
if (checkExpected(@as(f64, 0.0), @as(f64, -0.0), true) != error.Unexpected) return error.Unexpected; if (checkExpected(@as(f64, 0.0), @as(f64, -0.0), .strict) != error.Unexpected) return error.Unexpected;
if (checkExpected(nan(f80), nan(f80), true) == error.Unexpected) return error.Unexpected; if (checkExpected(nan(f80), nan(f80), .strict) == error.Unexpected) return error.Unexpected;
if (checkExpected(nan(f80), -nan(f80), true) != error.Unexpected) return error.Unexpected; if (checkExpected(nan(f80), -nan(f80), .strict) != error.Unexpected) return error.Unexpected;
if (checkExpected(@as(f80, 0.0), @as(f80, 0.0), true) == error.Unexpected) return error.Unexpected; if (checkExpected(@as(f80, 0.0), @as(f80, 0.0), .strict) == error.Unexpected) return error.Unexpected;
if (checkExpected(@as(f80, -0.0), @as(f80, -0.0), true) == error.Unexpected) return error.Unexpected; if (checkExpected(@as(f80, -0.0), @as(f80, -0.0), .strict) == error.Unexpected) return error.Unexpected;
if (checkExpected(@as(f80, -0.0), @as(f80, 0.0), true) != error.Unexpected) return error.Unexpected; if (checkExpected(@as(f80, -0.0), @as(f80, 0.0), .strict) != error.Unexpected) return error.Unexpected;
if (checkExpected(@as(f80, 0.0), @as(f80, -0.0), true) != error.Unexpected) return error.Unexpected; if (checkExpected(@as(f80, 0.0), @as(f80, -0.0), .strict) != error.Unexpected) return error.Unexpected;
if (checkExpected(nan(f128), nan(f128), true) == error.Unexpected) return error.Unexpected; if (checkExpected(nan(f128), nan(f128), .strict) == error.Unexpected) return error.Unexpected;
if (checkExpected(nan(f128), -nan(f128), true) != error.Unexpected) return error.Unexpected; if (checkExpected(nan(f128), -nan(f128), .strict) != error.Unexpected) return error.Unexpected;
if (checkExpected(@as(f128, 0.0), @as(f128, 0.0), true) == error.Unexpected) return error.Unexpected; if (checkExpected(@as(f128, 0.0), @as(f128, 0.0), .strict) == error.Unexpected) return error.Unexpected;
if (checkExpected(@as(f128, -0.0), @as(f128, -0.0), true) == error.Unexpected) return error.Unexpected; if (checkExpected(@as(f128, -0.0), @as(f128, -0.0), .strict) == error.Unexpected) return error.Unexpected;
if (checkExpected(@as(f128, -0.0), @as(f128, 0.0), true) != error.Unexpected) return error.Unexpected; if (checkExpected(@as(f128, -0.0), @as(f128, 0.0), .strict) != error.Unexpected) return error.Unexpected;
if (checkExpected(@as(f128, 0.0), @as(f128, -0.0), true) != error.Unexpected) return error.Unexpected; if (checkExpected(@as(f128, 0.0), @as(f128, -0.0), .strict) != error.Unexpected) return error.Unexpected;
} }
fn unary(comptime op: anytype, comptime opts: struct { strict: bool = false }) type { fn unary(comptime op: anytype, comptime opts: struct { compare: Compare = .relaxed }) type {
return struct { return struct {
// noinline so that `mem_arg` is on the stack // noinline so that `mem_arg` is on the stack
noinline fn testArgKinds( noinline fn testArgKinds(
@ -169,9 +190,9 @@ fn unary(comptime op: anytype, comptime opts: struct { strict: bool = false }) t
const expected = comptime op(Type, imm_arg); const expected = comptime op(Type, imm_arg);
var reg_arg = mem_arg; var reg_arg = mem_arg;
_ = .{&reg_arg}; _ = .{&reg_arg};
try checkExpected(expected, op(Type, reg_arg), opts.strict); try checkExpected(expected, op(Type, reg_arg), opts.compare);
try checkExpected(expected, op(Type, mem_arg), opts.strict); try checkExpected(expected, op(Type, mem_arg), opts.compare);
try checkExpected(expected, op(Type, imm_arg), opts.strict); try checkExpected(expected, op(Type, imm_arg), opts.compare);
} }
// noinline for a more helpful stack trace // noinline for a more helpful stack trace
noinline fn testArgs(comptime Type: type, comptime imm_arg: Type) !void { noinline fn testArgs(comptime Type: type, comptime imm_arg: Type) !void {
@ -1628,7 +1649,7 @@ fn unary(comptime op: anytype, comptime opts: struct { strict: bool = false }) t
}; };
} }
fn cast(comptime op: anytype, comptime opts: struct { strict: bool = false }) type { fn cast(comptime op: anytype, comptime opts: struct { compare: Compare = .relaxed }) type {
return struct { return struct {
// noinline so that `mem_arg` is on the stack // noinline so that `mem_arg` is on the stack
noinline fn testArgKinds( noinline fn testArgKinds(
@ -1656,9 +1677,9 @@ fn cast(comptime op: anytype, comptime opts: struct { strict: bool = false }) ty
const expected = comptime op(Result, Type, imm_arg, imm_arg); const expected = comptime op(Result, Type, imm_arg, imm_arg);
var reg_arg = mem_arg; var reg_arg = mem_arg;
_ = .{&reg_arg}; _ = .{&reg_arg};
try checkExpected(expected, op(Result, Type, reg_arg, imm_arg), opts.strict); try checkExpected(expected, op(Result, Type, reg_arg, imm_arg), opts.compare);
try checkExpected(expected, op(Result, Type, mem_arg, imm_arg), opts.strict); try checkExpected(expected, op(Result, Type, mem_arg, imm_arg), opts.compare);
try checkExpected(expected, op(Result, Type, imm_arg, imm_arg), opts.strict); try checkExpected(expected, op(Result, Type, imm_arg, imm_arg), opts.compare);
} }
// noinline for a more helpful stack trace // noinline for a more helpful stack trace
noinline fn testArgs(comptime Result: type, comptime Type: type, comptime imm_arg: Type) !void { noinline fn testArgs(comptime Result: type, comptime Type: type, comptime imm_arg: Type) !void {
@ -8504,7 +8525,7 @@ fn cast(comptime op: anytype, comptime opts: struct { strict: bool = false }) ty
}; };
} }
fn binary(comptime op: anytype, comptime opts: struct { strict: bool = false }) type { fn binary(comptime op: anytype, comptime opts: struct { compare: Compare = .relaxed }) type {
return struct { return struct {
// noinline so that `mem_lhs` and `mem_rhs` are on the stack // noinline so that `mem_lhs` and `mem_rhs` are on the stack
noinline fn testArgKinds( noinline fn testArgKinds(
@ -8534,14 +8555,14 @@ fn binary(comptime op: anytype, comptime opts: struct { strict: bool = false })
var reg_lhs = mem_lhs; var reg_lhs = mem_lhs;
var reg_rhs = mem_rhs; var reg_rhs = mem_rhs;
_ = .{ &reg_lhs, &reg_rhs }; _ = .{ &reg_lhs, &reg_rhs };
try checkExpected(expected, op(Type, reg_lhs, reg_rhs), opts.strict); try checkExpected(expected, op(Type, reg_lhs, reg_rhs), opts.compare);
try checkExpected(expected, op(Type, reg_lhs, mem_rhs), opts.strict); try checkExpected(expected, op(Type, reg_lhs, mem_rhs), opts.compare);
try checkExpected(expected, op(Type, reg_lhs, imm_rhs), opts.strict); try checkExpected(expected, op(Type, reg_lhs, imm_rhs), opts.compare);
try checkExpected(expected, op(Type, mem_lhs, reg_rhs), opts.strict); try checkExpected(expected, op(Type, mem_lhs, reg_rhs), opts.compare);
try checkExpected(expected, op(Type, mem_lhs, mem_rhs), opts.strict); try checkExpected(expected, op(Type, mem_lhs, mem_rhs), opts.compare);
try checkExpected(expected, op(Type, mem_lhs, imm_rhs), opts.strict); try checkExpected(expected, op(Type, mem_lhs, imm_rhs), opts.compare);
try checkExpected(expected, op(Type, imm_lhs, reg_rhs), opts.strict); try checkExpected(expected, op(Type, imm_lhs, reg_rhs), opts.compare);
try checkExpected(expected, op(Type, imm_lhs, mem_rhs), opts.strict); try checkExpected(expected, op(Type, imm_lhs, mem_rhs), opts.compare);
} }
// noinline for a more helpful stack trace // noinline for a more helpful stack trace
noinline fn testArgs(comptime Type: type, comptime imm_lhs: Type, comptime imm_rhs: Type) !void { noinline fn testArgs(comptime Type: type, comptime imm_lhs: Type, comptime imm_rhs: Type) !void {
@ -11315,6 +11336,124 @@ fn binary(comptime op: anytype, comptime opts: struct { strict: bool = false })
}; };
} }
inline fn add(comptime Type: type, lhs: Type, rhs: Type) @TypeOf(lhs + rhs) {
return lhs + rhs;
}
test add {
const test_add = binary(add, .{});
try test_add.testFloats();
try test_add.testFloatVectors();
}
inline fn subtract(comptime Type: type, lhs: Type, rhs: Type) @TypeOf(lhs - rhs) {
return lhs - rhs;
}
test subtract {
const test_subtract = binary(subtract, .{});
try test_subtract.testFloats();
try test_subtract.testFloatVectors();
}
inline fn multiply(comptime Type: type, lhs: Type, rhs: Type) @TypeOf(lhs * rhs) {
if (@inComptime() and @typeInfo(Type) == .vector) {
// workaround https://github.com/ziglang/zig/issues/22743
// TODO: return @select(Scalar(Type), boolAnd(lhs == lhs, rhs == rhs), lhs * rhs, lhs + rhs);
// workaround https://github.com/ziglang/zig/issues/22744
var res: Type = undefined;
for (0..@typeInfo(Type).vector.len) |i| res[i] = lhs[i] * rhs[i];
return res;
}
// workaround https://github.com/ziglang/zig/issues/22745
// TODO: return lhs * rhs;
var rt_lhs = lhs;
var rt_rhs = rhs;
_ = .{ &rt_lhs, &rt_rhs };
return rt_lhs * rt_rhs;
}
test multiply {
const test_multiply = binary(multiply, .{});
try test_multiply.testFloats();
try test_multiply.testFloatVectors();
}
inline fn divide(comptime Type: type, lhs: Type, rhs: Type) @TypeOf(lhs / rhs) {
return lhs / rhs;
}
test divide {
const test_divide = binary(divide, .{ .compare = .approx });
try test_divide.testFloats();
try test_divide.testFloatVectors();
}
// workaround https://github.com/ziglang/zig/issues/22748
// TODO: @TypeOf(@divTrunc(lhs, rhs))
inline fn divTrunc(comptime Type: type, lhs: Type, rhs: Type) @TypeOf(lhs / rhs) {
if (@inComptime()) {
// workaround https://github.com/ziglang/zig/issues/22748
return @trunc(lhs / rhs);
}
// workaround https://github.com/ziglang/zig/issues/22748
// workaround https://github.com/ziglang/zig/issues/22749
// TODO: return @divTrunc(lhs, rhs);
var rt_lhs = lhs;
var rt_rhs = rhs;
_ = .{ &rt_lhs, &rt_rhs };
return @divTrunc(rt_lhs, rt_rhs);
}
test divTrunc {
const test_div_trunc = binary(divTrunc, .{ .compare = .approx_int });
try test_div_trunc.testFloats();
try test_div_trunc.testFloatVectors();
}
// workaround https://github.com/ziglang/zig/issues/22748
// TODO: @TypeOf(@divFloor(lhs, rhs))
inline fn divFloor(comptime Type: type, lhs: Type, rhs: Type) @TypeOf(lhs / rhs) {
if (@inComptime()) {
// workaround https://github.com/ziglang/zig/issues/22748
return @floor(lhs / rhs);
}
// workaround https://github.com/ziglang/zig/issues/22748
// workaround https://github.com/ziglang/zig/issues/22749
// TODO: return @divFloor(lhs, rhs);
var rt_lhs = lhs;
var rt_rhs = rhs;
_ = &rt_lhs;
_ = &rt_rhs;
return @divFloor(rt_lhs, rt_rhs);
}
test divFloor {
const test_div_floor = binary(divFloor, .{ .compare = .approx_int });
try test_div_floor.testFloats();
try test_div_floor.testFloatVectors();
}
// workaround https://github.com/ziglang/zig/issues/22748
// TODO: @TypeOf(@rem(lhs, rhs))
inline fn rem(comptime Type: type, lhs: Type, rhs: Type) Type {
if (@inComptime()) {
// workaround https://github.com/ziglang/zig/issues/22748
switch (@typeInfo(Type)) {
else => return if (rhs != 0) @rem(lhs, rhs) else nan(Type),
.vector => |info| {
var res: Type = undefined;
inline for (0..info.len) |i| res[i] = if (rhs[i] != 0) @rem(lhs[i], rhs[i]) else nan(Scalar(Type));
return res;
},
}
}
// workaround https://github.com/ziglang/zig/issues/22748
// TODO: return @rem(lhs, rhs);
var rt_rhs = rhs;
_ = &rt_rhs;
return @rem(lhs, rt_rhs);
}
test rem {
const test_rem = binary(rem, .{});
try test_rem.testFloats();
try test_rem.testFloatVectors();
}
inline fn bitNot(comptime Type: type, rhs: Type) @TypeOf(~rhs) { inline fn bitNot(comptime Type: type, rhs: Type) @TypeOf(~rhs) {
return ~rhs; return ~rhs;
} }
@ -11324,17 +11463,6 @@ test bitNot {
try test_bit_not.testIntVectors(); try test_bit_not.testIntVectors();
} }
inline fn abs(comptime Type: type, rhs: Type) @TypeOf(@abs(rhs)) {
return @abs(rhs);
}
test abs {
const test_abs = unary(abs, .{ .strict = true });
try test_abs.testInts();
try test_abs.testIntVectors();
try test_abs.testFloats();
try test_abs.testFloatVectors();
}
inline fn clz(comptime Type: type, rhs: Type) @TypeOf(@clz(rhs)) { inline fn clz(comptime Type: type, rhs: Type) @TypeOf(@clz(rhs)) {
return @clz(rhs); return @clz(rhs);
} }
@ -11344,6 +11472,143 @@ test clz {
try test_clz.testIntVectors(); try test_clz.testIntVectors();
} }
inline fn sqrt(comptime Type: type, rhs: Type) @TypeOf(@sqrt(rhs)) {
return @sqrt(rhs);
}
test sqrt {
const test_sqrt = unary(sqrt, .{});
try test_sqrt.testFloats();
try test_sqrt.testFloatVectors();
}
inline fn sin(comptime Type: type, rhs: Type) @TypeOf(@sin(rhs)) {
return @sin(rhs);
}
test sin {
const test_sin = unary(sin, .{ .compare = .strict });
try test_sin.testFloats();
try test_sin.testFloatVectors();
}
inline fn cos(comptime Type: type, rhs: Type) @TypeOf(@cos(rhs)) {
return @cos(rhs);
}
test cos {
const test_cos = unary(cos, .{ .compare = .strict });
try test_cos.testFloats();
try test_cos.testFloatVectors();
}
inline fn tan(comptime Type: type, rhs: Type) @TypeOf(@tan(rhs)) {
return @tan(rhs);
}
test tan {
const test_tan = unary(tan, .{ .compare = .strict });
try test_tan.testFloats();
try test_tan.testFloatVectors();
}
inline fn exp(comptime Type: type, rhs: Type) @TypeOf(@exp(rhs)) {
return @exp(rhs);
}
test exp {
const test_exp = unary(exp, .{ .compare = .strict });
try test_exp.testFloats();
try test_exp.testFloatVectors();
}
inline fn exp2(comptime Type: type, rhs: Type) @TypeOf(@exp2(rhs)) {
return @exp2(rhs);
}
test exp2 {
const test_exp2 = unary(exp2, .{ .compare = .strict });
try test_exp2.testFloats();
try test_exp2.testFloatVectors();
}
inline fn log(comptime Type: type, rhs: Type) @TypeOf(@log(rhs)) {
return @log(rhs);
}
test log {
const test_log = unary(log, .{ .compare = .strict });
try test_log.testFloats();
try test_log.testFloatVectors();
}
inline fn log2(comptime Type: type, rhs: Type) @TypeOf(@log2(rhs)) {
return @log2(rhs);
}
test log2 {
const test_log2 = unary(log2, .{ .compare = .strict });
try test_log2.testFloats();
try test_log2.testFloatVectors();
}
inline fn log10(comptime Type: type, rhs: Type) @TypeOf(@log10(rhs)) {
return @log10(rhs);
}
test log10 {
const test_log10 = unary(log10, .{ .compare = .strict });
try test_log10.testFloats();
try test_log10.testFloatVectors();
}
inline fn abs(comptime Type: type, rhs: Type) @TypeOf(@abs(rhs)) {
return @abs(rhs);
}
test abs {
const test_abs = unary(abs, .{ .compare = .strict });
try test_abs.testInts();
try test_abs.testIntVectors();
try test_abs.testFloats();
try test_abs.testFloatVectors();
}
inline fn floor(comptime Type: type, rhs: Type) @TypeOf(@floor(rhs)) {
return @floor(rhs);
}
test floor {
const test_floor = unary(floor, .{ .compare = .strict });
try test_floor.testFloats();
try test_floor.testFloatVectors();
}
inline fn ceil(comptime Type: type, rhs: Type) @TypeOf(@ceil(rhs)) {
return @ceil(rhs);
}
test ceil {
const test_ceil = unary(ceil, .{ .compare = .strict });
try test_ceil.testFloats();
try test_ceil.testFloatVectors();
}
inline fn round(comptime Type: type, rhs: Type) @TypeOf(@round(rhs)) {
return @round(rhs);
}
test round {
const test_round = unary(round, .{ .compare = .strict });
try test_round.testFloats();
try test_round.testFloatVectors();
}
inline fn trunc(comptime Type: type, rhs: Type) @TypeOf(@trunc(rhs)) {
return @trunc(rhs);
}
test trunc {
const test_trunc = unary(trunc, .{ .compare = .strict });
try test_trunc.testFloats();
try test_trunc.testFloatVectors();
}
inline fn negate(comptime Type: type, rhs: Type) @TypeOf(-rhs) {
return -rhs;
}
test negate {
const test_negate = unary(negate, .{ .compare = .strict });
try test_negate.testFloats();
try test_negate.testFloatVectors();
}
inline fn intCast(comptime Result: type, comptime Type: type, rhs: Type, comptime ct_rhs: Type) Result { inline fn intCast(comptime Result: type, comptime Type: type, rhs: Type, comptime ct_rhs: Type) Result {
@setRuntimeSafety(false); // TODO @setRuntimeSafety(false); // TODO
const res_info = switch (@typeInfo(Result)) { const res_info = switch (@typeInfo(Result)) {
@ -11407,7 +11672,7 @@ inline fn floatCast(comptime Result: type, comptime Type: type, rhs: Type, compt
return @floatCast(rhs); return @floatCast(rhs);
} }
test floatCast { test floatCast {
const test_float_cast = cast(floatCast, .{ .strict = true }); const test_float_cast = cast(floatCast, .{ .compare = .strict });
try test_float_cast.testFloats(); try test_float_cast.testFloats();
try test_float_cast.testFloatVectors(); try test_float_cast.testFloatVectors();
} }
@ -11610,3 +11875,12 @@ test optionalsNotEqual {
try test_optionals_not_equal.testInts(); try test_optionals_not_equal.testInts();
try test_optionals_not_equal.testFloats(); try test_optionals_not_equal.testFloats();
} }
inline fn mulAdd(comptime Type: type, lhs: Type, rhs: Type) @TypeOf(@mulAdd(Type, lhs, rhs, rhs)) {
return @mulAdd(Type, lhs, rhs, rhs);
}
test mulAdd {
const test_mul_add = binary(mulAdd, .{ .compare = .approx });
try test_mul_add.testFloats();
try test_mul_add.testFloatVectors();
}