mirror of
https://github.com/ziglang/zig.git
synced 2026-01-03 03:53:20 +00:00
x86_64: rewrite @abs for scalar floats
This commit is contained in:
parent
f1ce1aff11
commit
d652dd0658
File diff suppressed because it is too large
Load Diff
@ -330,8 +330,8 @@ pub const Inst = struct {
|
|||||||
f_pi,
|
f_pi,
|
||||||
/// Float ___ Pop Pop
|
/// Float ___ Pop Pop
|
||||||
f_pp,
|
f_pp,
|
||||||
/// Float ___ stack-top pointer
|
/// Float ___ crement Stack-Top Pointer
|
||||||
f_stp,
|
f_cstp,
|
||||||
/// Float ___ Status Word
|
/// Float ___ Status Word
|
||||||
f_sw,
|
f_sw,
|
||||||
/// Float ___ Unordered
|
/// Float ___ Unordered
|
||||||
@ -555,6 +555,7 @@ pub const Inst = struct {
|
|||||||
/// Decimal adjust AL after subtraction
|
/// Decimal adjust AL after subtraction
|
||||||
da,
|
da,
|
||||||
/// Decrement by 1
|
/// Decrement by 1
|
||||||
|
/// Decrement stack-top pointer
|
||||||
/// Decrement shadow stack pointer
|
/// Decrement shadow stack pointer
|
||||||
de,
|
de,
|
||||||
/// Unsigned division
|
/// Unsigned division
|
||||||
@ -587,6 +588,7 @@ pub const Inst = struct {
|
|||||||
/// Input from port
|
/// Input from port
|
||||||
/// Input from port to string
|
/// Input from port to string
|
||||||
/// Increment by 1
|
/// Increment by 1
|
||||||
|
/// Increment stack-top pointer
|
||||||
/// Increment shadow stack pointer
|
/// Increment shadow stack pointer
|
||||||
in,
|
in,
|
||||||
/// Call to interrupt procedure
|
/// Call to interrupt procedure
|
||||||
@ -792,14 +794,10 @@ pub const Inst = struct {
|
|||||||
comi,
|
comi,
|
||||||
/// Cosine
|
/// Cosine
|
||||||
cos,
|
cos,
|
||||||
/// Decrement stack-top pointer
|
|
||||||
decstp,
|
|
||||||
/// Reverse divide
|
/// Reverse divide
|
||||||
divr,
|
divr,
|
||||||
/// Free floating-point register
|
/// Free floating-point register
|
||||||
free,
|
free,
|
||||||
/// Increment stack-top pointer
|
|
||||||
incstp,
|
|
||||||
/// Initialize floating-point unit
|
/// Initialize floating-point unit
|
||||||
init,
|
init,
|
||||||
/// Load binary coded decimal integer
|
/// Load binary coded decimal integer
|
||||||
|
|||||||
@ -427,7 +427,7 @@ pub const zigcc = struct {
|
|||||||
|
|
||||||
const int_param_regs = gp_regs[0 .. volatile_gpr - 1];
|
const int_param_regs = gp_regs[0 .. volatile_gpr - 1];
|
||||||
const x87_param_regs = x87_regs[0..volatile_x87];
|
const x87_param_regs = x87_regs[0..volatile_x87];
|
||||||
const sse_param_regs = sse_avx_regs[0..volatile_sse];
|
const sse_param_regs = sse_avx_regs[0 .. volatile_sse / 2];
|
||||||
const int_return_regs = gp_regs[0..volatile_gpr];
|
const int_return_regs = gp_regs[0..volatile_gpr];
|
||||||
const x87_return_regs = x87_regs[0..volatile_x87];
|
const x87_return_regs = x87_regs[0..volatile_x87];
|
||||||
const sse_return_regs = sse_avx_regs[0..volatile_gpr];
|
const sse_return_regs = sse_avx_regs[0..volatile_gpr];
|
||||||
@ -443,11 +443,11 @@ pub const SysV = struct {
|
|||||||
pub const caller_preserved_regs = [_]Register{ .rax, .rcx, .rdx, .rsi, .rdi, .r8, .r9, .r10, .r11 } ++ x87_regs ++ sse_avx_regs;
|
pub const caller_preserved_regs = [_]Register{ .rax, .rcx, .rdx, .rsi, .rdi, .r8, .r9, .r10, .r11 } ++ x87_regs ++ sse_avx_regs;
|
||||||
|
|
||||||
pub const c_abi_int_param_regs = [_]Register{ .rdi, .rsi, .rdx, .rcx, .r8, .r9 };
|
pub const c_abi_int_param_regs = [_]Register{ .rdi, .rsi, .rdx, .rcx, .r8, .r9 };
|
||||||
pub const c_abi_x87_param_regs = x87_regs[0..0].*;
|
pub const c_abi_x87_param_regs = x87_regs[0..0];
|
||||||
pub const c_abi_sse_param_regs = sse_avx_regs[0..8].*;
|
pub const c_abi_sse_param_regs = sse_avx_regs[0..8];
|
||||||
pub const c_abi_int_return_regs = [_]Register{ .rax, .rdx };
|
pub const c_abi_int_return_regs = [_]Register{ .rax, .rdx };
|
||||||
pub const c_abi_x87_return_regs = x87_regs[0..2].*;
|
pub const c_abi_x87_return_regs = x87_regs[0..2];
|
||||||
pub const c_abi_sse_return_regs = sse_avx_regs[0..4].*;
|
pub const c_abi_sse_return_regs = sse_avx_regs[0..4];
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Win64 = struct {
|
pub const Win64 = struct {
|
||||||
@ -460,11 +460,11 @@ pub const Win64 = struct {
|
|||||||
pub const caller_preserved_regs = [_]Register{ .rax, .rcx, .rdx, .r8, .r9, .r10, .r11 } ++ x87_regs ++ sse_avx_regs;
|
pub const caller_preserved_regs = [_]Register{ .rax, .rcx, .rdx, .r8, .r9, .r10, .r11 } ++ x87_regs ++ sse_avx_regs;
|
||||||
|
|
||||||
pub const c_abi_int_param_regs = [_]Register{ .rcx, .rdx, .r8, .r9 };
|
pub const c_abi_int_param_regs = [_]Register{ .rcx, .rdx, .r8, .r9 };
|
||||||
pub const c_abi_x87_param_regs = x87_regs[0..0].*;
|
pub const c_abi_x87_param_regs = x87_regs[0..0];
|
||||||
pub const c_abi_sse_param_regs = sse_avx_regs[0..4].*;
|
pub const c_abi_sse_param_regs = sse_avx_regs[0..4];
|
||||||
pub const c_abi_int_return_regs = [_]Register{.rax};
|
pub const c_abi_int_return_regs = [_]Register{.rax};
|
||||||
pub const c_abi_x87_return_regs = x87_regs[0..0].*;
|
pub const c_abi_x87_return_regs = x87_regs[0..0];
|
||||||
pub const c_abi_sse_return_regs = sse_avx_regs[0..1].*;
|
pub const c_abi_sse_return_regs = sse_avx_regs[0..1];
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn getCalleePreservedRegs(cc: std.builtin.CallingConvention.Tag) []const Register {
|
pub fn getCalleePreservedRegs(cc: std.builtin.CallingConvention.Tag) []const Register {
|
||||||
@ -497,17 +497,21 @@ pub fn getCAbiIntParamRegs(cc: std.builtin.CallingConvention.Tag) []const Regist
|
|||||||
pub fn getCAbiX87ParamRegs(cc: std.builtin.CallingConvention.Tag) []const Register {
|
pub fn getCAbiX87ParamRegs(cc: std.builtin.CallingConvention.Tag) []const Register {
|
||||||
return switch (cc) {
|
return switch (cc) {
|
||||||
.auto => zigcc.x87_param_regs,
|
.auto => zigcc.x87_param_regs,
|
||||||
.x86_64_sysv => &SysV.c_abi_x87_param_regs,
|
.x86_64_sysv => SysV.c_abi_x87_param_regs,
|
||||||
.x86_64_win => &Win64.c_abi_x87_param_regs,
|
.x86_64_win => Win64.c_abi_x87_param_regs,
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getCAbiSseParamRegs(cc: std.builtin.CallingConvention.Tag) []const Register {
|
pub fn getCAbiSseParamRegs(cc: std.builtin.CallingConvention.Tag, target: *const std.Target) []const Register {
|
||||||
return switch (cc) {
|
return switch (cc) {
|
||||||
.auto => zigcc.sse_param_regs,
|
.auto => switch (target.cpu.arch) {
|
||||||
.x86_64_sysv => &SysV.c_abi_sse_param_regs,
|
else => unreachable,
|
||||||
.x86_64_win => &Win64.c_abi_sse_param_regs,
|
.x86 => zigcc.sse_param_regs[0 .. zigcc.sse_param_regs.len / 2],
|
||||||
|
.x86_64 => zigcc.sse_param_regs,
|
||||||
|
},
|
||||||
|
.x86_64_sysv => SysV.c_abi_sse_param_regs,
|
||||||
|
.x86_64_win => Win64.c_abi_sse_param_regs,
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -524,8 +528,8 @@ pub fn getCAbiIntReturnRegs(cc: std.builtin.CallingConvention.Tag) []const Regis
|
|||||||
pub fn getCAbiX87ReturnRegs(cc: std.builtin.CallingConvention.Tag) []const Register {
|
pub fn getCAbiX87ReturnRegs(cc: std.builtin.CallingConvention.Tag) []const Register {
|
||||||
return switch (cc) {
|
return switch (cc) {
|
||||||
.auto => zigcc.x87_return_regs,
|
.auto => zigcc.x87_return_regs,
|
||||||
.x86_64_sysv => &SysV.c_abi_x87_return_regs,
|
.x86_64_sysv => SysV.c_abi_x87_return_regs,
|
||||||
.x86_64_win => &Win64.c_abi_x87_return_regs,
|
.x86_64_win => Win64.c_abi_x87_return_regs,
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -533,8 +537,8 @@ pub fn getCAbiX87ReturnRegs(cc: std.builtin.CallingConvention.Tag) []const Regis
|
|||||||
pub fn getCAbiSseReturnRegs(cc: std.builtin.CallingConvention.Tag) []const Register {
|
pub fn getCAbiSseReturnRegs(cc: std.builtin.CallingConvention.Tag) []const Register {
|
||||||
return switch (cc) {
|
return switch (cc) {
|
||||||
.auto => zigcc.sse_return_regs,
|
.auto => zigcc.sse_return_regs,
|
||||||
.x86_64_sysv => &SysV.c_abi_sse_return_regs,
|
.x86_64_sysv => SysV.c_abi_sse_return_regs,
|
||||||
.x86_64_win => &Win64.c_abi_sse_return_regs,
|
.x86_64_win => Win64.c_abi_sse_return_regs,
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,22 +1,136 @@
|
|||||||
|
const builtin = @import("builtin");
|
||||||
|
const inf = math.inf;
|
||||||
|
const math = std.math;
|
||||||
|
const max = math.floatMax;
|
||||||
|
const min = math.floatMin;
|
||||||
|
const nan = math.nan;
|
||||||
|
const std = @import("std");
|
||||||
|
const trueMin = math.floatTrueMin;
|
||||||
|
|
||||||
|
const Gpr = switch (builtin.cpu.arch) {
|
||||||
|
else => unreachable,
|
||||||
|
.x86 => u32,
|
||||||
|
.x86_64 => u64,
|
||||||
|
};
|
||||||
|
const Sse = if (std.Target.x86.featureSetHas(builtin.cpu.features, .avx))
|
||||||
|
@Vector(32, u8)
|
||||||
|
else
|
||||||
|
@Vector(16, u8);
|
||||||
|
|
||||||
|
inline fn sign(rhs: anytype) bool {
|
||||||
|
return @call(.always_inline, math.signbit, .{rhs});
|
||||||
|
}
|
||||||
|
inline fn boolAnd(lhs: anytype, rhs: @TypeOf(lhs)) @TypeOf(lhs) {
|
||||||
|
switch (@typeInfo(@TypeOf(lhs))) {
|
||||||
|
.bool => return lhs and rhs,
|
||||||
|
.vector => |vector| switch (vector.child) {
|
||||||
|
bool => {
|
||||||
|
const Bits = @Vector(vector.len, u1);
|
||||||
|
const lhs_bits: Bits = @bitCast(lhs);
|
||||||
|
const rhs_bits: Bits = @bitCast(rhs);
|
||||||
|
return @bitCast(lhs_bits & rhs_bits);
|
||||||
|
},
|
||||||
|
else => {},
|
||||||
|
},
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
|
@compileError("unsupported boolAnd type: " ++ @typeName(@TypeOf(lhs)));
|
||||||
|
}
|
||||||
|
inline fn boolOr(lhs: anytype, rhs: @TypeOf(lhs)) @TypeOf(lhs) {
|
||||||
|
switch (@typeInfo(@TypeOf(lhs))) {
|
||||||
|
.bool => return lhs or rhs,
|
||||||
|
.vector => |vector| switch (vector.child) {
|
||||||
|
bool => {
|
||||||
|
const Bits = @Vector(vector.len, u1);
|
||||||
|
const lhs_bits: Bits = @bitCast(lhs);
|
||||||
|
const rhs_bits: Bits = @bitCast(rhs);
|
||||||
|
return @bitCast(lhs_bits | rhs_bits);
|
||||||
|
},
|
||||||
|
else => {},
|
||||||
|
},
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
|
@compileError("unsupported boolOr type: " ++ @typeName(@TypeOf(lhs)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// noinline for a more helpful stack trace
|
||||||
|
noinline fn checkExpected(expected: anytype, actual: @TypeOf(expected)) !void {
|
||||||
|
const info = @typeInfo(@TypeOf(expected));
|
||||||
|
const unexpected = switch (switch (info) {
|
||||||
|
else => info,
|
||||||
|
.vector => |vector| @typeInfo(vector.child),
|
||||||
|
}) {
|
||||||
|
else => expected != actual,
|
||||||
|
.float => boolOr(boolAnd(expected != actual, boolOr(expected == expected, actual == actual)), sign(expected) != sign(actual)),
|
||||||
|
};
|
||||||
|
if (switch (info) {
|
||||||
|
else => unexpected,
|
||||||
|
.vector => @reduce(.Or, unexpected),
|
||||||
|
}) return error.Unexpected;
|
||||||
|
}
|
||||||
|
test checkExpected {
|
||||||
|
if (checkExpected(nan(f32), nan(f32)) == error.Unexpected) return error.Unexpected;
|
||||||
|
if (checkExpected(nan(f32), -nan(f32)) != error.Unexpected) return error.Unexpected;
|
||||||
|
if (checkExpected(@as(f32, 0.0), @as(f32, 0.0)) == error.Unexpected) return error.Unexpected;
|
||||||
|
if (checkExpected(@as(f32, -0.0), @as(f32, -0.0)) == error.Unexpected) return error.Unexpected;
|
||||||
|
if (checkExpected(@as(f32, -0.0), @as(f32, 0.0)) != error.Unexpected) return error.Unexpected;
|
||||||
|
if (checkExpected(@as(f32, 0.0), @as(f32, -0.0)) != error.Unexpected) return error.Unexpected;
|
||||||
|
}
|
||||||
|
|
||||||
fn Unary(comptime op: anytype) type {
|
fn Unary(comptime op: anytype) type {
|
||||||
return struct {
|
return struct {
|
||||||
fn testArgs(comptime Type: type, comptime imm_arg: Type) !void {
|
// noinline so that `mem_arg` is on the stack
|
||||||
const expected = op(Type, imm_arg);
|
noinline fn testArgKinds(
|
||||||
try struct {
|
_: Gpr,
|
||||||
fn checkExpected(actual: @TypeOf(expected)) !void {
|
_: Gpr,
|
||||||
if (switch (@typeInfo(@TypeOf(expected))) {
|
_: Gpr,
|
||||||
else => actual != expected,
|
_: Gpr,
|
||||||
.vector => @reduce(.Or, actual != expected),
|
_: Gpr,
|
||||||
}) return error.Unexpected;
|
_: Gpr,
|
||||||
}
|
_: Gpr,
|
||||||
noinline fn testArgKinds(mem_arg: Type) !void {
|
_: Gpr,
|
||||||
|
_: Sse,
|
||||||
|
_: Sse,
|
||||||
|
_: Sse,
|
||||||
|
_: Sse,
|
||||||
|
_: Sse,
|
||||||
|
_: Sse,
|
||||||
|
_: Sse,
|
||||||
|
_: Sse,
|
||||||
|
comptime Type: type,
|
||||||
|
comptime imm_arg: Type,
|
||||||
|
mem_arg: Type,
|
||||||
|
) !void {
|
||||||
|
const expected = comptime op(Type, imm_arg);
|
||||||
var reg_arg = mem_arg;
|
var reg_arg = mem_arg;
|
||||||
_ = .{®_arg};
|
_ = .{®_arg};
|
||||||
try checkExpected(op(Type, reg_arg));
|
try checkExpected(expected, op(Type, reg_arg));
|
||||||
try checkExpected(op(Type, mem_arg));
|
try checkExpected(expected, op(Type, mem_arg));
|
||||||
try checkExpected(op(Type, imm_arg));
|
try checkExpected(expected, op(Type, imm_arg));
|
||||||
}
|
}
|
||||||
}.testArgKinds(imm_arg);
|
// noinline for a more helpful stack trace
|
||||||
|
noinline fn testArgs(comptime Type: type, comptime imm_arg: Type) !void {
|
||||||
|
try testArgKinds(
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
Type,
|
||||||
|
imm_arg,
|
||||||
|
imm_arg,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
fn testIntTypes() !void {
|
fn testIntTypes() !void {
|
||||||
try testArgs(i1, -1);
|
try testArgs(i1, -1);
|
||||||
@ -381,6 +495,102 @@ fn Unary(comptime op: anytype) type {
|
|||||||
try testArgs(u1025, 1 << 1023);
|
try testArgs(u1025, 1 << 1023);
|
||||||
try testArgs(u1025, 1 << 1024);
|
try testArgs(u1025, 1 << 1024);
|
||||||
}
|
}
|
||||||
|
fn testFloatTypes() !void {
|
||||||
|
try testArgs(f16, -nan(f16));
|
||||||
|
try testArgs(f16, -inf(f16));
|
||||||
|
try testArgs(f16, -max(f16));
|
||||||
|
try testArgs(f16, -10.0);
|
||||||
|
try testArgs(f16, -1.0);
|
||||||
|
try testArgs(f16, -0.1);
|
||||||
|
try testArgs(f16, -min(f16));
|
||||||
|
try testArgs(f16, -trueMin(f16));
|
||||||
|
try testArgs(f16, -0.0);
|
||||||
|
try testArgs(f16, 0.0);
|
||||||
|
try testArgs(f16, trueMin(f16));
|
||||||
|
try testArgs(f16, min(f16));
|
||||||
|
try testArgs(f16, 0.1);
|
||||||
|
try testArgs(f16, 1.0);
|
||||||
|
try testArgs(f16, 10.0);
|
||||||
|
try testArgs(f16, max(f16));
|
||||||
|
try testArgs(f16, inf(f16));
|
||||||
|
try testArgs(f16, nan(f16));
|
||||||
|
|
||||||
|
try testArgs(f32, -nan(f32));
|
||||||
|
try testArgs(f32, -inf(f32));
|
||||||
|
try testArgs(f32, -max(f32));
|
||||||
|
try testArgs(f32, -10.0);
|
||||||
|
try testArgs(f32, -1.0);
|
||||||
|
try testArgs(f32, -0.1);
|
||||||
|
try testArgs(f32, -min(f32));
|
||||||
|
try testArgs(f32, -trueMin(f32));
|
||||||
|
try testArgs(f32, -0.0);
|
||||||
|
try testArgs(f32, 0.0);
|
||||||
|
try testArgs(f32, trueMin(f32));
|
||||||
|
try testArgs(f32, min(f32));
|
||||||
|
try testArgs(f32, 0.1);
|
||||||
|
try testArgs(f32, 1.0);
|
||||||
|
try testArgs(f32, 10.0);
|
||||||
|
try testArgs(f32, max(f32));
|
||||||
|
try testArgs(f32, inf(f32));
|
||||||
|
try testArgs(f32, nan(f32));
|
||||||
|
|
||||||
|
try testArgs(f64, -nan(f64));
|
||||||
|
try testArgs(f64, -inf(f64));
|
||||||
|
try testArgs(f64, -max(f64));
|
||||||
|
try testArgs(f64, -10.0);
|
||||||
|
try testArgs(f64, -1.0);
|
||||||
|
try testArgs(f64, -0.1);
|
||||||
|
try testArgs(f64, -min(f64));
|
||||||
|
try testArgs(f64, -trueMin(f64));
|
||||||
|
try testArgs(f64, -0.0);
|
||||||
|
try testArgs(f64, 0.0);
|
||||||
|
try testArgs(f64, trueMin(f64));
|
||||||
|
try testArgs(f64, min(f64));
|
||||||
|
try testArgs(f64, 0.1);
|
||||||
|
try testArgs(f64, 1.0);
|
||||||
|
try testArgs(f64, 10.0);
|
||||||
|
try testArgs(f64, max(f64));
|
||||||
|
try testArgs(f64, inf(f64));
|
||||||
|
try testArgs(f64, nan(f64));
|
||||||
|
|
||||||
|
try testArgs(f80, -nan(f80));
|
||||||
|
try testArgs(f80, -inf(f80));
|
||||||
|
try testArgs(f80, -max(f80));
|
||||||
|
try testArgs(f80, -10.0);
|
||||||
|
try testArgs(f80, -1.0);
|
||||||
|
try testArgs(f80, -0.1);
|
||||||
|
try testArgs(f80, -min(f80));
|
||||||
|
try testArgs(f80, -trueMin(f80));
|
||||||
|
try testArgs(f80, -0.0);
|
||||||
|
try testArgs(f80, 0.0);
|
||||||
|
try testArgs(f80, trueMin(f80));
|
||||||
|
try testArgs(f80, min(f80));
|
||||||
|
try testArgs(f80, 0.1);
|
||||||
|
try testArgs(f80, 1.0);
|
||||||
|
try testArgs(f80, 10.0);
|
||||||
|
try testArgs(f80, max(f80));
|
||||||
|
try testArgs(f80, inf(f80));
|
||||||
|
try testArgs(f80, nan(f80));
|
||||||
|
|
||||||
|
try testArgs(f128, -nan(f128));
|
||||||
|
try testArgs(f128, -inf(f128));
|
||||||
|
try testArgs(f128, -max(f128));
|
||||||
|
try testArgs(f128, -10.0);
|
||||||
|
try testArgs(f128, -1.0);
|
||||||
|
try testArgs(f128, -0.1);
|
||||||
|
try testArgs(f128, -min(f128));
|
||||||
|
try testArgs(f128, -trueMin(f128));
|
||||||
|
try testArgs(f128, -0.0);
|
||||||
|
try testArgs(f128, 0.0);
|
||||||
|
try testArgs(f128, trueMin(f128));
|
||||||
|
try testArgs(f128, min(f128));
|
||||||
|
try testArgs(f128, 0.1);
|
||||||
|
try testArgs(f128, 1.0);
|
||||||
|
try testArgs(f128, 10.0);
|
||||||
|
try testArgs(f128, max(f128));
|
||||||
|
try testArgs(f128, inf(f128));
|
||||||
|
try testArgs(f128, nan(f128));
|
||||||
|
}
|
||||||
fn testIntVectorTypes() !void {
|
fn testIntVectorTypes() !void {
|
||||||
try testArgs(@Vector(3, i1), .{ -1 << 0, -1, 0 });
|
try testArgs(@Vector(3, i1), .{ -1 << 0, -1, 0 });
|
||||||
try testArgs(@Vector(3, u1), .{ 0, 1, 1 << 0 });
|
try testArgs(@Vector(3, u1), .{ 0, 1, 1 << 0 });
|
||||||
@ -931,29 +1141,68 @@ fn Unary(comptime op: anytype) type {
|
|||||||
|
|
||||||
fn Binary(comptime op: anytype) type {
|
fn Binary(comptime op: anytype) type {
|
||||||
return struct {
|
return struct {
|
||||||
fn testArgs(comptime Type: type, comptime imm_lhs: Type, comptime imm_rhs: Type) !void {
|
// noinline so that `mem_lhs` and `mem_rhs` are on the stack
|
||||||
const expected = op(Type, imm_lhs, imm_rhs);
|
noinline fn testArgKinds(
|
||||||
try struct {
|
_: Gpr,
|
||||||
fn checkExpected(actual: @TypeOf(expected)) !void {
|
_: Gpr,
|
||||||
if (switch (@typeInfo(@TypeOf(expected))) {
|
_: Gpr,
|
||||||
else => actual != expected,
|
_: Gpr,
|
||||||
.vector => @reduce(.Or, actual != expected),
|
_: Gpr,
|
||||||
}) return error.Unexpected;
|
_: Gpr,
|
||||||
}
|
_: Gpr,
|
||||||
noinline fn testArgKinds(mem_lhs: Type, mem_rhs: Type) !void {
|
_: Gpr,
|
||||||
|
_: Sse,
|
||||||
|
_: Sse,
|
||||||
|
_: Sse,
|
||||||
|
_: Sse,
|
||||||
|
_: Sse,
|
||||||
|
_: Sse,
|
||||||
|
_: Sse,
|
||||||
|
_: Sse,
|
||||||
|
comptime Type: type,
|
||||||
|
comptime imm_lhs: Type,
|
||||||
|
mem_lhs: Type,
|
||||||
|
comptime imm_rhs: Type,
|
||||||
|
mem_rhs: Type,
|
||||||
|
) !void {
|
||||||
|
const expected = comptime op(Type, imm_lhs, imm_rhs);
|
||||||
var reg_lhs = mem_lhs;
|
var reg_lhs = mem_lhs;
|
||||||
var reg_rhs = mem_rhs;
|
var reg_rhs = mem_rhs;
|
||||||
_ = .{ ®_lhs, ®_rhs };
|
_ = .{ ®_lhs, ®_rhs };
|
||||||
try checkExpected(op(Type, reg_lhs, reg_rhs));
|
try checkExpected(expected, op(Type, reg_lhs, reg_rhs));
|
||||||
try checkExpected(op(Type, reg_lhs, mem_rhs));
|
try checkExpected(expected, op(Type, reg_lhs, mem_rhs));
|
||||||
try checkExpected(op(Type, reg_lhs, imm_rhs));
|
try checkExpected(expected, op(Type, reg_lhs, imm_rhs));
|
||||||
try checkExpected(op(Type, mem_lhs, reg_rhs));
|
try checkExpected(expected, op(Type, mem_lhs, reg_rhs));
|
||||||
try checkExpected(op(Type, mem_lhs, mem_rhs));
|
try checkExpected(expected, op(Type, mem_lhs, mem_rhs));
|
||||||
try checkExpected(op(Type, mem_lhs, imm_rhs));
|
try checkExpected(expected, op(Type, mem_lhs, imm_rhs));
|
||||||
try checkExpected(op(Type, imm_lhs, reg_rhs));
|
try checkExpected(expected, op(Type, imm_lhs, reg_rhs));
|
||||||
try checkExpected(op(Type, imm_lhs, mem_rhs));
|
try checkExpected(expected, op(Type, imm_lhs, mem_rhs));
|
||||||
}
|
}
|
||||||
}.testArgKinds(imm_lhs, imm_rhs);
|
// noinline for a more helpful stack trace
|
||||||
|
noinline fn testArgs(comptime Type: type, comptime imm_lhs: Type, comptime imm_rhs: Type) !void {
|
||||||
|
try testArgKinds(
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
Type,
|
||||||
|
imm_lhs,
|
||||||
|
imm_lhs,
|
||||||
|
imm_rhs,
|
||||||
|
imm_rhs,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
fn testIntTypes() !void {
|
fn testIntTypes() !void {
|
||||||
try testArgs(u8, 0xbb, 0x43);
|
try testArgs(u8, 0xbb, 0x43);
|
||||||
@ -1308,6 +1557,7 @@ inline fn abs(comptime Type: type, rhs: Type) @TypeOf(@abs(rhs)) {
|
|||||||
test abs {
|
test abs {
|
||||||
try Unary(abs).testIntTypes();
|
try Unary(abs).testIntTypes();
|
||||||
try Unary(abs).testIntVectorTypes();
|
try Unary(abs).testIntVectorTypes();
|
||||||
|
try Unary(abs).testFloatTypes();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fn clz(comptime Type: type, rhs: Type) @TypeOf(@clz(rhs)) {
|
inline fn clz(comptime Type: type, rhs: Type) @TypeOf(@clz(rhs)) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user