x86_64: implement conversions between scalar floats and ints

Closes #22797
This commit is contained in:
Jacob Young 2025-02-08 05:56:15 -05:00 committed by Andrew Kelley
parent 138d30bb47
commit 4e4775d6bd
39 changed files with 6958 additions and 124 deletions

View File

@ -61,33 +61,43 @@ comptime {
_ = @import("compiler_rt/fixhfsi.zig"); _ = @import("compiler_rt/fixhfsi.zig");
_ = @import("compiler_rt/fixhfdi.zig"); _ = @import("compiler_rt/fixhfdi.zig");
_ = @import("compiler_rt/fixhfti.zig"); _ = @import("compiler_rt/fixhfti.zig");
_ = @import("compiler_rt/fixhfei.zig");
_ = @import("compiler_rt/fixsfsi.zig"); _ = @import("compiler_rt/fixsfsi.zig");
_ = @import("compiler_rt/fixsfdi.zig"); _ = @import("compiler_rt/fixsfdi.zig");
_ = @import("compiler_rt/fixsfti.zig"); _ = @import("compiler_rt/fixsfti.zig");
_ = @import("compiler_rt/fixsfei.zig");
_ = @import("compiler_rt/fixdfsi.zig"); _ = @import("compiler_rt/fixdfsi.zig");
_ = @import("compiler_rt/fixdfdi.zig"); _ = @import("compiler_rt/fixdfdi.zig");
_ = @import("compiler_rt/fixdfti.zig"); _ = @import("compiler_rt/fixdfti.zig");
_ = @import("compiler_rt/fixdfei.zig");
_ = @import("compiler_rt/fixtfsi.zig"); _ = @import("compiler_rt/fixtfsi.zig");
_ = @import("compiler_rt/fixtfdi.zig"); _ = @import("compiler_rt/fixtfdi.zig");
_ = @import("compiler_rt/fixtfti.zig"); _ = @import("compiler_rt/fixtfti.zig");
_ = @import("compiler_rt/fixtfei.zig");
_ = @import("compiler_rt/fixxfsi.zig"); _ = @import("compiler_rt/fixxfsi.zig");
_ = @import("compiler_rt/fixxfdi.zig"); _ = @import("compiler_rt/fixxfdi.zig");
_ = @import("compiler_rt/fixxfti.zig"); _ = @import("compiler_rt/fixxfti.zig");
_ = @import("compiler_rt/fixxfei.zig");
_ = @import("compiler_rt/fixunshfsi.zig"); _ = @import("compiler_rt/fixunshfsi.zig");
_ = @import("compiler_rt/fixunshfdi.zig"); _ = @import("compiler_rt/fixunshfdi.zig");
_ = @import("compiler_rt/fixunshfti.zig"); _ = @import("compiler_rt/fixunshfti.zig");
_ = @import("compiler_rt/fixunshfei.zig");
_ = @import("compiler_rt/fixunssfsi.zig"); _ = @import("compiler_rt/fixunssfsi.zig");
_ = @import("compiler_rt/fixunssfdi.zig"); _ = @import("compiler_rt/fixunssfdi.zig");
_ = @import("compiler_rt/fixunssfti.zig"); _ = @import("compiler_rt/fixunssfti.zig");
_ = @import("compiler_rt/fixunssfei.zig");
_ = @import("compiler_rt/fixunsdfsi.zig"); _ = @import("compiler_rt/fixunsdfsi.zig");
_ = @import("compiler_rt/fixunsdfdi.zig"); _ = @import("compiler_rt/fixunsdfdi.zig");
_ = @import("compiler_rt/fixunsdfti.zig"); _ = @import("compiler_rt/fixunsdfti.zig");
_ = @import("compiler_rt/fixunsdfei.zig");
_ = @import("compiler_rt/fixunstfsi.zig"); _ = @import("compiler_rt/fixunstfsi.zig");
_ = @import("compiler_rt/fixunstfdi.zig"); _ = @import("compiler_rt/fixunstfdi.zig");
_ = @import("compiler_rt/fixunstfti.zig"); _ = @import("compiler_rt/fixunstfti.zig");
_ = @import("compiler_rt/fixunstfei.zig");
_ = @import("compiler_rt/fixunsxfsi.zig"); _ = @import("compiler_rt/fixunsxfsi.zig");
_ = @import("compiler_rt/fixunsxfdi.zig"); _ = @import("compiler_rt/fixunsxfdi.zig");
_ = @import("compiler_rt/fixunsxfti.zig"); _ = @import("compiler_rt/fixunsxfti.zig");
_ = @import("compiler_rt/fixunsxfei.zig");
_ = @import("compiler_rt/float_from_int.zig"); _ = @import("compiler_rt/float_from_int.zig");
_ = @import("compiler_rt/floatsihf.zig"); _ = @import("compiler_rt/floatsihf.zig");
@ -105,21 +115,31 @@ comptime {
_ = @import("compiler_rt/floattidf.zig"); _ = @import("compiler_rt/floattidf.zig");
_ = @import("compiler_rt/floattitf.zig"); _ = @import("compiler_rt/floattitf.zig");
_ = @import("compiler_rt/floattixf.zig"); _ = @import("compiler_rt/floattixf.zig");
_ = @import("compiler_rt/floatundihf.zig"); _ = @import("compiler_rt/floateihf.zig");
_ = @import("compiler_rt/floatundisf.zig"); _ = @import("compiler_rt/floateisf.zig");
_ = @import("compiler_rt/floatundidf.zig"); _ = @import("compiler_rt/floateidf.zig");
_ = @import("compiler_rt/floatunditf.zig"); _ = @import("compiler_rt/floateitf.zig");
_ = @import("compiler_rt/floatundixf.zig"); _ = @import("compiler_rt/floateixf.zig");
_ = @import("compiler_rt/floatunsihf.zig"); _ = @import("compiler_rt/floatunsihf.zig");
_ = @import("compiler_rt/floatunsisf.zig"); _ = @import("compiler_rt/floatunsisf.zig");
_ = @import("compiler_rt/floatunsidf.zig"); _ = @import("compiler_rt/floatunsidf.zig");
_ = @import("compiler_rt/floatunsitf.zig"); _ = @import("compiler_rt/floatunsitf.zig");
_ = @import("compiler_rt/floatunsixf.zig"); _ = @import("compiler_rt/floatunsixf.zig");
_ = @import("compiler_rt/floatundihf.zig");
_ = @import("compiler_rt/floatundisf.zig");
_ = @import("compiler_rt/floatundidf.zig");
_ = @import("compiler_rt/floatunditf.zig");
_ = @import("compiler_rt/floatundixf.zig");
_ = @import("compiler_rt/floatuntihf.zig"); _ = @import("compiler_rt/floatuntihf.zig");
_ = @import("compiler_rt/floatuntisf.zig"); _ = @import("compiler_rt/floatuntisf.zig");
_ = @import("compiler_rt/floatuntidf.zig"); _ = @import("compiler_rt/floatuntidf.zig");
_ = @import("compiler_rt/floatuntitf.zig"); _ = @import("compiler_rt/floatuntitf.zig");
_ = @import("compiler_rt/floatuntixf.zig"); _ = @import("compiler_rt/floatuntixf.zig");
_ = @import("compiler_rt/floatuneihf.zig");
_ = @import("compiler_rt/floatuneisf.zig");
_ = @import("compiler_rt/floatuneidf.zig");
_ = @import("compiler_rt/floatuneitf.zig");
_ = @import("compiler_rt/floatuneixf.zig");
// comparison // comparison
_ = @import("compiler_rt/comparef.zig"); _ = @import("compiler_rt/comparef.zig");

View File

@ -9,7 +9,7 @@ const __divdc3 = @import("./divdc3.zig").__divdc3;
const __divxc3 = @import("./divxc3.zig").__divxc3; const __divxc3 = @import("./divxc3.zig").__divxc3;
const __divtc3 = @import("./divtc3.zig").__divtc3; const __divtc3 = @import("./divtc3.zig").__divtc3;
test { test "divc3" {
try testDiv(f16, __divhc3); try testDiv(f16, __divhc3);
try testDiv(f32, __divsc3); try testDiv(f32, __divsc3);
try testDiv(f64, __divdc3); try testDiv(f64, __divdc3);

View File

@ -0,0 +1,13 @@
const divCeil = @import("std").math.divCeil;
const common = @import("./common.zig");
const bigIntFromFloat = @import("./int_from_float.zig").bigIntFromFloat;
pub const panic = common.panic;
comptime {
@export(&__fixdfei, .{ .name = "__fixdfei", .linkage = common.linkage, .visibility = common.visibility });
}
pub fn __fixdfei(r: [*]u32, bits: usize, a: f64) callconv(.c) void {
return bigIntFromFloat(.signed, r[0 .. divCeil(usize, bits, 32) catch unreachable], a);
}

View File

@ -8,7 +8,10 @@ comptime {
if (common.want_windows_v2u64_abi) { if (common.want_windows_v2u64_abi) {
@export(&__fixdfti_windows_x86_64, .{ .name = "__fixdfti", .linkage = common.linkage, .visibility = common.visibility }); @export(&__fixdfti_windows_x86_64, .{ .name = "__fixdfti", .linkage = common.linkage, .visibility = common.visibility });
} else { } else {
@export(&__fixdfti, .{ .name = "__fixdfti", .linkage = common.linkage, .visibility = common.visibility }); @export(&__fixdfti, .{ .name = switch (builtin.cpu.arch) {
.hexagon => "__hexagon",
else => "_",
} ++ "_fixdfti", .linkage = common.linkage, .visibility = common.visibility });
} }
} }

View File

@ -0,0 +1,13 @@
const divCeil = @import("std").math.divCeil;
const common = @import("./common.zig");
const bigIntFromFloat = @import("./int_from_float.zig").bigIntFromFloat;
pub const panic = common.panic;
comptime {
@export(&__fixhfei, .{ .name = "__fixhfei", .linkage = common.linkage, .visibility = common.visibility });
}
pub fn __fixhfei(r: [*]u32, bits: usize, a: f16) callconv(.c) void {
return bigIntFromFloat(.signed, r[0 .. divCeil(usize, bits, 32) catch unreachable], a);
}

View File

@ -0,0 +1,13 @@
const divCeil = @import("std").math.divCeil;
const common = @import("./common.zig");
const bigIntFromFloat = @import("./int_from_float.zig").bigIntFromFloat;
pub const panic = common.panic;
comptime {
@export(&__fixsfei, .{ .name = "__fixsfei", .linkage = common.linkage, .visibility = common.visibility });
}
pub fn __fixsfei(r: [*]u32, bits: usize, a: f32) callconv(.c) void {
return bigIntFromFloat(.signed, r[0 .. divCeil(usize, bits, 32) catch unreachable], a);
}

View File

@ -8,7 +8,10 @@ comptime {
if (common.want_windows_v2u64_abi) { if (common.want_windows_v2u64_abi) {
@export(&__fixsfti_windows_x86_64, .{ .name = "__fixsfti", .linkage = common.linkage, .visibility = common.visibility }); @export(&__fixsfti_windows_x86_64, .{ .name = "__fixsfti", .linkage = common.linkage, .visibility = common.visibility });
} else { } else {
@export(&__fixsfti, .{ .name = "__fixsfti", .linkage = common.linkage, .visibility = common.visibility }); @export(&__fixsfti, .{ .name = switch (builtin.cpu.arch) {
.hexagon => "__hexagon",
else => "_",
} ++ "_fixsfti", .linkage = common.linkage, .visibility = common.visibility });
} }
} }

View File

@ -0,0 +1,13 @@
const divCeil = @import("std").math.divCeil;
const common = @import("./common.zig");
const bigIntFromFloat = @import("./int_from_float.zig").bigIntFromFloat;
pub const panic = common.panic;
comptime {
@export(&__fixtfei, .{ .name = "__fixtfei", .linkage = common.linkage, .visibility = common.visibility });
}
pub fn __fixtfei(r: [*]u32, bits: usize, a: f128) callconv(.c) void {
return bigIntFromFloat(.signed, r[0 .. divCeil(usize, bits, 32) catch unreachable], a);
}

View File

@ -0,0 +1,13 @@
const divCeil = @import("std").math.divCeil;
const common = @import("./common.zig");
const bigIntFromFloat = @import("./int_from_float.zig").bigIntFromFloat;
pub const panic = common.panic;
comptime {
@export(&__fixunsdfei, .{ .name = "__fixunsdfei", .linkage = common.linkage, .visibility = common.visibility });
}
pub fn __fixunsdfei(r: [*]u32, bits: usize, a: f64) callconv(.c) void {
return bigIntFromFloat(.unsigned, r[0 .. divCeil(usize, bits, 32) catch unreachable], a);
}

View File

@ -8,7 +8,10 @@ comptime {
if (common.want_windows_v2u64_abi) { if (common.want_windows_v2u64_abi) {
@export(&__fixunsdfti_windows_x86_64, .{ .name = "__fixunsdfti", .linkage = common.linkage, .visibility = common.visibility }); @export(&__fixunsdfti_windows_x86_64, .{ .name = "__fixunsdfti", .linkage = common.linkage, .visibility = common.visibility });
} else { } else {
@export(&__fixunsdfti, .{ .name = "__fixunsdfti", .linkage = common.linkage, .visibility = common.visibility }); @export(&__fixunsdfti, .{ .name = switch (builtin.cpu.arch) {
.hexagon => "__hexagon",
else => "_",
} ++ "_fixunsdfti", .linkage = common.linkage, .visibility = common.visibility });
} }
} }

View File

@ -0,0 +1,13 @@
const divCeil = @import("std").math.divCeil;
const common = @import("./common.zig");
const bigIntFromFloat = @import("./int_from_float.zig").bigIntFromFloat;
pub const panic = common.panic;
comptime {
@export(&__fixunshfei, .{ .name = "__fixunshfei", .linkage = common.linkage, .visibility = common.visibility });
}
pub fn __fixunshfei(r: [*]u32, bits: usize, a: f16) callconv(.c) void {
return bigIntFromFloat(.unsigned, r[0 .. divCeil(usize, bits, 32) catch unreachable], a);
}

View File

@ -0,0 +1,13 @@
const divCeil = @import("std").math.divCeil;
const common = @import("./common.zig");
const bigIntFromFloat = @import("./int_from_float.zig").bigIntFromFloat;
pub const panic = common.panic;
comptime {
@export(&__fixunssfei, .{ .name = "__fixunssfei", .linkage = common.linkage, .visibility = common.visibility });
}
pub fn __fixunssfei(r: [*]u32, bits: usize, a: f32) callconv(.c) void {
return bigIntFromFloat(.unsigned, r[0 .. divCeil(usize, bits, 32) catch unreachable], a);
}

View File

@ -8,7 +8,10 @@ comptime {
if (common.want_windows_v2u64_abi) { if (common.want_windows_v2u64_abi) {
@export(&__fixunssfti_windows_x86_64, .{ .name = "__fixunssfti", .linkage = common.linkage, .visibility = common.visibility }); @export(&__fixunssfti_windows_x86_64, .{ .name = "__fixunssfti", .linkage = common.linkage, .visibility = common.visibility });
} else { } else {
@export(&__fixunssfti, .{ .name = "__fixunssfti", .linkage = common.linkage, .visibility = common.visibility }); @export(&__fixunssfti, .{ .name = switch (builtin.cpu.arch) {
.hexagon => "__hexagon",
else => "_",
} ++ "_fixunssfti", .linkage = common.linkage, .visibility = common.visibility });
} }
} }

