Skip to content

Commit da335f0

Browse files
committed
x86_64: implement float @sqrt builtin
1 parent fbe5bf4 commit da335f0

File tree

2 files changed

+93
-88
lines changed

2 files changed

+93
-88
lines changed

src/arch/x86_64/CodeGen.zig

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5359,9 +5359,21 @@ fn airSqrt(self: *Self, inst: Air.Inst.Index) !void {
53595359
else => unreachable,
53605360
},
53615361
else => unreachable,
5362-
}) orelse return self.fail("TODO implement airSqrt for {}", .{
5363-
ty.fmt(mod),
5364-
});
5362+
}) orelse {
5363+
if (ty.zigTypeTag(mod) != .Float) return self.fail("TODO implement airSqrt for {}", .{
5364+
ty.fmt(mod),
5365+
});
5366+
5367+
var callee: ["__sqrt?".len]u8 = undefined;
5368+
break :result try self.genCall(.{ .lib = .{
5369+
.return_type = ty.toIntern(),
5370+
.param_types = &.{ty.toIntern()},
5371+
.callee = std.fmt.bufPrint(&callee, "{s}sqrt{s}", .{
5372+
floatLibcAbiPrefix(ty),
5373+
floatLibcAbiSuffix(ty),
5374+
}) catch unreachable,
5375+
} }, &.{ty}, &.{src_mcv});
5376+
};
53655377
switch (mir_tag[0]) {
53665378
.v_ss, .v_sd => if (src_mcv.isMemory()) try self.asmRegisterRegisterMemory(
53675379
mir_tag,

test/behavior/floatop.zig

Lines changed: 78 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,6 @@ const std = @import("std");
22
const builtin = @import("builtin");
33
const expect = std.testing.expect;
44
const math = std.math;
5-
const has_f80_rt = switch (builtin.cpu.arch) {
6-
.x86_64, .x86 => true,
7-
else => false,
8-
};
9-
const no_x86_64_hardware_f16_support = builtin.zig_backend == .stage2_x86_64 and
10-
!std.Target.x86.featureSetHas(builtin.cpu.features, .f16c);
115

126
const epsilon_16 = 0.002;
137
const epsilon = 0.000001;
@@ -247,42 +241,93 @@ test "negative f128 intFromFloat at compile-time" {
247241
try expect(@as(i64, -2) == b);
248242
}
249243

250-
test "@sqrt" {
244+
test "@sqrt f16" {
251245
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
252246
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
253247
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
254248
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
249+
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
255250

256-
try testSqrt();
257-
try comptime testSqrt();
251+
try testSqrt(f16);
252+
try comptime testSqrt(f16);
258253
}
259254

260-
fn testSqrt() !void {
261-
try expect(@sqrt(@as(f16, 4)) == 2);
262-
try expect(@sqrt(@as(f32, 9)) == 3);
263-
try expect(@sqrt(@as(f64, 25)) == 5);
264-
try expect(math.approxEqAbs(f32, @sqrt(@as(f32, 1.1)), 1.0488088481701516, epsilon));
265-
try expect(math.approxEqAbs(f32, @sqrt(@as(f32, 2.0)), 1.4142135623730950, epsilon));
255+
test "@sqrt f32/f64" {
256+
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
257+
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
258+
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
259+
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
260+
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
261+
262+
try testSqrt(f32);
263+
try comptime testSqrt(f32);
264+
try testSqrt(f64);
265+
try comptime testSqrt(f64);
266+
}
266267

267-
if (false) {
268-
if (has_f80_rt) {
269-
// TODO https://github.com/ziglang/zig/issues/10875
270-
if (builtin.os.tag != .freebsd) {
271-
var a: f80 = 25;
272-
try expect(@sqrt(a) == 5);
273-
}
274-
}
275-
{
276-
const a: comptime_float = 25.0;
277-
try expect(@sqrt(a) == 5.0);
278-
}
279-
// TODO test f128, and c_longdouble
280-
// https://github.com/ziglang/zig/issues/4026
281-
//{
282-
// var a: f128 = 49;
283-
//try expect(@sqrt(a) == 7);
284-
//}
268+
test "@sqrt f80/f128/c_longdouble" {
269+
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
270+
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
271+
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
272+
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
273+
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
274+
275+
if (builtin.os.tag == .freebsd) {
276+
// TODO https://github.com/ziglang/zig/issues/10875
277+
return error.SkipZigTest;
285278
}
279+
280+
try testSqrt(f80);
281+
try comptime testSqrt(f80);
282+
try testSqrt(f128);
283+
try comptime testSqrt(f128);
284+
try testSqrt(c_longdouble);
285+
try comptime testSqrt(c_longdouble);
286+
}
287+
288+
fn testSqrt(comptime T: type) !void {
289+
const eps = epsForType(T);
290+
var four: T = 4.0;
291+
try expect(@sqrt(four) == 2.0);
292+
var nine: T = 9.0;
293+
try expect(@sqrt(nine) == 3.0);
294+
var twenty_five: T = 25.0;
295+
try expect(@sqrt(twenty_five) == 5.0);
296+
var sixty_four: T = 64.0;
297+
try expect(@sqrt(sixty_four) == 8.0);
298+
var one_point_one: T = 1.1;
299+
300+
try expect(math.approxEqAbs(T, @sqrt(one_point_one), 1.0488088481701516, eps));
301+
var two: T = 2.0;
302+
try expect(math.approxEqAbs(T, @sqrt(two), 1.4142135623730950, eps));
303+
var three_point_six: T = 3.6;
304+
try expect(math.approxEqAbs(T, @sqrt(three_point_six), 1.8973665961010276, eps));
305+
var sixty_four_point_one: T = 64.1;
306+
try expect(math.approxEqAbs(T, @sqrt(sixty_four_point_one), 8.00624756049923802, eps));
307+
var twelve: T = 12.0;
308+
try expect(math.approxEqAbs(T, @sqrt(twelve), 3.46410161513775459, eps));
309+
var thirteen: T = 13.0;
310+
try expect(math.approxEqAbs(T, @sqrt(thirteen), 3.60555127546398929, eps));
311+
var fourteen: T = 14.0;
312+
try expect(math.approxEqAbs(T, @sqrt(fourteen), 3.74165738677394139, eps));
313+
var a: T = 7.539840;
314+
try expect(math.approxEqAbs(T, @sqrt(a), 2.74587690911300684, eps));
315+
var b: T = 19.230934;
316+
try expect(math.approxEqAbs(T, @sqrt(b), 4.38530888307767894, eps));
317+
var c: T = 8942.230469;
318+
try expect(math.approxEqAbs(T, @sqrt(c), 94.5633674791671111, eps));
319+
320+
// special cases
321+
var inf: T = math.inf(T);
322+
try expect(math.isPositiveInf(@sqrt(inf)));
323+
var zero: T = 0.0;
324+
try expect(@sqrt(zero) == 0.0);
325+
var neg_zero: T = -0.0;
326+
try expect(@sqrt(neg_zero) == 0.0);
327+
var neg_one: T = -1.0;
328+
try expect(math.isNan(@sqrt(neg_one)));
329+
var nan: T = math.nan(T);
330+
try expect(math.isNan(@sqrt(nan)));
286331
}
287332

288333
test "@sqrt with vectors" {
@@ -304,58 +349,6 @@ fn testSqrtWithVectors() !void {
304349
try expect(math.approxEqAbs(f32, @sqrt(@as(f32, 4.4)), result[3], epsilon));
305350
}
306351

307-
test "more @sqrt f16 tests" {
308-
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
309-
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
310-
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
311-
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
312-
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
313-
314-
// TODO these are not all passing at comptime
315-
try expect(@sqrt(@as(f16, 0.0)) == 0.0);
316-
try expect(math.approxEqAbs(f16, @sqrt(@as(f16, 2.0)), 1.414214, epsilon));
317-
try expect(math.approxEqAbs(f16, @sqrt(@as(f16, 3.6)), 1.897367, epsilon));
318-
try expect(@sqrt(@as(f16, 4.0)) == 2.0);
319-
try expect(math.approxEqAbs(f16, @sqrt(@as(f16, 7.539840)), 2.745877, epsilon));
320-
try expect(math.approxEqAbs(f16, @sqrt(@as(f16, 19.230934)), 4.385309, epsilon));
321-
try expect(@sqrt(@as(f16, 64.0)) == 8.0);
322-
try expect(math.approxEqAbs(f16, @sqrt(@as(f16, 64.1)), 8.006248, epsilon));
323-
try expect(math.approxEqAbs(f16, @sqrt(@as(f16, 8942.230469)), 94.563370, epsilon));
324-
325-
// special cases
326-
try expect(math.isPositiveInf(@sqrt(@as(f16, math.inf(f16)))));
327-
try expect(@sqrt(@as(f16, 0.0)) == 0.0);
328-
try expect(@sqrt(@as(f16, -0.0)) == -0.0);
329-
try expect(math.isNan(@sqrt(@as(f16, -1.0))));
330-
try expect(math.isNan(@sqrt(@as(f16, math.nan(f16)))));
331-
}
332-
333-
test "another, possibly redundant @sqrt test" {
334-
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
335-
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
336-
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
337-
if (no_x86_64_hardware_f16_support) return error.SkipZigTest;
338-
339-
try testSqrtLegacy(f64, 12.0);
340-
try comptime testSqrtLegacy(f64, 12.0);
341-
try testSqrtLegacy(f32, 13.0);
342-
try comptime testSqrtLegacy(f32, 13.0);
343-
try testSqrtLegacy(f16, 13.0);
344-
try comptime testSqrtLegacy(f16, 13.0);
345-
346-
// TODO: make this pass
347-
if (false) {
348-
const x = 14.0;
349-
const y = x * x;
350-
const z = @sqrt(y);
351-
try comptime expect(z == x);
352-
}
353-
}
354-
355-
fn testSqrtLegacy(comptime T: type, x: T) !void {
356-
try expect(@sqrt(x * x) == x);
357-
}
358-
359352
test "@sin f16" {
360353
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
361354
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO

0 commit comments

Comments
 (0)