| author | |
| committer | |
| log | e3a63b4e5abd501d58a2fc574b827f3250c14461 |
| tree | 114c2e109f4ca83e2867af9bcab375430a8d433d |
| parent | d3d77138ecd692a045c478d804d188b3d88c14d5 |
3 files changed, 144 insertions(+), 0 deletions(-)
lib/std/special/compiler_rt.zig+5| ... | ... | @@ -75,6 +75,9 @@ comptime { |
| 75 | 75 | @export("__floatsisf", @import("compiler_rt/floatsiXf.zig").__floatsisf, linkage); |
| 76 | 76 | @export("__floatdidf", @import("compiler_rt/floatdidf.zig").__floatdidf, linkage); |
| 77 | 77 | @export("__floatsitf", @import("compiler_rt/floatsiXf.zig").__floatsitf, linkage); |
| 78 | ||
| 79 | @export("__floatunsisf", @import("compiler_rt/floatunsisf.zig").__floatunsisf, linkage); | |
| 80 | @export("__floatundisf", @import("compiler_rt/floatundisf.zig").__floatundisf, linkage); | |
| 78 | 81 | @export("__floatunsidf", @import("compiler_rt/floatunsidf.zig").__floatunsidf, linkage); |
| 79 | 82 | @export("__floatundidf", @import("compiler_rt/floatundidf.zig").__floatundidf, linkage); |
| 80 | 83 | |
| ... | ... | @@ -183,6 +186,8 @@ comptime { |
| 183 | 186 | @export("__aeabi_l2d", @import("compiler_rt/floatdidf.zig").__floatdidf, linkage); |
| 184 | 187 | @export("__aeabi_ui2d", @import("compiler_rt/floatunsidf.zig").__floatunsidf, linkage); |
| 185 | 188 | @export("__aeabi_ul2d", @import("compiler_rt/floatundidf.zig").__floatundidf, linkage); |
| 189 | @export("__aeabi_ui2f", @import("compiler_rt/floatunsisf.zig").__floatunsisf, linkage); | |
| 190 | @export("__aeabi_ul2f", @import("compiler_rt/floatundisf.zig").__floatundisf, linkage); | |
| 186 | 191 | |
| 187 | 192 | @export("__aeabi_fneg", @import("compiler_rt/negXf2.zig").__negsf2, linkage); |
| 188 | 193 | @export("__aeabi_dneg", @import("compiler_rt/negXf2.zig").__negdf2, linkage); |
lib/std/special/compiler_rt/floatundisf.zig created+86| ... | ... | @@ -0,0 +1,86 @@ |
| 1 | const builtin = @import("builtin"); | |
| 2 | const std = @import("std"); | |
| 3 | const maxInt = std.math.maxInt; | |
| 4 | ||
| 5 | const FLT_MANT_DIG = 24; | |
| 6 | ||
| 7 | pub extern fn __floatundisf(arg: u64) f32 { | |
| 8 | @setRuntimeSafety(builtin.is_test); | |
| 9 | ||
| 10 | if (arg == 0) return 0; | |
| 11 | ||
| 12 | var a = arg; | |
| 13 | const N: usize = @TypeOf(a).bit_count; | |
| 14 | // Number of significant digits | |
| 15 | const sd = N - @clz(u64, a); | |
| 16 | // 8 exponent | |
| 17 | var e = @intCast(u32, sd) - 1; | |
| 18 | ||
| 19 | if (sd > FLT_MANT_DIG) { | |
| 20 | // start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx | |
| 21 | // finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR | |
| 22 | // 12345678901234567890123456 | |
| 23 | // 1 = msb 1 bit | |
| 24 | // P = bit FLT_MANT_DIG-1 bits to the right of 1 | |
| 25 | // Q = bit FLT_MANT_DIG bits to the right of 1 | |
| 26 | // R = "or" of all bits to the right of Q | |
| 27 | switch (sd) { | |
| 28 | FLT_MANT_DIG + 1 => a <<= 1, | |
| 29 | FLT_MANT_DIG + 2 => {}, | |
| 30 | else => { | |
| 31 | const shift_amt = @intCast(u6, ((N + FLT_MANT_DIG + 2) - sd)); | |
| 32 | const all_ones: u64 = maxInt(u64); | |
| 33 | a = (a >> @intCast(u6, sd - (FLT_MANT_DIG + 2))) | | |
| 34 | @boolToInt(a & (all_ones >> shift_amt) != 0); | |
| 35 | }, | |
| 36 | } | |
| 37 | // Or P into R | |
| 38 | a |= @boolToInt((a & 4) != 0); | |
| 39 | // round - this step may add a significant bit | |
| 40 | a += 1; | |
| 41 | // dump Q and R | |
| 42 | a >>= 2; | |
| 43 | // a is now rounded to FLT_MANT_DIG or FLT_MANT_DIG+1 bits | |
| 44 | if ((a & (@as(u64, 1) << FLT_MANT_DIG)) != 0) { | |
| 45 | a >>= 1; | |
| 46 | e += 1; | |
| 47 | } | |
| 48 | // a is now rounded to FLT_MANT_DIG bits | |
| 49 | } else { | |
| 50 | a <<= @intCast(u6, FLT_MANT_DIG - sd); | |
| 51 | // a is now rounded to FLT_MANT_DIG bits | |
| 52 | } | |
| 53 | ||
| 54 | const result: u32 = ((e + 127) << 23) | // exponent | |
| 55 | @truncate(u32, a & 0x007FFFFF); // mantissa | |
| 56 | return @bitCast(f32, result); | |
| 57 | } | |
| 58 | ||
| 59 | fn test__floatundisf(a: u64, expected: f32) void { | |
| 60 | std.testing.expectEqual(expected, __floatundisf(a)); | |
| 61 | } | |
| 62 | ||
| 63 | test "floatundisf" { | |
| 64 | test__floatundisf(0, 0.0); | |
| 65 | test__floatundisf(1, 1.0); | |
| 66 | test__floatundisf(2, 2.0); | |
| 67 | test__floatundisf(0x7FFFFF8000000000, 0x1.FFFFFEp+62F); | |
| 68 | test__floatundisf(0x7FFFFF0000000000, 0x1.FFFFFCp+62F); | |
| 69 | test__floatundisf(0x8000008000000000, 0x1p+63F); | |
| 70 | test__floatundisf(0x8000010000000000, 0x1.000002p+63F); | |
| 71 | test__floatundisf(0x8000000000000000, 0x1p+63F); | |
| 72 | test__floatundisf(0x8000000000000001, 0x1p+63F); | |
| 73 | test__floatundisf(0xFFFFFFFFFFFFFFFE, 0x1p+64F); | |
| 74 | test__floatundisf(0xFFFFFFFFFFFFFFFF, 0x1p+64F); | |
| 75 | test__floatundisf(0x0007FB72E8000000, 0x1.FEDCBAp+50F); | |
| 76 | test__floatundisf(0x0007FB72EA000000, 0x1.FEDCBAp+50F); | |
| 77 | test__floatundisf(0x0007FB72EB000000, 0x1.FEDCBAp+50F); | |
| 78 | test__floatundisf(0x0007FB72EBFFFFFF, 0x1.FEDCBAp+50F); | |
| 79 | test__floatundisf(0x0007FB72EC000000, 0x1.FEDCBCp+50F); | |
| 80 | test__floatundisf(0x0007FB72E8000001, 0x1.FEDCBAp+50F); | |
| 81 | test__floatundisf(0x0007FB72E6000000, 0x1.FEDCBAp+50F); | |
| 82 | test__floatundisf(0x0007FB72E7000000, 0x1.FEDCBAp+50F); | |
| 83 | test__floatundisf(0x0007FB72E7FFFFFF, 0x1.FEDCBAp+50F); | |
| 84 | test__floatundisf(0x0007FB72E4000001, 0x1.FEDCBAp+50F); | |
| 85 | test__floatundisf(0x0007FB72E4000000, 0x1.FEDCB8p+50F); | |
| 86 | } |
lib/std/special/compiler_rt/floatunsisf.zig created+53| ... | ... | @@ -0,0 +1,53 @@ |
| 1 | const builtin = @import("builtin"); | |
| 2 | const std = @import("std"); | |
| 3 | const maxInt = std.math.maxInt; | |
| 4 | ||
| 5 | const significandBits = 23; | |
| 6 | const exponentBias = 127; | |
| 7 | const implicitBit = @as(u32, 1) << significandBits; | |
| 8 | ||
| 9 | pub extern fn __floatunsisf(arg: u32) f32 { | |
| 10 | @setRuntimeSafety(builtin.is_test); | |
| 11 | ||
| 12 | if (arg == 0) return 0.0; | |
| 13 | ||
| 14 | // The exponent is the width of abs(a) | |
| 15 | const exp = @as(u32, 31) - @clz(u32, arg); | |
| 16 | ||
| 17 | var mantissa: u32 = undefined; | |
| 18 | if (exp <= significandBits) { | |
| 19 | // Shift a into the significand field and clear the implicit bit | |
| 20 | const shift = @intCast(u5, significandBits - exp); | |
| 21 | mantissa = @as(u32, arg) << shift ^ implicitBit; | |
| 22 | } else { | |
| 23 | const shift = @intCast(u5, exp - significandBits); | |
| 24 | // Round to the nearest number after truncation | |
| 25 | mantissa = @as(u32, arg) >> shift ^ implicitBit; | |
| 26 | // Align to the left and check if the truncated part is halfway over | |
| 27 | const round = arg << @intCast(u5, 31 - shift); | |
| 28 | mantissa += @boolToInt(round > 0x80000000); | |
| 29 | // Tie to even | |
| 30 | mantissa += mantissa & 1; | |
| 31 | } | |
| 32 | ||
| 33 | // Use the addition instead of a or since we may have a carry from the | |
| 34 | // mantissa to the exponent | |
| 35 | var result = mantissa; | |
| 36 | result += (exp + exponentBias) << significandBits; | |
| 37 | ||
| 38 | return @bitCast(f32, result); | |
| 39 | } | |
| 40 | ||
| 41 | fn test_one_floatunsisf(a: u32, expected: u32) void { | |
| 42 | const r = __floatunsisf(a); | |
| 43 | std.testing.expect(@bitCast(u32, r) == expected); | |
| 44 | } | |
| 45 | ||
| 46 | test "floatunsisf" { | |
| 47 | // Test the produced bit pattern | |
| 48 | test_one_floatunsisf(0, 0); | |
| 49 | test_one_floatunsisf(1, 0x3f800000); | |
| 50 | test_one_floatunsisf(0x7FFFFFFF, 0x4f000000); | |
| 51 | test_one_floatunsisf(0x80000000, 0x4f000000); | |
| 52 | test_one_floatunsisf(0xFFFFFFFF, 0x4f800000); | |
| 53 | } |