View File

@ -0,0 +1,13 @@
const divCeil = @import("std").math.divCeil;
const common = @import("./common.zig");
const bigIntFromFloat = @import("./int_from_float.zig").bigIntFromFloat;
pub const panic = common.panic;
comptime {
@export(&__fixunstfei, .{ .name = "__fixunstfei", .linkage = common.linkage, .visibility = common.visibility });
}
pub fn __fixunstfei(r: [*]u32, bits: usize, a: f128) callconv(.c) void {
return bigIntFromFloat(.unsigned, r[0 .. divCeil(usize, bits, 32) catch unreachable], a);
}

View File

@ -0,0 +1,13 @@
const divCeil = @import("std").math.divCeil;
const common = @import("./common.zig");
const bigIntFromFloat = @import("./int_from_float.zig").bigIntFromFloat;
pub const panic = common.panic;
comptime {
@export(&__fixunsxfei, .{ .name = "__fixunsxfei", .linkage = common.linkage, .visibility = common.visibility });
}
pub fn __fixunsxfei(r: [*]u32, bits: usize, a: f80) callconv(.c) void {
return bigIntFromFloat(.unsigned, r[0 .. divCeil(usize, bits, 32) catch unreachable], a);
}

View File

@ -0,0 +1,13 @@
const divCeil = @import("std").math.divCeil;
const common = @import("./common.zig");
const bigIntFromFloat = @import("./int_from_float.zig").bigIntFromFloat;
pub const panic = common.panic;
comptime {
@export(&__fixxfei, .{ .name = "__fixxfei", .linkage = common.linkage, .visibility = common.visibility });
}
pub fn __fixxfei(r: [*]u32, bits: usize, a: f80) callconv(.c) void {
return bigIntFromFloat(.signed, r[0 .. divCeil(usize, bits, 32) catch unreachable], a);
}

