From 917103710e6f2a6c5a28a3630e25f59a46e3cd21 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Wed, 8 May 2019 22:26:54 +0200 Subject: [PATCH] compiler-rt: Add __floatsidf & __floatsisf Also add their AEABI aliases, __aeabi_i2f & __aeabi_i2d --- CMakeLists.txt | 1 + std/special/compiler_rt.zig | 4 ++ std/special/compiler_rt/floatsiXf.zig | 90 +++++++++++++++++++++++++++ 3 files changed, 95 insertions(+) create mode 100644 std/special/compiler_rt/floatsiXf.zig diff --git a/CMakeLists.txt b/CMakeLists.txt index 9bffaa4ce8..cbcd498251 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -677,6 +677,7 @@ set(ZIG_STD_FILES "special/compiler_rt/fixunstfdi.zig" "special/compiler_rt/fixunstfsi.zig" "special/compiler_rt/fixunstfti.zig" + "special/compiler_rt/floatsiXf.zig" "special/compiler_rt/floattidf.zig" "special/compiler_rt/floattisf.zig" "special/compiler_rt/floattitf.zig" diff --git a/std/special/compiler_rt.zig b/std/special/compiler_rt.zig index 2faec8eab7..53c364e07e 100644 --- a/std/special/compiler_rt.zig +++ b/std/special/compiler_rt.zig @@ -64,6 +64,8 @@ comptime { @export("__divsf3", @import("compiler_rt/divsf3.zig").__divsf3, linkage); @export("__divdf3", @import("compiler_rt/divdf3.zig").__divdf3, linkage); + @export("__floatsidf", @import("compiler_rt/floatsiXf.zig").__floatsidf, linkage); + @export("__floatsisf", @import("compiler_rt/floatsiXf.zig").__floatsisf, linkage); @export("__floattitf", @import("compiler_rt/floattitf.zig").__floattitf, linkage); @export("__floattidf", @import("compiler_rt/floattidf.zig").__floattidf, linkage); @export("__floattisf", @import("compiler_rt/floattisf.zig").__floattisf, linkage); @@ -151,6 +153,7 @@ comptime { @export("__aeabi_memcmp4", __aeabi_memcmp, linkage); @export("__aeabi_memcmp8", __aeabi_memcmp, linkage); + @export("__aeabi_i2d", @import("compiler_rt/floatsiXf.zig").__floatsidf, linkage); @export("__aeabi_fneg", @import("compiler_rt/negXf2.zig").__negsf2, linkage); @export("__aeabi_dneg", @import("compiler_rt/negXf2.zig").__negdf2, linkage); @@ -170,6 +173,7 @@ comptime { @export("__aeabi_h2f", @import("compiler_rt/extendXfYf2.zig").__extendhfsf2, linkage); @export("__aeabi_f2h", @import("compiler_rt/truncXfYf2.zig").__truncsfhf2, linkage); + @export("__aeabi_i2f", @import("compiler_rt/floatsiXf.zig").__floatsisf, linkage); @export("__aeabi_fadd", @import("compiler_rt/addXf3.zig").__addsf3, linkage); @export("__aeabi_dadd", @import("compiler_rt/addXf3.zig").__adddf3, linkage); @export("__aeabi_fsub", @import("compiler_rt/addXf3.zig").__subsf3, linkage); diff --git a/std/special/compiler_rt/floatsiXf.zig b/std/special/compiler_rt/floatsiXf.zig new file mode 100644 index 0000000000..e96304b471 --- /dev/null +++ b/std/special/compiler_rt/floatsiXf.zig @@ -0,0 +1,90 @@ +const builtin = @import("builtin"); +const std = @import("std"); +const maxInt = std.math.maxInt; + +fn floatsiXf(comptime T: type, a: i32) T { + @setRuntimeSafety(builtin.is_test); + + const Z = @IntType(false, T.bit_count); + const S = @IntType(false, T.bit_count - @clz(Z(T.bit_count) - 1)); + + if (a == 0) { + return T(0.0); + } + + const significandBits = std.math.floatMantissaBits(T); + const exponentBits = std.math.floatExponentBits(T); + const exponentBias = ((1 << exponentBits - 1) - 1); + + const implicitBit = Z(1) << significandBits; + const signBit = Z(1 << Z.bit_count - 1); + + const sign = a >> 31; + // Take absolute value of a via abs(x) = (x^(x >> 31)) - (x >> 31). + const abs_a = (a ^ sign) -% sign; + // The exponent is the width of abs(a) + const exp = Z(31 - @clz(abs_a)); + + const sign_bit = if (sign < 0) signBit else 0; + + var mantissa: Z = undefined; + // Shift a into the significand field and clear the implicit bit. + if (exp <= significandBits) { + // No rounding needed + const shift = @intCast(S, significandBits - exp); + mantissa = @intCast(Z, @bitCast(u32, abs_a)) << shift ^ implicitBit; + } else { + const shift = @intCast(S, exp - significandBits); + // Round to the nearest number after truncation + mantissa = @intCast(Z, @bitCast(u32, abs_a)) >> shift ^ implicitBit; + // Align to the left and check if the truncated part is halfway over + const round = @bitCast(u32, abs_a) << @intCast(u5, 31 - shift); + mantissa += @boolToInt(round > 0x80000000); + // Tie to even + mantissa += mantissa & 1; + } + + // Use the addition instead of a or since we may have a carry from the + // mantissa to the exponent + var result = mantissa; + result += (exp + exponentBias) << significandBits; + result += sign_bit; + + return @bitCast(T, result); +} + +pub extern fn __floatsisf(arg: i32) f32 { + @setRuntimeSafety(builtin.is_test); + return @inlineCall(floatsiXf, f32, arg); +} + +pub extern fn __floatsidf(arg: i32) f64 { + @setRuntimeSafety(builtin.is_test); + return @inlineCall(floatsiXf, f64, arg); +} + +fn test_one_floatsidf(a: i32, expected: u64) void { + const r = __floatsidf(a); + std.testing.expect(@bitCast(u64, r) == expected); +} + +fn test_one_floatsisf(a: i32, expected: u32) void { + const r = __floatsisf(a); + std.testing.expect(@bitCast(u32, r) == expected); +} + +test "floatsidf" { + test_one_floatsidf(0, 0x0000000000000000); + test_one_floatsidf(1, 0x3ff0000000000000); + test_one_floatsidf(-1, 0xbff0000000000000); + test_one_floatsidf(0x7FFFFFFF, 0x41dfffffffc00000); + test_one_floatsidf(@bitCast(i32, @intCast(u32, 0x80000000)), 0xc1e0000000000000); +} + +test "floatsisf" { + test_one_floatsisf(0, 0x00000000); + test_one_floatsisf(1, 0x3f800000); + test_one_floatsisf(-1, 0xbf800000); + test_one_floatsisf(0x7FFFFFFF, 0x4f000000); + test_one_floatsisf(@bitCast(i32, @intCast(u32, 0x80000000)), 0xcf000000); +}