x86_64: rewrite scalar float equality comparisons

This commit is contained in:
Jacob Young 2025-01-21 08:46:12 -05:00
parent 921725427e
commit ae3d95fc8d
6 changed files with 838 additions and 186 deletions

File diff suppressed because it is too large Load Diff

View File

@ -361,7 +361,7 @@ pub const Mnemonic = enum {
addps, addss,
andps,
andnps,
cmpps, cmpss,
cmpps, cmpss, comiss,
cvtpi2ps, cvtps2pi, cvtsi2ss, cvtss2si, cvttps2pi, cvttss2si,
divps, divss,
fxrstor, fxrstor64, fxsave, fxsave64,
@ -386,7 +386,7 @@ pub const Mnemonic = enum {
andpd,
andnpd,
cmppd, //cmpsd,
comisd, comiss,
comisd,
cvtdq2pd, cvtdq2ps, cvtpd2dq, cvtpd2pi, cvtpd2ps, cvtpi2pd,
cvtps2dq, cvtps2pd, cvtsd2si, cvtsd2ss, cvtsi2sd, cvtss2sd,
cvttpd2dq, cvttpd2pi, cvttps2dq, cvttsd2si,
@ -504,6 +504,7 @@ pub const Mnemonic = enum {
vstmxcsr,
vsubpd, vsubps, vsubsd, vsubss,
vtestpd, vtestps,
vucomisd, vucomiss,
vxorpd, vxorps,
// F16C
vcvtph2ps, vcvtps2ph,

View File

@ -354,6 +354,8 @@ pub const Inst = struct {
fn_env,
/// Float No Wait ___ status word
fn_sw,
/// Float Extended ___
fx_,
/// ___ in 32-bit and Compatibility Mode
_32,
@ -817,8 +819,10 @@ pub const Inst = struct {
/// Round to integer
rndint,
/// Restore x87 FPU state
/// Restore x87 FPU, MMX, XMM, and MXCSR state
rstor,
/// Store x87 FPU state
/// Save x87 FPU, MMX technology, and MXCSR state
save,
/// Scale
scale,
@ -923,10 +927,6 @@ pub const Inst = struct {
/// Extract doubleword
/// Extract quadword
extr,
/// Restore x87 FPU, MMX, XMM, and MXCSR state
fxrstor,
/// Save x87 FPU, MMX technology, and MXCSR state
fxsave,
/// Insert byte
/// Insert word
/// Insert doubleword

View File

@ -366,7 +366,6 @@ pub const Register = enum(u8) {
@intFromEnum(Register.eax) ... @intFromEnum(Register.r15d) => @intFromEnum(Register.eax),
@intFromEnum(Register.ax) ... @intFromEnum(Register.r15w) => @intFromEnum(Register.ax),
@intFromEnum(Register.al) ... @intFromEnum(Register.r15b) => @intFromEnum(Register.al),
@intFromEnum(Register.ah) ... @intFromEnum(Register.bh) => @intFromEnum(Register.ah) - 4,
else => unreachable,
// zig fmt: on
};
@ -385,7 +384,10 @@ pub const Register = enum(u8) {
}
pub fn to8(reg: Register) Register {
return @enumFromInt(@intFromEnum(reg) - reg.gpBase() + @intFromEnum(Register.al));
return switch (@intFromEnum(reg)) {
else => @enumFromInt(@intFromEnum(reg) - reg.gpBase() + @intFromEnum(Register.al)),
@intFromEnum(Register.ah)...@intFromEnum(Register.bh) => reg,
};
}
fn sseBase(reg: Register) u7 {

View File

@ -437,6 +437,7 @@ pub const table = [_]Entry{
.{ .jmp, .d, &.{ .rel32 }, &.{ 0xe9 }, 0, .none, .none },
.{ .jmp, .m, &.{ .rm64 }, &.{ 0xff }, 4, .none, .none },
.{ .lahf, .z, &.{}, &.{ 0x9f }, 0, .none, .@"32bit" },
.{ .lahf, .z, &.{}, &.{ 0x9f }, 0, .none, .sahf },
.{ .lar, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x02 }, 0, .none, .none },
@ -744,6 +745,7 @@ pub const table = [_]Entry{
.{ .rsm, .z, &.{}, &.{ 0x0f, 0xaa }, 0, .none, .none },
.{ .sahf, .z, &.{}, &.{ 0x9e }, 0, .none, .@"32bit" },
.{ .sahf, .z, &.{}, &.{ 0x9e }, 0, .none, .sahf },
.{ .sal, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 4, .none, .none },
@ -2275,6 +2277,10 @@ pub const table = [_]Entry{
.{ .vtestpd, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x38, 0x0f }, 0, .vex_128_w0, .avx },
.{ .vtestpd, .rm, &.{ .ymm, .ymm_m256 }, &.{ 0x66, 0x0f, 0x38, 0x0f }, 0, .vex_256_w0, .avx },
.{ .vucomisd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0x66, 0x0f, 0x2e }, 0, .vex_lig_wig, .avx },
.{ .vucomiss, .rm, &.{ .xmm, .xmm_m32 }, &.{ 0x0f, 0x2e }, 0, .vex_lig_wig, .avx },
.{ .vxorpd, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x57 }, 0, .vex_128_wig, .avx },
.{ .vxorpd, .rvm, &.{ .ymm, .ymm, .ymm_m256 }, &.{ 0x66, 0x0f, 0x57 }, 0, .vex_256_wig, .avx },

View File

@ -17,8 +17,23 @@ const Sse = if (std.Target.x86.featureSetHas(builtin.cpu.features, .avx))
else
@Vector(16, u8);
inline fn sign(rhs: anytype) bool {
return @call(.always_inline, math.signbit, .{rhs});
inline fn sign(rhs: anytype) switch (@typeInfo(@TypeOf(rhs))) {
else => bool,
.vector => |vector| @Vector(vector.len, bool),
} {
switch (@typeInfo(@TypeOf(rhs))) {
else => return @as(@Type(.{ .int = .{
.signedness = .signed,
.bits = @bitSizeOf(@TypeOf(rhs)),
} }), @bitCast(rhs)) < 0,
.vector => |vector| {
const V = @Vector(vector.len, @Type(.{ .int = .{
.signedness = .signed,
.bits = @bitSizeOf(vector.child),
} }));
return @as(V, @bitCast(rhs)) < @as(V, @splat(0));
},
}
}
inline fn boolAnd(lhs: anytype, rhs: @TypeOf(lhs)) @TypeOf(lhs) {
switch (@typeInfo(@TypeOf(lhs))) {
@ -69,12 +84,40 @@ noinline fn checkExpected(expected: anytype, actual: @TypeOf(expected)) !void {
}) return error.Unexpected;
}
test checkExpected {
if (checkExpected(nan(f16), nan(f16)) == error.Unexpected) return error.Unexpected;
if (checkExpected(nan(f16), -nan(f16)) != error.Unexpected) return error.Unexpected;
if (checkExpected(@as(f16, 0.0), @as(f16, 0.0)) == error.Unexpected) return error.Unexpected;
if (checkExpected(@as(f16, -0.0), @as(f16, -0.0)) == error.Unexpected) return error.Unexpected;
if (checkExpected(@as(f16, -0.0), @as(f16, 0.0)) != error.Unexpected) return error.Unexpected;
if (checkExpected(@as(f16, 0.0), @as(f16, -0.0)) != error.Unexpected) return error.Unexpected;
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;
if (checkExpected(nan(f64), nan(f64)) == error.Unexpected) return error.Unexpected;
if (checkExpected(nan(f64), -nan(f64)) != error.Unexpected) return error.Unexpected;
if (checkExpected(@as(f64, 0.0), @as(f64, 0.0)) == error.Unexpected) return error.Unexpected;
if (checkExpected(@as(f64, -0.0), @as(f64, -0.0)) == error.Unexpected) return error.Unexpected;
if (checkExpected(@as(f64, -0.0), @as(f64, 0.0)) != error.Unexpected) return error.Unexpected;
if (checkExpected(@as(f64, 0.0), @as(f64, -0.0)) != error.Unexpected) return error.Unexpected;
if (checkExpected(nan(f80), nan(f80)) == error.Unexpected) return error.Unexpected;
if (checkExpected(nan(f80), -nan(f80)) != error.Unexpected) return error.Unexpected;
if (checkExpected(@as(f80, 0.0), @as(f80, 0.0)) == error.Unexpected) return error.Unexpected;
if (checkExpected(@as(f80, -0.0), @as(f80, -0.0)) == error.Unexpected) return error.Unexpected;
if (checkExpected(@as(f80, -0.0), @as(f80, 0.0)) != error.Unexpected) return error.Unexpected;
if (checkExpected(@as(f80, 0.0), @as(f80, -0.0)) != error.Unexpected) return error.Unexpected;
if (checkExpected(nan(f128), nan(f128)) == error.Unexpected) return error.Unexpected;
if (checkExpected(nan(f128), -nan(f128)) != error.Unexpected) return error.Unexpected;
if (checkExpected(@as(f128, 0.0), @as(f128, 0.0)) == error.Unexpected) return error.Unexpected;
if (checkExpected(@as(f128, -0.0), @as(f128, -0.0)) == error.Unexpected) return error.Unexpected;
if (checkExpected(@as(f128, -0.0), @as(f128, 0.0)) != error.Unexpected) return error.Unexpected;
if (checkExpected(@as(f128, 0.0), @as(f128, -0.0)) != error.Unexpected) return error.Unexpected;
}
fn Unary(comptime op: anytype) type {