View File

@ -1,5 +1,6 @@
const Int = @import("std").meta.Int; const std = @import("std");
const math = @import("std").math; const Int = std.meta.Int;
const math = std.math;
pub fn floatFromInt(comptime T: type, x: anytype) T { pub fn floatFromInt(comptime T: type, x: anytype) T {
if (x == 0) return 0; if (x == 0) return 0;
@ -18,7 +19,7 @@ pub fn floatFromInt(comptime T: type, x: anytype) T {
const max_exp = exp_bias; const max_exp = exp_bias;
// Sign // Sign
const abs_val = if (@TypeOf(x) == comptime_int or @typeInfo(@TypeOf(x)).int.signedness == .signed) @abs(x) else x; const abs_val = @abs(x);
const sign_bit = if (x < 0) @as(uT, 1) << (float_bits - 1) else 0; const sign_bit = if (x < 0) @as(uT, 1) << (float_bits - 1) else 0;
var result: uT = sign_bit; var result: uT = sign_bit;
@ -53,6 +54,54 @@ pub fn floatFromInt(comptime T: type, x: anytype) T {
return @bitCast(sign_bit | result); return @bitCast(sign_bit | result);
} }
const endian = @import("builtin").cpu.arch.endian();
inline fn limb(limbs: []const u32, index: usize) u32 {
return switch (endian) {
.little => limbs[index],
.big => limbs[limbs.len - 1 - index],
};
}
pub inline fn floatFromBigInt(comptime T: type, comptime signedness: std.builtin.Signedness, x: []const u32) T {
switch (x.len) {
0 => return 0,
inline 1...4 => |limbs_len| return @floatFromInt(@as(
@Type(.{ .int = .{ .signedness = signedness, .bits = 32 * limbs_len } }),
@bitCast(x[0..limbs_len].*),
)),
else => {},
}
// sign implicit fraction round sticky
const I = comptime @Type(.{ .int = .{
.signedness = signedness,
.bits = @as(u16, @intFromBool(signedness == .signed)) + 1 + math.floatFractionalBits(T) + 1 + 1,
} });
const clrsb = clrsb: {
var clsb: usize = 0;
const sign_bits: u32 = switch (signedness) {
.signed => @bitCast(@as(i32, @bitCast(limb(x, x.len - 1))) >> 31),
.unsigned => 0,
};
for (0..x.len) |limb_index| {
const l = limb(x, x.len - 1 - limb_index) ^ sign_bits;
clsb += @clz(l);
if (l != 0) break;
}
break :clrsb clsb - @intFromBool(signedness == .signed);
};
const active_bits = 32 * x.len - clrsb;
const exponent = active_bits -| @bitSizeOf(I);
const exponent_limb = exponent / 32;
const sticky = for (0..exponent_limb) |limb_index| {
if (limb(x, limb_index) != 0) break true;
} else limb(x, exponent_limb) & ((@as(u32, 1) << @truncate(exponent)) - 1) != 0;
return math.ldexp(@as(T, @floatFromInt(
std.mem.readPackedIntNative(I, std.mem.sliceAsBytes(x), exponent) | @intFromBool(sticky),
)), @intCast(exponent));
}
test { test {
_ = @import("float_from_int_test.zig"); _ = @import("float_from_int_test.zig");
} }

View File

@ -1,6 +1,8 @@
const std = @import("std"); const std = @import("std");
const builtin = @import("builtin");
const testing = std.testing; const testing = std.testing;
const math = std.math; const math = std.math;
const endian = builtin.cpu.arch.endian();
const __floatunsihf = @import("floatunsihf.zig").__floatunsihf; const __floatunsihf = @import("floatunsihf.zig").__floatunsihf;
@ -11,6 +13,8 @@ const __floatdisf = @import("floatdisf.zig").__floatdisf;
const __floatundisf = @import("floatundisf.zig").__floatundisf; const __floatundisf = @import("floatundisf.zig").__floatundisf;
const __floattisf = @import("floattisf.zig").__floattisf; const __floattisf = @import("floattisf.zig").__floattisf;
const __floatuntisf = @import("floatuntisf.zig").__floatuntisf; const __floatuntisf = @import("floatuntisf.zig").__floatuntisf;
const __floateisf = @import("floateisf.zig").__floateisf;
const __floatuneisf = @import("floatuneisf.zig").__floatuneisf;
// Conversion to f64 // Conversion to f64
const __floatsidf = @import("floatsidf.zig").__floatsidf; const __floatsidf = @import("floatsidf.zig").__floatsidf;
@ -231,6 +235,54 @@ test "floatuntisf" {
try test__floatuntisf(math.maxInt(u128), @bitCast(math.inf(f32))); try test__floatuntisf(math.maxInt(u128), @bitCast(math.inf(f32)));
} }
fn test_floateisf(expected: u32, comptime T: type, a: T) !void {
const int = @typeInfo(T).int;
var a_buf: [@divExact(int.bits, 32)]u32 = undefined;
std.mem.writeInt(T, std.mem.asBytes(&a_buf), a, endian);
const r = switch (int.signedness) {
.signed => __floateisf,
.unsigned => __floatuneisf,
}(&a_buf, int.bits);
try testing.expect(expected == @as(u32, @bitCast(r)));
}
test "floateisf" {
try test_floateisf(0xFF000000, i256, -1 << 127);
try test_floateisf(0xFF000000, i256, -math.maxInt(u127));
try test_floateisf(0xDF012347, i256, -0x8123468100000000);
try test_floateisf(0xDF012347, i256, -0x8123468000000001);
try test_floateisf(0xDF012346, i256, -0x8123468000000000);
try test_floateisf(0xDF012346, i256, -0x8123458100000000);
try test_floateisf(0xDF012346, i256, -0x8123458000000001);
try test_floateisf(0xDF012346, i256, -0x8123458000000000);
try test_floateisf(0xDF012345, i256, -0x8123456789ABCDEF);
try test_floateisf(0xBF800000, i256, -1);
try test_floateisf(0x00000000, i256, 0);
try test_floateisf(0x5F012345, i256, 0x8123456789ABCDEF);
try test_floateisf(0x5F012346, i256, 0x8123458000000000);
try test_floateisf(0x5F012346, i256, 0x8123458000000001);
try test_floateisf(0x5F012346, i256, 0x8123458100000000);
try test_floateisf(0x5F012346, i256, 0x8123468000000000);
try test_floateisf(0x5F012347, i256, 0x8123468000000001);
try test_floateisf(0x5F012347, i256, 0x8123468100000000);
try test_floateisf(0x7F000000, i256, math.maxInt(u127));
try test_floateisf(0x7F000000, i256, 1 << 127);
}
test "floatuneisf" {
try test_floateisf(0x00000000, u256, 0);
try test_floateisf(0x5F012345, u256, 0x8123456789ABCDEF);
try test_floateisf(0x5F012346, u256, 0x8123458000000000);
try test_floateisf(0x5F012346, u256, 0x8123458000000001);
try test_floateisf(0x5F012346, u256, 0x8123458080000000);
try test_floateisf(0x5F012346, u256, 0x8123468000000000);
try test_floateisf(0x5F012347, u256, 0x8123468000000001);
try test_floateisf(0x5F012347, u256, 0x8123468080000000);
try test_floateisf(0x7F000000, u256, math.maxInt(u127));
try test_floateisf(0x7F000000, u256, 1 << 127);
try test_floateisf(0x7F800000, u256, math.maxInt(u256));
}
fn test_one_floatsidf(a: i32, expected: u64) !void { fn test_one_floatsidf(a: i32, expected: u64) !void {
const r = __floatsidf(a); const r = __floatsidf(a);
try std.testing.expect(@as(u64, @bitCast(r)) == expected); try std.testing.expect(@as(u64, @bitCast(r)) == expected);
@ -810,8 +862,6 @@ test "conversion to f32" {
} }
test "conversion to f80" { test "conversion to f80" {
if (std.debug.runtime_safety) return error.SkipZigTest;
const floatFromInt = @import("./float_from_int.zig").floatFromInt; const floatFromInt = @import("./float_from_int.zig").floatFromInt;
try testing.expect(floatFromInt(f80, @as(i80, -12)) == -12); try testing.expect(floatFromInt(f80, @as(i80, -12)) == -12);

View File

@ -0,0 +1,13 @@
const divCeil = @import("std").math.divCeil;
const common = @import("./common.zig");
const floatFromBigInt = @import("./float_from_int.zig").floatFromBigInt;
pub const panic = common.panic;
comptime {
@export(&__floateidf, .{ .name = "__floateidf", .linkage = common.linkage, .visibility = common.visibility });
}
pub fn __floateidf(a: [*]const u32, bits: usize) callconv(.c) f64 {
return floatFromBigInt(f64, .signed, a[0 .. divCeil(usize, bits, 32) catch unreachable]);
}

View File

@ -0,0 +1,13 @@
const divCeil = @import("std").math.divCeil;
const common = @import("./common.zig");
const floatFromBigInt = @import("./float_from_int.zig").floatFromBigInt;
pub const panic = common.panic;
comptime {
@export(&__floateihf, .{ .name = "__floateihf", .linkage = common.linkage, .visibility = common.visibility });
}
pub fn __floateihf(a: [*]const u32, bits: usize) callconv(.c) f16 {
return floatFromBigInt(f16, .signed, a[0 .. divCeil(usize, bits, 32) catch unreachable]);
}

View File

@ -0,0 +1,13 @@
const divCeil = @import("std").math.divCeil;
const common = @import("./common.zig");
const floatFromBigInt = @import("./float_from_int.zig").floatFromBigInt;
pub const panic = common.panic;
comptime {
@export(&__floateisf, .{ .name = "__floateisf", .linkage = common.linkage, .visibility = common.visibility });
}
pub fn __floateisf(a: [*]const u32, bits: usize) callconv(.c) f32 {
return floatFromBigInt(f32, .signed, a[0 .. divCeil(usize, bits, 32) catch unreachable]);
}

View File

@ -0,0 +1,13 @@
const divCeil = @import("std").math.divCeil;
const common = @import("./common.zig");
const floatFromBigInt = @import("./float_from_int.zig").floatFromBigInt;
pub const panic = common.panic;
comptime {
@export(&__floateitf, .{ .name = "__floateitf", .linkage = common.linkage, .visibility = common.visibility });
}
pub fn __floateitf(a: [*]const u32, bits: usize) callconv(.c) f128 {
return floatFromBigInt(f128, .signed, a[0 .. divCeil(usize, bits, 32) catch unreachable]);
}

View File

@ -0,0 +1,13 @@
const divCeil = @import("std").math.divCeil;
const common = @import("./common.zig");
const floatFromBigInt = @import("./float_from_int.zig").floatFromBigInt;
pub const panic = common.panic;
comptime {
@export(&__floateixf, .{ .name = "__floateixf", .linkage = common.linkage, .visibility = common.visibility });
}
pub fn __floateixf(a: [*]const u32, bits: usize) callconv(.c) f80 {
return floatFromBigInt(f80, .signed, a[0 .. divCeil(usize, bits, 32) catch unreachable]);
}

View File

@ -8,7 +8,10 @@ comptime {
if (common.want_windows_v2u64_abi) { if (common.want_windows_v2u64_abi) {
@export(&__floattidf_windows_x86_64, .{ .name = "__floattidf", .linkage = common.linkage, .visibility = common.visibility }); @export(&__floattidf_windows_x86_64, .{ .name = "__floattidf", .linkage = common.linkage, .visibility = common.visibility });
} else { } else {
@export(&__floattidf, .{ .name = "__floattidf", .linkage = common.linkage, .visibility = common.visibility }); @export(&__floattidf, .{ .name = switch (builtin.cpu.arch) {
.hexagon => "__hexagon",
else => "_",
} ++ "_floattidf", .linkage = common.linkage, .visibility = common.visibility });
} }
} }

View File

@ -8,7 +8,10 @@ comptime {
if (common.want_windows_v2u64_abi) { if (common.want_windows_v2u64_abi) {
@export(&__floattisf_windows_x86_64, .{ .name = "__floattisf", .linkage = common.linkage, .visibility = common.visibility }); @export(&__floattisf_windows_x86_64, .{ .name = "__floattisf", .linkage = common.linkage, .visibility = common.visibility });
} else { } else {
@export(&__floattisf, .{ .name = "__floattisf", .linkage = common.linkage, .visibility = common.visibility }); @export(&__floattisf, .{ .name = switch (builtin.cpu.arch) {
.hexagon => "__hexagon",
else => "_",
} ++ "_floattisf", .linkage = common.linkage, .visibility = common.visibility });
} }
} }

View File

@ -0,0 +1,13 @@
const divCeil = @import("std").math.divCeil;
const common = @import("./common.zig");
const floatFromBigInt = @import("./float_from_int.zig").floatFromBigInt;
pub const panic = common.panic;
comptime {
@export(&__floatuneidf, .{ .name = "__floatuneidf", .linkage = common.linkage, .visibility = common.visibility });
}
pub fn __floatuneidf(a: [*]const u32, bits: usize) callconv(.c) f64 {
return floatFromBigInt(f64, .unsigned, a[0 .. divCeil(usize, bits, 32) catch unreachable]);
}

View File

@ -0,0 +1,13 @@
const divCeil = @import("std").math.divCeil;
const common = @import("./common.zig");
const floatFromBigInt = @import("./float_from_int.zig").floatFromBigInt;
pub const panic = common.panic;
comptime {
@export(&__floatuneihf, .{ .name = "__floatuneihf", .linkage = common.linkage, .visibility = common.visibility });
}
pub fn __floatuneihf(a: [*]const u32, bits: usize) callconv(.c) f16 {
return floatFromBigInt(f16, .unsigned, a[0 .. divCeil(usize, bits, 32) catch unreachable]);
}

View File

@ -0,0 +1,13 @@
const divCeil = @import("std").math.divCeil;
const common = @import("./common.zig");
const floatFromBigInt = @import("./float_from_int.zig").floatFromBigInt;
pub const panic = common.panic;
comptime {
@export(&__floatuneisf, .{ .name = "__floatuneisf", .linkage = common.linkage, .visibility = common.visibility });
}
pub fn __floatuneisf(a: [*]const u32, bits: usize) callconv(.c) f32 {
return floatFromBigInt(f32, .unsigned, a[0 .. divCeil(usize, bits, 32) catch unreachable]);
}

View File

@ -0,0 +1,13 @@
const divCeil = @import("std").math.divCeil;
const common = @import("./common.zig");
const floatFromBigInt = @import("./float_from_int.zig").floatFromBigInt;
pub const panic = common.panic;
comptime {
@export(&__floatuneitf, .{ .name = "__floatuneitf", .linkage = common.linkage, .visibility = common.visibility });
}
pub fn __floatuneitf(a: [*]const u32, bits: usize) callconv(.c) f128 {
return floatFromBigInt(f128, .unsigned, a[0 .. divCeil(usize, bits, 32) catch unreachable]);
}

View File

@ -0,0 +1,13 @@
const divCeil = @import("std").math.divCeil;
const common = @import("./common.zig");
const floatFromBigInt = @import("./float_from_int.zig").floatFromBigInt;
pub const panic = common.panic;
comptime {
@export(&__floatuneixf, .{ .name = "__floatuneixf", .linkage = common.linkage, .visibility = common.visibility });
}
pub fn __floatuneixf(a: [*]const u32, bits: usize) callconv(.c) f80 {
return floatFromBigInt(f80, .unsigned, a[0 .. divCeil(usize, bits, 32) catch unreachable]);
}

View File

@ -1,5 +1,6 @@
const Int = @import("std").meta.Int; const std = @import("std");
const math = @import("std").math; const Int = std.meta.Int;
const math = std.math;
const Log2Int = math.Log2Int; const Log2Int = math.Log2Int;
pub inline fn intFromFloat(comptime I: type, a: anytype) I { pub inline fn intFromFloat(comptime I: type, a: anytype) I {
@ -50,6 +51,55 @@ pub inline fn intFromFloat(comptime I: type, a: anytype) I {
return result; return result;
} }
pub inline fn bigIntFromFloat(comptime signedness: std.builtin.Signedness, result: []u32, a: anytype) void {
switch (result.len) {
0 => return,
inline 1...4 => |limbs_len| {
result[0..limbs_len].* = @bitCast(@as(
@Type(.{ .int = .{ .signedness = signedness, .bits = 32 * limbs_len } }),
@intFromFloat(a),
));
return;
},
else => {},
}
// sign implicit fraction
const significand_bits = 1 + math.floatFractionalBits(@TypeOf(a));
const I = @Type(comptime .{ .int = .{
.signedness = signedness,
.bits = @as(u16, @intFromBool(signedness == .signed)) + significand_bits,
} });
const parts = math.frexp(a);
const exponent = @max(parts.exponent - significand_bits, 0);
const int: I = @intFromFloat(switch (exponent) {
0 => a,
else => math.ldexp(parts.significand, significand_bits),
});
switch (signedness) {
.signed => {
const endian = @import("builtin").cpu.arch.endian();
const exponent_limb = switch (endian) {
.little => exponent / 32,
.big => result.len - 1 - exponent / 32,
};
const sign_bits: u32 = if (int < 0) math.maxInt(u32) else 0;
@memset(result[0..exponent_limb], switch (endian) {
.little => 0,
.big => sign_bits,
});
result[exponent_limb] = sign_bits << @truncate(exponent);
@memset(result[exponent_limb + 1 ..], switch (endian) {
.little => sign_bits,
.big => 0,
});
},
.unsigned => @memset(result, 0),
}
std.mem.writePackedIntNative(I, std.mem.sliceAsBytes(result), exponent, int);
}
test { test {
_ = @import("int_from_float_test.zig"); _ = @import("int_from_float_test.zig");
} }

View File

@ -2,6 +2,7 @@ const std = @import("std");
const builtin = @import("builtin"); const builtin = @import("builtin");
const testing = std.testing; const testing = std.testing;
const math = std.math; const math = std.math;
const endian = builtin.cpu.arch.endian();
const __fixunshfti = @import("fixunshfti.zig").__fixunshfti; const __fixunshfti = @import("fixunshfti.zig").__fixunshfti;
const __fixunsxfti = @import("fixunsxfti.zig").__fixunsxfti; const __fixunsxfti = @import("fixunsxfti.zig").__fixunsxfti;
@ -13,6 +14,8 @@ const __fixsfdi = @import("fixsfdi.zig").__fixsfdi;
const __fixunssfdi = @import("fixunssfdi.zig").__fixunssfdi; const __fixunssfdi = @import("fixunssfdi.zig").__fixunssfdi;
const __fixsfti = @import("fixsfti.zig").__fixsfti; const __fixsfti = @import("fixsfti.zig").__fixsfti;
const __fixunssfti = @import("fixunssfti.zig").__fixunssfti; const __fixunssfti = @import("fixunssfti.zig").__fixunssfti;
const __fixsfei = @import("fixsfei.zig").__fixsfei;
const __fixunssfei = @import("fixunssfei.zig").__fixunssfei;
// Conversion from f64 // Conversion from f64
const __fixdfsi = @import("fixdfsi.zig").__fixdfsi; const __fixdfsi = @import("fixdfsi.zig").__fixdfsi;
@ -343,6 +346,41 @@ test "fixunssfti" {
try test__fixunssfti(math.inf(f32), math.maxInt(u128)); try test__fixunssfti(math.inf(f32), math.maxInt(u128));
} }
fn test_fixsfei(comptime T: type, expected: T, a: f32) !void {
const int = @typeInfo(T).int;
var expected_buf: [@divExact(int.bits, 32)]u32 = undefined;
std.mem.writeInt(T, std.mem.asBytes(&expected_buf), expected, endian);
var actual_buf: [@divExact(int.bits, 32)]u32 = undefined;
_ = switch (int.signedness) {
.signed => __fixsfei,
.unsigned => __fixunssfei,
}(&actual_buf, int.bits, a);
try testing.expect(std.mem.eql(u32, &expected_buf, &actual_buf));
}
test "fixsfei" {
try test_fixsfei(i256, -1 << 127, -0x1p127);
try test_fixsfei(i256, -1 << 100, -0x1p100);
try test_fixsfei(i256, -1 << 50, -0x1p50);
try test_fixsfei(i256, -1 << 1, -0x1p1);
try test_fixsfei(i256, -1 << 0, -0x1p0);
try test_fixsfei(i256, 0, 0);
try test_fixsfei(i256, 1 << 0, 0x1p0);
try test_fixsfei(i256, 1 << 1, 0x1p1);
try test_fixsfei(i256, 1 << 50, 0x1p50);
try test_fixsfei(i256, 1 << 100, 0x1p100);
try test_fixsfei(i256, 1 << 127, 0x1p127);
}
test "fixunsfei" {
try test_fixsfei(u256, 0, 0);
try test_fixsfei(u256, 1 << 0, 0x1p0);
try test_fixsfei(u256, 1 << 1, 0x1p1);
try test_fixsfei(u256, 1 << 50, 0x1p50);
try test_fixsfei(u256, 1 << 100, 0x1p100);
try test_fixsfei(u256, 1 << 127, 0x1p127);
}
fn test__fixdfsi(a: f64, expected: i32) !void { fn test__fixdfsi(a: f64, expected: i32) !void {
const x = __fixdfsi(a); const x = __fixdfsi(a);
try testing.expect(x == expected); try testing.expect(x == expected);

View File

@ -181,7 +181,7 @@ inline fn copyRange4(
dest[last..][0..copy_len].* = src[last..][0..copy_len].*; dest[last..][0..copy_len].* = src[last..][0..copy_len].*;
} }
test { test "memcpy" {
const S = struct { const S = struct {
fn testFunc(comptime copy_func: anytype) !void { fn testFunc(comptime copy_func: anytype) !void {
const max_len = 1024; const max_len = 1024;

View File

@ -9,7 +9,7 @@ const __muldc3 = @import("./muldc3.zig").__muldc3;
const __mulxc3 = @import("./mulxc3.zig").__mulxc3; const __mulxc3 = @import("./mulxc3.zig").__mulxc3;
const __multc3 = @import("./multc3.zig").__multc3; const __multc3 = @import("./multc3.zig").__multc3;
test { test "mulc3" {
try testMul(f16, __mulhc3); try testMul(f16, __mulhc3);
try testMul(f32, __mulsc3); try testMul(f32, __mulsc3);
try testMul(f64, __muldc3); try testMul(f64, __muldc3);

View File

@ -222,7 +222,7 @@ pub fn __tan(x_: f64, y_: f64, odd: bool) f64 {
r = y + z * (s * (r + v) + y) + s * T[0]; r = y + z * (s * (r + v) + y) + s * T[0];
w = x + r; w = x + r;
if (big) { if (big) {
s = 1 - 2 * @as(f64, @floatFromInt(@intFromBool(odd))); s = @floatFromInt(1 - 2 * @as(i3, @intFromBool(odd)));
v = s - 2.0 * (x + (r - w * w / (w + s))); v = s - 2.0 * (x + (r - w * w / (w + s)));
return if (sign) -v else v; return if (sign) -v else v;
} }

File diff suppressed because it is too large Load Diff

View File

@ -379,7 +379,7 @@ pub const Mnemonic = enum {
sqrtps, sqrtss, sqrtps, sqrtss,
stmxcsr, stmxcsr,
subps, subss, subps, subss,
ucomiss, ucomiss, unpckhps, unpcklps,
xorps, xorps,
// SSE2 // SSE2
addpd, addsd, addpd, addsd,
@ -409,7 +409,7 @@ pub const Mnemonic = enum {
shufpd, shufpd,
sqrtpd, sqrtsd, sqrtpd, sqrtsd,
subpd, subsd, subpd, subsd,
ucomisd, ucomisd, unpckhpd, unpcklpd,
xorpd, xorpd,
// SSE3 // SSE3
addsubpd, addsubps, haddpd, haddps, lddqu, movddup, movshdup, movsldup, addsubpd, addsubps, haddpd, haddps, lddqu, movddup, movshdup, movsldup,
@ -504,7 +504,7 @@ pub const Mnemonic = enum {
vstmxcsr, vstmxcsr,
vsubpd, vsubps, vsubsd, vsubss, vsubpd, vsubps, vsubsd, vsubss,
vtestpd, vtestps, vtestpd, vtestps,
vucomisd, vucomiss, vucomisd, vucomiss, vunpckhpd, vunpckhps, vunpcklpd, vunpcklps,
vxorpd, vxorps, vxorpd, vxorps,
// F16C // F16C
vcvtph2ps, vcvtps2ph, vcvtph2ps, vcvtps2ph,

View File

@ -1392,6 +1392,10 @@ pub const table = [_]Entry{
.{ .ucomiss, .rm, &.{ .xmm, .xmm_m32 }, &.{ 0x0f, 0x2e }, 0, .none, .sse }, .{ .ucomiss, .rm, &.{ .xmm, .xmm_m32 }, &.{ 0x0f, 0x2e }, 0, .none, .sse },
.{ .unpckhps, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x0f, 0x15 }, 0, .none, .sse },
.{ .unpcklps, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x0f, 0x14 }, 0, .none, .sse },
.{ .xorps, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x0f, 0x57 }, 0, .none, .sse }, .{ .xorps, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x0f, 0x57 }, 0, .none, .sse },
// SSE2 // SSE2
@ -1611,6 +1615,10 @@ pub const table = [_]Entry{
.{ .ucomisd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0x66, 0x0f, 0x2e }, 0, .none, .sse2 }, .{ .ucomisd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0x66, 0x0f, 0x2e }, 0, .none, .sse2 },
.{ .unpckhpd, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x15 }, 0, .none, .sse2 },
.{ .unpcklpd, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x14 }, 0, .none, .sse2 },
.{ .xorpd, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x57 }, 0, .none, .sse2 }, .{ .xorpd, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x57 }, 0, .none, .sse2 },
// SSE3 // SSE3
@ -2281,6 +2289,18 @@ pub const table = [_]Entry{
.{ .vucomiss, .rm, &.{ .xmm, .xmm_m32 }, &.{ 0x0f, 0x2e }, 0, .vex_lig_wig, .avx }, .{ .vucomiss, .rm, &.{ .xmm, .xmm_m32 }, &.{ 0x0f, 0x2e }, 0, .vex_lig_wig, .avx },
.{ .vunpckhpd, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x15 }, 0, .vex_128_wig, .avx },
.{ .vunpckhpd, .rvm, &.{ .ymm, .ymm, .ymm_m256 }, &.{ 0x66, 0x0f, 0x15 }, 0, .vex_256_wig, .avx },
.{ .vunpckhps, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x0f, 0x15 }, 0, .vex_128_wig, .avx },
.{ .vunpckhps, .rvm, &.{ .ymm, .ymm, .ymm_m256 }, &.{ 0x0f, 0x15 }, 0, .vex_256_wig, .avx },
.{ .vunpcklpd, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x14 }, 0, .vex_128_wig, .avx },
.{ .vunpcklpd, .rvm, &.{ .ymm, .ymm, .ymm_m256 }, &.{ 0x66, 0x0f, 0x14 }, 0, .vex_256_wig, .avx },
.{ .vunpcklps, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x0f, 0x14 }, 0, .vex_128_wig, .avx },
.{ .vunpcklps, .rvm, &.{ .ymm, .ymm, .ymm_m256 }, &.{ 0x0f, 0x14 }, 0, .vex_256_wig, .avx },
.{ .vxorpd, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x57 }, 0, .vex_128_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 }, .{ .vxorpd, .rvm, &.{ .ymm, .ymm, .ymm_m256 }, &.{ 0x66, 0x0f, 0x57 }, 0, .vex_256_wig, .avx },

File diff suppressed because it is too large Load Diff