diff --git a/lib/std/special/compiler_rt.zig b/lib/std/special/compiler_rt.zig index 01c3a20389..2716de8113 100644 --- a/lib/std/special/compiler_rt.zig +++ b/lib/std/special/compiler_rt.zig @@ -92,6 +92,7 @@ comptime { @export(@import("compiler_rt/floatunsidf.zig").__floatunsidf, .{ .name = "__floatunsidf", .linkage = linkage }); @export(@import("compiler_rt/floatundidf.zig").__floatundidf, .{ .name = "__floatundidf", .linkage = linkage }); + @export(@import("compiler_rt/floatditf.zig").__floatditf, .{ .name = "__floatditf", .linkage = linkage }); @export(@import("compiler_rt/floattitf.zig").__floattitf, .{ .name = "__floattitf", .linkage = linkage }); @export(@import("compiler_rt/floattidf.zig").__floattidf, .{ .name = "__floattidf", .linkage = linkage }); @export(@import("compiler_rt/floattisf.zig").__floattisf, .{ .name = "__floattisf", .linkage = linkage }); diff --git a/lib/std/special/compiler_rt/floatditf.zig b/lib/std/special/compiler_rt/floatditf.zig new file mode 100644 index 0000000000..35264f27e9 --- /dev/null +++ b/lib/std/special/compiler_rt/floatditf.zig @@ -0,0 +1,38 @@ +const builtin = @import("builtin"); +const is_test = builtin.is_test; +const std = @import("std"); +const maxInt = std.math.maxInt; + +const significandBits = 112; +const exponentBias = 16383; +const implicitBit = (@as(u128, 1) << significandBits); + +pub fn __floatditf(arg: i64) callconv(.C) f128 { + @setRuntimeSafety(is_test); + + if (arg == 0) + return 0.0; + + // All other cases begin by extracting the sign and absolute value of a + var sign: u128 = 0; + var aAbs = @bitCast(u64, arg); + if (arg < 0) { + sign = 1 << 127; + aAbs = ~@bitCast(u64, arg)+ 1; + } + + // Exponent of (fp_t)a is the width of abs(a). + const exponent = 63 - @clz(u64, aAbs); + var result: u128 = undefined; + + // Shift a into the significand field, rounding if it is a right-shift + const shift = significandBits - exponent; + result = @as(u128, aAbs) << shift ^ implicitBit; + + result += (@as(u128, exponent) + exponentBias) << significandBits; + return @bitCast(f128, result | sign); +} + +test "import floatditf" { + _ = @import("floatditf_test.zig"); +} diff --git a/lib/std/special/compiler_rt/floatditf_test.zig b/lib/std/special/compiler_rt/floatditf_test.zig new file mode 100644 index 0000000000..8cdb8157a9 --- /dev/null +++ b/lib/std/special/compiler_rt/floatditf_test.zig @@ -0,0 +1,26 @@ +const __floatditf = @import("floatditf.zig").__floatditf; +const testing = @import("std").testing; + +fn test__floatditf(a: i64, expected: f128) void { + const x = __floatditf(a); + testing.expect(x == expected); +} + +test "floatditf" { + test__floatditf(0x7fffffffffffffff, make_ti(0x403dffffffffffff, 0xfffc000000000000)); + test__floatditf(0x123456789abcdef1, make_ti(0x403b23456789abcd, 0xef10000000000000)); + test__floatditf(0x2, make_ti(0x4000000000000000, 0x0)); + test__floatditf(0x1, make_ti(0x3fff000000000000, 0x0)); + test__floatditf(0x0, make_ti(0x0, 0x0)); + test__floatditf(@bitCast(i64, @as(u64, 0xffffffffffffffff)), make_ti(0xbfff000000000000, 0x0)); + test__floatditf(@bitCast(i64, @as(u64, 0xfffffffffffffffe)), make_ti(0xc000000000000000, 0x0)); + test__floatditf(-0x123456789abcdef1, make_ti(0xc03b23456789abcd, 0xef10000000000000)); + test__floatditf(@bitCast(i64, @as(u64, 0x8000000000000000)), make_ti(0xc03e000000000000, 0x0)); +} + +fn make_ti(high: u64, low: u64) f128 { + var result: u128 = high; + result <<= 64; + result |= low; + return @bitCast(f128, result); +} diff --git a/src-self-hosted/value.zig b/src-self-hosted/value.zig index eff7c95be7..e71805dc5b 100644 --- a/src-self-hosted/value.zig +++ b/src-self-hosted/value.zig @@ -586,8 +586,7 @@ pub const Value = extern union { .zero => 0, .int_u64 => @intToFloat(T, self.cast(Payload.Int_u64).?.int), - // .int_i64 => @intToFloat(f128, self.cast(Payload.Int_i64).?.int), - .int_i64 => @panic("TODO lld: error: undefined symbol: __floatditf"), + .int_i64 => @intToFloat(T, self.cast(Payload.Int_i64).?.int), .int_big_positive, .int_big_negative => @panic("big int to f128"), else => unreachable,