zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

commit 61ebfe6603c8fef26008683f96b62dab2c502429 (tree)
parent c32b2e45efb0d0ced14c76d5221b2db636e40246
Author: Marc Tiehuis <marctiehuis@gmail.com>
Date:   Thu, 28 Jun 2018 21:12:47 +1200

compiler_rt: Add floatunditf and floatunsitf

Diffstat:
Astd/special/compiler_rt/floatunditf.zig | 28++++++++++++++++++++++++++++
Astd/special/compiler_rt/floatunditf_test.zig | 33+++++++++++++++++++++++++++++++++
Astd/special/compiler_rt/floatunsitf.zig | 29+++++++++++++++++++++++++++++
Astd/special/compiler_rt/floatunsitf_test.zig | 29+++++++++++++++++++++++++++++
Mstd/special/compiler_rt/truncXfYf2.zig | 4++--
5 files changed, 121 insertions(+), 2 deletions(-)

diff --git a/std/special/compiler_rt/floatunditf.zig b/std/special/compiler_rt/floatunditf.zig @@ -0,0 +1,28 @@ +const builtin = @import("builtin"); +const is_test = builtin.is_test; +const std = @import("../../index.zig"); + +pub extern fn __floatunditf(a: u128) f128 { + @setRuntimeSafety(is_test); + + if (a == 0) { + return 0; + } + + const mantissa_bits = std.math.floatMantissaBits(f128); + const exponent_bits = std.math.floatExponentBits(f128); + const exponent_bias = (1 << (exponent_bits - 1)) - 1; + const implicit_bit = 1 << mantissa_bits; + + const exp = (u128.bit_count - 1) - @clz(a); + const shift = mantissa_bits - @intCast(u7, exp); + + var result: u128 = (a << shift) ^ implicit_bit; + result += (@intCast(u128, exp) + exponent_bias) << mantissa_bits; + + return @bitCast(f128, result); +} + +test "import floatunditf" { + _ = @import("floatunditf_test.zig"); +} diff --git a/std/special/compiler_rt/floatunditf_test.zig b/std/special/compiler_rt/floatunditf_test.zig @@ -0,0 +1,33 @@ +const __floatunditf = @import("floatunditf.zig").__floatunditf; +const assert = @import("std").debug.assert; + +fn test__floatunditf(a: u128, expected_hi: u64, expected_lo: u64) void { + const x = __floatunditf(a); + + const x_repr = @bitCast(u128, x); + const x_hi = @intCast(u64, x_repr >> 64); + const x_lo = @truncate(u64, x_repr); + + if (x_hi == expected_hi and x_lo == expected_lo) { + return; + } + // nan repr + else if (expected_hi == 0x7fff800000000000 and expected_lo == 0x0) { + if ((x_hi & 0x7fff000000000000) == 0x7fff000000000000 and ((x_hi & 0xffffffffffff) > 0 or x_lo > 0)) { + return; + } + } + + @panic("__floatunditf test failure"); +} + +test "floatunditf" { + test__floatunditf(0xffffffffffffffff, 0x403effffffffffff, 0xfffe000000000000); + test__floatunditf(0xfffffffffffffffe, 0x403effffffffffff, 0xfffc000000000000); + test__floatunditf(0x8000000000000000, 0x403e000000000000, 0x0); + test__floatunditf(0x7fffffffffffffff, 0x403dffffffffffff, 0xfffc000000000000); + test__floatunditf(0x123456789abcdef1, 0x403b23456789abcd, 0xef10000000000000); + test__floatunditf(0x2, 0x4000000000000000, 0x0); + test__floatunditf(0x1, 0x3fff000000000000, 0x0); + test__floatunditf(0x0, 0x0, 0x0); +} diff --git a/std/special/compiler_rt/floatunsitf.zig b/std/special/compiler_rt/floatunsitf.zig @@ -0,0 +1,29 @@ +const builtin = @import("builtin"); +const is_test = builtin.is_test; +const std = @import("../../index.zig"); + +pub extern fn __floatunsitf(a: u64) f128 { + @setRuntimeSafety(is_test); + + if (a == 0) { + return 0; + } + + const mantissa_bits = std.math.floatMantissaBits(f128); + const exponent_bits = std.math.floatExponentBits(f128); + const exponent_bias = (1 << (exponent_bits - 1)) - 1; + const implicit_bit = 1 << mantissa_bits; + + const exp = (u64.bit_count - 1) - @clz(a); + const shift = mantissa_bits - @intCast(u7, exp); + + // TODO: @bitCast alignment error + var result align(16) = (@intCast(u128, a) << shift) ^ implicit_bit; + result += (@intCast(u128, exp) + exponent_bias) << mantissa_bits; + + return @bitCast(f128, result); +} + +test "import floatunsitf" { + _ = @import("floatunsitf_test.zig"); +} diff --git a/std/special/compiler_rt/floatunsitf_test.zig b/std/special/compiler_rt/floatunsitf_test.zig @@ -0,0 +1,29 @@ +const __floatunsitf = @import("floatunsitf.zig").__floatunsitf; +const assert = @import("std").debug.assert; + +fn test__floatunsitf(a: u64, expected_hi: u64, expected_lo: u64) void { + const x = __floatunsitf(a); + + const x_repr = @bitCast(u128, x); + const x_hi = @intCast(u64, x_repr >> 64); + const x_lo = @truncate(u64, x_repr); + + if (x_hi == expected_hi and x_lo == expected_lo) { + return; + } + // nan repr + else if (expected_hi == 0x7fff800000000000 and expected_lo == 0x0) { + if ((x_hi & 0x7fff000000000000) == 0x7fff000000000000 and ((x_hi & 0xffffffffffff) > 0 or x_lo > 0)) { + return; + } + } + + @panic("__floatunsitf test failure"); +} + +test "floatunsitf" { + test__floatunsitf(0x7fffffff, 0x401dfffffffc0000, 0x0); + test__floatunsitf(0, 0x0, 0x0); + test__floatunsitf(0xffffffff, 0x401efffffffe0000, 0x0); + test__floatunsitf(0x12345678, 0x401b234567800000, 0x0); +} diff --git a/std/special/compiler_rt/truncXfYf2.zig b/std/special/compiler_rt/truncXfYf2.zig @@ -85,8 +85,8 @@ inline fn truncXfYf2(comptime dst_t: type, comptime src_t: type, a: src_t) dst_t // a underflows on conversion to the destination type or is an exact // zero. The result may be a denormal or zero. Extract the exponent // to get the shift amount for the denormalization. - const aExp = aAbs >> srcSigBits; - const shift = srcExpBias - dstExpBias - aExp + 1; + const aExp = @intCast(u32, aAbs >> srcSigBits); + const shift = @intCast(u32, srcExpBias - dstExpBias - aExp + 1); const significand: src_rep_t = (aRep & srcSignificandMask) | srcMinNormal;