Commit 288d3062d0

Jacob Young <jacobly0@users.noreply.github.com>
2025-02-05 01:09:46
x86_64: avoid comparing different transcendental function impls
1 parent 96ed1a2
Changed files (2)
src
arch
test
behavior
x86_64
src/arch/x86_64/CodeGen.zig
@@ -28849,166 +28849,52 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
                     } },
                 }, .{
-                    .required_features = .{ .avx, .x87, null, null },
-                    .src_constraints = .{ .{ .scalar_float = .{ .of = .xword, .is = .tbyte } }, .any, .any },
-                    .patterns = &.{
-                        .{ .src = .{ .to_mem, .none, .none } },
-                    },
-                    .call_frame = .{ .size = 16, .alignment = .@"16" },
-                    .extra_temps = .{
-                        .{ .type = .f80, .kind = .{ .reg = .xmm0 } },
-                        .{ .type = .f80, .kind = .{ .frame = .call_frame } },
-                        .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__sqrtx" } } },
-                        .unused,
-                        .unused,
-                        .unused,
-                        .unused,
-                        .unused,
-                        .unused,
-                    },
-                    .dst_temps = .{.{ .reg = .st0 }},
-                    .clobbers = .{ .eflags = true, .caller_preserved = .ccc },
-                    .each = .{ .once = &.{
-                        .{ ._, .v_dqa, .mov, .tmp0x, .mem(.src0x), ._, ._ },
-                        .{ ._, .v_dqa, .mov, .mem(.tmp1x), .tmp0x, ._, ._ },
-                        .{ ._, ._, .call, .tmp2d, ._, ._, ._ },
-                    } },
-                }, .{
-                    .required_features = .{ .sse2, .x87, null, null },
-                    .src_constraints = .{ .{ .scalar_float = .{ .of = .xword, .is = .tbyte } }, .any, .any },
-                    .patterns = &.{
-                        .{ .src = .{ .to_mem, .none, .none } },
-                    },
-                    .call_frame = .{ .size = 16, .alignment = .@"16" },
-                    .extra_temps = .{
-                        .{ .type = .f80, .kind = .{ .reg = .xmm0 } },
-                        .{ .type = .f80, .kind = .{ .frame = .call_frame } },
-                        .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__sqrtx" } } },
-                        .unused,
-                        .unused,
-                        .unused,
-                        .unused,
-                        .unused,
-                        .unused,
-                    },
-                    .dst_temps = .{.{ .reg = .st0 }},
-                    .clobbers = .{ .eflags = true, .caller_preserved = .ccc },
-                    .each = .{ .once = &.{
-                        .{ ._, ._dqa, .mov, .tmp0x, .mem(.src0x), ._, ._ },
-                        .{ ._, ._dqa, .mov, .mem(.tmp1x), .tmp0x, ._, ._ },
-                        .{ ._, ._, .call, .tmp2d, ._, ._, ._ },
-                    } },
-                }, .{
-                    .required_features = .{ .sse, .x87, null, null },
+                    .required_features = .{ .x87, null, null, null },
                     .src_constraints = .{ .{ .scalar_float = .{ .of = .xword, .is = .tbyte } }, .any, .any },
                     .patterns = &.{
-                        .{ .src = .{ .to_mem, .none, .none } },
+                        .{ .src = .{ .mem, .none, .none } },
+                        .{ .src = .{ .to_x87, .none, .none } },
                     },
-                    .call_frame = .{ .size = 16, .alignment = .@"16" },
                     .extra_temps = .{
-                        .{ .type = .f80, .kind = .{ .reg = .xmm0 } },
-                        .{ .type = .f80, .kind = .{ .frame = .call_frame } },
-                        .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__sqrtx" } } },
-                        .unused,
-                        .unused,
-                        .unused,
+                        .{ .type = .f80, .kind = .{ .reg = .st7 } },
                         .unused,
                         .unused,
                         .unused,
-                    },
-                    .dst_temps = .{.{ .reg = .st0 }},
-                    .clobbers = .{ .eflags = true, .caller_preserved = .ccc },
-                    .each = .{ .once = &.{
-                        .{ ._, ._ps, .mova, .tmp0x, .mem(.src0x), ._, ._ },
-                        .{ ._, ._ps, .mova, .mem(.tmp1x), .tmp0x, ._, ._ },
-                        .{ ._, ._, .call, .tmp2d, ._, ._, ._ },
-                    } },
-                }, .{
-                    .required_features = .{ .avx, .x87, null, null },
-                    .src_constraints = .{ .{ .multiple_scalar_float = .{ .of = .xword, .is = .tbyte } }, .any, .any },
-                    .patterns = &.{
-                        .{ .src = .{ .to_mem, .none, .none } },
-                    },
-                    .call_frame = .{ .size = 16, .alignment = .@"16" },
-                    .extra_temps = .{
-                        .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
-                        .{ .type = .f80, .kind = .{ .reg = .xmm0 } },
-                        .{ .type = .f80, .kind = .{ .frame = .call_frame } },
-                        .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__sqrtx" } } },
                         .unused,
                         .unused,
                         .unused,
                         .unused,
                         .unused,
                     },
-                    .dst_temps = .{.mem},
-                    .clobbers = .{ .eflags = true, .caller_preserved = .ccc },
+                    .dst_temps = .{.{ .mut_rc = .{ .ref = .src0, .rc = .x87 } }},
                     .each = .{ .once = &.{
-                        .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_unaligned_size), ._, ._ },
-                        .{ .@"0:", .v_dqa, .mov, .tmp1x, .memia(.src0x, .tmp0, .add_unaligned_size), ._, ._ },
-                        .{ ._, .v_dqa, .mov, .mem(.tmp2x), .tmp1x, ._, ._ },
-                        .{ ._, ._, .call, .tmp3d, ._, ._, ._ },
-                        .{ .pseudo, .f_cstp, .de, ._, ._, ._, ._ },
-                        .{ ._, .f_p, .st, .memia(.dst0t, .tmp0, .add_unaligned_size), ._, ._, ._ },
-                        .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
-                        .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
+                        .{ ._, .f_, .ld, .src0t, ._, ._, ._ },
+                        .{ ._, .f_, .sqrt, ._, ._, ._, ._ },
+                        .{ ._, .f_p, .st, .dst0t, ._, ._, ._ },
                     } },
                 }, .{
-                    .required_features = .{ .sse2, .x87, null, null },
+                    .required_features = .{ .x87, null, null, null },
                     .src_constraints = .{ .{ .multiple_scalar_float = .{ .of = .xword, .is = .tbyte } }, .any, .any },
                     .patterns = &.{
                         .{ .src = .{ .to_mem, .none, .none } },
                     },
-                    .call_frame = .{ .size = 16, .alignment = .@"16" },
                     .extra_temps = .{
                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
-                        .{ .type = .f80, .kind = .{ .reg = .xmm0 } },
-                        .{ .type = .f80, .kind = .{ .frame = .call_frame } },
-                        .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__sqrtx" } } },
-                        .unused,
-                        .unused,
+                        .{ .type = .f80, .kind = .{ .reg = .st7 } },
                         .unused,
                         .unused,
                         .unused,
-                    },
-                    .dst_temps = .{.mem},
-                    .clobbers = .{ .eflags = true, .caller_preserved = .ccc },
-                    .each = .{ .once = &.{
-                        .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_unaligned_size), ._, ._ },
-                        .{ .@"0:", ._dqa, .mov, .tmp1x, .memia(.src0x, .tmp0, .add_unaligned_size), ._, ._ },
-                        .{ ._, ._dqa, .mov, .mem(.tmp2x), .tmp1x, ._, ._ },
-                        .{ ._, ._, .call, .tmp3d, ._, ._, ._ },
-                        .{ .pseudo, .f_cstp, .de, ._, ._, ._, ._ },
-                        .{ ._, .f_p, .st, .memia(.dst0t, .tmp0, .add_unaligned_size), ._, ._, ._ },
-                        .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
-                        .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
-                    } },
-                }, .{
-                    .required_features = .{ .sse, .x87, null, null },
-                    .src_constraints = .{ .{ .multiple_scalar_float = .{ .of = .xword, .is = .tbyte } }, .any, .any },
-                    .patterns = &.{
-                        .{ .src = .{ .to_mem, .none, .none } },
-                    },
-                    .call_frame = .{ .size = 16, .alignment = .@"16" },
-                    .extra_temps = .{
-                        .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
-                        .{ .type = .f80, .kind = .{ .reg = .xmm0 } },
-                        .{ .type = .f80, .kind = .{ .frame = .call_frame } },
-                        .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__sqrtx" } } },
-                        .unused,
                         .unused,
                         .unused,
                         .unused,
                         .unused,
                     },
                     .dst_temps = .{.mem},
-                    .clobbers = .{ .eflags = true, .caller_preserved = .ccc },
+                    .clobbers = .{ .eflags = true },
                     .each = .{ .once = &.{
                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_unaligned_size), ._, ._ },
-                        .{ .@"0:", ._ps, .mova, .tmp1x, .memia(.src0x, .tmp0, .add_unaligned_size), ._, ._ },
-                        .{ ._, ._ps, .mova, .mem(.tmp2x), .tmp1x, ._, ._ },
-                        .{ ._, ._, .call, .tmp3d, ._, ._, ._ },
-                        .{ .pseudo, .f_cstp, .de, ._, ._, ._, ._ },
+                        .{ .@"0:", .f_, .ld, .memia(.src0t, .tmp0, .add_unaligned_size), ._, ._, ._ },
+                        .{ ._, .f_, .sqrt, ._, ._, ._, ._ },
                         .{ ._, .f_p, .st, .memia(.dst0t, .tmp0, .add_unaligned_size), ._, ._, ._ },
                         .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
test/behavior/x86_64/math.zig
@@ -163,7 +163,10 @@ test checkExpected {
     if (checkExpected(@as(f128, 0.0), @as(f128, -0.0), .strict) != error.Unexpected) return error.Unexpected;
 }
 
-fn unary(comptime op: anytype, comptime opts: struct { compare: Compare = .relaxed }) type {
+fn unary(comptime op: anytype, comptime opts: struct {
+    libc_name: ?[]const u8 = null,
+    compare: Compare = .relaxed,
+}) type {
     return struct {
         // noinline so that `mem_arg` is on the stack
         noinline fn testArgKinds(
@@ -187,12 +190,34 @@ fn unary(comptime op: anytype, comptime opts: struct { compare: Compare = .relax
             comptime imm_arg: Type,
             mem_arg: Type,
         ) !void {
-            const expected = comptime op(Type, imm_arg);
+            const expected = expected: {
+                if (opts.libc_name) |libc_name| libc: {
+                    const libc_func = @extern(*const fn (Scalar(Type)) callconv(.c) Scalar(Type), .{
+                        .name = switch (Scalar(Type)) {
+                            f16 => "__" ++ libc_name ++ "h",
+                            f32 => libc_name ++ "f",
+                            f64 => libc_name,
+                            f80 => "__" ++ libc_name ++ "x",
+                            f128 => libc_name ++ "q",
+                            else => break :libc,
+                        },
+                    });
+                    switch (@typeInfo(Type)) {
+                        else => break :expected libc_func(imm_arg),
+                        .vector => |vector| {
+                            var res: Type = undefined;
+                            inline for (0..vector.len) |i| res[i] = libc_func(imm_arg[i]);
+                            break :expected res;
+                        },
+                    }
+                }
+                break :expected comptime op(Type, imm_arg);
+            };
             var reg_arg = mem_arg;
             _ = .{&reg_arg};
             try checkExpected(expected, op(Type, reg_arg), opts.compare);
             try checkExpected(expected, op(Type, mem_arg), opts.compare);
-            try checkExpected(expected, op(Type, imm_arg), opts.compare);
+            if (opts.libc_name == null) try checkExpected(expected, op(Type, imm_arg), opts.compare);
         }
         // noinline for a more helpful stack trace
         noinline fn testArgs(comptime Type: type, comptime imm_arg: Type) !void {
@@ -11476,7 +11501,7 @@ inline fn sqrt(comptime Type: type, rhs: Type) @TypeOf(@sqrt(rhs)) {
     return @sqrt(rhs);
 }
 test sqrt {
-    const test_sqrt = unary(sqrt, .{});
+    const test_sqrt = unary(sqrt, .{ .libc_name = "sqrt", .compare = .approx });
     try test_sqrt.testFloats();
     try test_sqrt.testFloatVectors();
 }
@@ -11485,7 +11510,7 @@ inline fn sin(comptime Type: type, rhs: Type) @TypeOf(@sin(rhs)) {
     return @sin(rhs);
 }
 test sin {
-    const test_sin = unary(sin, .{ .compare = .strict });
+    const test_sin = unary(sin, .{ .libc_name = "sin", .compare = .strict });
     try test_sin.testFloats();
     try test_sin.testFloatVectors();
 }
@@ -11494,7 +11519,7 @@ inline fn cos(comptime Type: type, rhs: Type) @TypeOf(@cos(rhs)) {
     return @cos(rhs);
 }
 test cos {
-    const test_cos = unary(cos, .{ .compare = .strict });
+    const test_cos = unary(cos, .{ .libc_name = "cos", .compare = .strict });
     try test_cos.testFloats();
     try test_cos.testFloatVectors();
 }
@@ -11503,7 +11528,7 @@ inline fn tan(comptime Type: type, rhs: Type) @TypeOf(@tan(rhs)) {
     return @tan(rhs);
 }
 test tan {
-    const test_tan = unary(tan, .{ .compare = .strict });
+    const test_tan = unary(tan, .{ .libc_name = "tan", .compare = .strict });
     try test_tan.testFloats();
     try test_tan.testFloatVectors();
 }
@@ -11512,7 +11537,7 @@ inline fn exp(comptime Type: type, rhs: Type) @TypeOf(@exp(rhs)) {
     return @exp(rhs);
 }
 test exp {
-    const test_exp = unary(exp, .{ .compare = .strict });
+    const test_exp = unary(exp, .{ .libc_name = "exp", .compare = .strict });
     try test_exp.testFloats();
     try test_exp.testFloatVectors();
 }
@@ -11521,7 +11546,7 @@ inline fn exp2(comptime Type: type, rhs: Type) @TypeOf(@exp2(rhs)) {
     return @exp2(rhs);
 }
 test exp2 {
-    const test_exp2 = unary(exp2, .{ .compare = .strict });
+    const test_exp2 = unary(exp2, .{ .libc_name = "exp2", .compare = .strict });
     try test_exp2.testFloats();
     try test_exp2.testFloatVectors();
 }
@@ -11530,7 +11555,7 @@ inline fn log(comptime Type: type, rhs: Type) @TypeOf(@log(rhs)) {
     return @log(rhs);
 }
 test log {
-    const test_log = unary(log, .{ .compare = .strict });
+    const test_log = unary(log, .{ .libc_name = "log", .compare = .strict });
     try test_log.testFloats();
     try test_log.testFloatVectors();
 }
@@ -11539,7 +11564,7 @@ inline fn log2(comptime Type: type, rhs: Type) @TypeOf(@log2(rhs)) {
     return @log2(rhs);
 }
 test log2 {
-    const test_log2 = unary(log2, .{ .compare = .strict });
+    const test_log2 = unary(log2, .{ .libc_name = "log2", .compare = .strict });
     try test_log2.testFloats();
     try test_log2.testFloatVectors();
 }
@@ -11548,7 +11573,7 @@ inline fn log10(comptime Type: type, rhs: Type) @TypeOf(@log10(rhs)) {
     return @log10(rhs);
 }
 test log10 {
-    const test_log10 = unary(log10, .{ .compare = .strict });
+    const test_log10 = unary(log10, .{ .libc_name = "log10", .compare = .strict });
     try test_log10.testFloats();
     try test_log10.testFloatVectors();
 }
@@ -11568,7 +11593,7 @@ inline fn floor(comptime Type: type, rhs: Type) @TypeOf(@floor(rhs)) {
     return @floor(rhs);
 }
 test floor {
-    const test_floor = unary(floor, .{ .compare = .strict });
+    const test_floor = unary(floor, .{ .libc_name = "floor", .compare = .strict });
     try test_floor.testFloats();
     try test_floor.testFloatVectors();
 }
@@ -11577,7 +11602,7 @@ inline fn ceil(comptime Type: type, rhs: Type) @TypeOf(@ceil(rhs)) {
     return @ceil(rhs);
 }
 test ceil {
-    const test_ceil = unary(ceil, .{ .compare = .strict });
+    const test_ceil = unary(ceil, .{ .libc_name = "ceil", .compare = .strict });
     try test_ceil.testFloats();
     try test_ceil.testFloatVectors();
 }
@@ -11586,7 +11611,7 @@ inline fn round(comptime Type: type, rhs: Type) @TypeOf(@round(rhs)) {
     return @round(rhs);
 }
 test round {
-    const test_round = unary(round, .{ .compare = .strict });
+    const test_round = unary(round, .{ .libc_name = "round", .compare = .strict });
     try test_round.testFloats();
     try test_round.testFloatVectors();
 }
@@ -11595,7 +11620,7 @@ inline fn trunc(comptime Type: type, rhs: Type) @TypeOf(@trunc(rhs)) {
     return @trunc(rhs);
 }
 test trunc {
-    const test_trunc = unary(trunc, .{ .compare = .strict });
+    const test_trunc = unary(trunc, .{ .libc_name = "trunc", .compare = .strict });
     try test_trunc.testFloats();
     try test_trunc.testFloatVectors();
 }