authorgravatar for topolarity@tapscott.meCody Tapscott <topolarity@tapscott.me> 2022-10-09 13:42:39-07:00
committergravatar for topolarity@tapscott.meCody Tapscott <topolarity@tapscott.me> 2022-10-09 13:42:39-07:00
logc9ecf7b920f1e5b7aa2366e83f722de46813ace3
tree86586779a6be2ee831181859c19bfcd31ea18002
parent05915b85dd3c00c40bf6645e0f09157be04dc829

compiler_rt: Fix `extendf_f80` bug

Zig should probably perform this cast automatically (w/ safety). Integer shifts are a real pain otherwise. Adds some test coverage, too.

3 files changed, 52 insertions(+), 2 deletions(-)

lib/compiler_rt/extenddfxf2.zig+1-1
...@@ -7,6 +7,6 @@ comptime {...@@ -7,6 +7,6 @@ comptime {
7 @export(__extenddfxf2, .{ .name = "__extenddfxf2", .linkage = common.linkage });7 @export(__extenddfxf2, .{ .name = "__extenddfxf2", .linkage = common.linkage });
8}8}
99
10fn __extenddfxf2(a: f64) callconv(.C) f80 {10pub fn __extenddfxf2(a: f64) callconv(.C) f80 {
11 return extend_f80(f64, @bitCast(u64, a));11 return extend_f80(f64, @bitCast(u64, a));
12}12}
lib/compiler_rt/extendf.zig+3-1
...@@ -92,6 +92,8 @@ pub inline fn extend_f80(comptime src_t: type, a: std.meta.Int(.unsigned, @typeI...@@ -92,6 +92,8 @@ pub inline fn extend_f80(comptime src_t: type, a: std.meta.Int(.unsigned, @typeI
92 const src_qnan = 1 << (src_sig_bits - 1);92 const src_qnan = 1 << (src_sig_bits - 1);
93 const src_nan_code = src_qnan - 1;93 const src_nan_code = src_qnan - 1;
9494
95 const SrcShift = std.math.Log2Int(src_rep_t);
96
95 var dst: std.math.F80 = undefined;97 var dst: std.math.F80 = undefined;
9698
97 // Break a into a sign and representation of the absolute value99 // Break a into a sign and representation of the absolute value
...@@ -124,7 +126,7 @@ pub inline fn extend_f80(comptime src_t: type, a: std.meta.Int(.unsigned, @typeI...@@ -124,7 +126,7 @@ pub inline fn extend_f80(comptime src_t: type, a: std.meta.Int(.unsigned, @typeI
124126
125 dst.fraction = @as(u64, a_abs) << @intCast(u6, dst_sig_bits - src_sig_bits + scale);127 dst.fraction = @as(u64, a_abs) << @intCast(u6, dst_sig_bits - src_sig_bits + scale);
126 dst.fraction |= dst_int_bit; // bit 64 is always set for normal numbers128 dst.fraction |= dst_int_bit; // bit 64 is always set for normal numbers
127 dst.exp = @truncate(u16, a_abs >> @intCast(u4, src_sig_bits - scale));129 dst.exp = @truncate(u16, a_abs >> @intCast(SrcShift, src_sig_bits - scale));
128 dst.exp ^= 1;130 dst.exp ^= 1;
129 dst.exp |= dst_exp_bias - src_exp_bias - scale + 1;131 dst.exp |= dst_exp_bias - src_exp_bias - scale + 1;
130 } else {132 } else {
lib/compiler_rt/extendf_test.zig+48
...@@ -1,10 +1,27 @@...@@ -1,10 +1,27 @@
1const std = @import("std");
2const math = std.math;
1const builtin = @import("builtin");3const builtin = @import("builtin");
2const __extendhfsf2 = @import("extendhfsf2.zig").__extendhfsf2;4const __extendhfsf2 = @import("extendhfsf2.zig").__extendhfsf2;
3const __extendhftf2 = @import("extendhftf2.zig").__extendhftf2;5const __extendhftf2 = @import("extendhftf2.zig").__extendhftf2;
4const __extendsftf2 = @import("extendsftf2.zig").__extendsftf2;6const __extendsftf2 = @import("extendsftf2.zig").__extendsftf2;
5const __extenddftf2 = @import("extenddftf2.zig").__extenddftf2;7const __extenddftf2 = @import("extenddftf2.zig").__extenddftf2;
8const __extenddfxf2 = @import("extenddfxf2.zig").__extenddfxf2;
6const F16T = @import("./common.zig").F16T;9const F16T = @import("./common.zig").F16T;
710
11fn test__extenddfxf2(a: f64, expected: u80) !void {
12 const x = __extenddfxf2(a);
13
14 const rep = @bitCast(u80, x);
15 if (rep == expected)
16 return;
17
18 // test other possible NaN representation(signal NaN)
19 if (math.isNan(@bitCast(f80, expected)) and math.isNan(x))
20 return;
21
22 @panic("__extenddfxf2 test failure");
23}
24
8fn test__extenddftf2(a: f64, expected_hi: u64, expected_lo: u64) !void {25fn test__extenddftf2(a: f64, expected_hi: u64, expected_lo: u64) !void {
9 const x = __extenddftf2(a);26 const x = __extenddftf2(a);
1027
...@@ -65,6 +82,33 @@ fn test__extendsftf2(a: f32, expected_hi: u64, expected_lo: u64) !void {...@@ -65,6 +82,33 @@ fn test__extendsftf2(a: f32, expected_hi: u64, expected_lo: u64) !void {
65 return error.TestFailure;82 return error.TestFailure;
66}83}
6784
85test "extenddfxf2" {
86 // qNaN
87 try test__extenddfxf2(makeQNaN64(), 0x7fffc000000000000000);
88
89 // NaN
90 try test__extenddfxf2(makeNaN64(0x7100000000000), 0x7fffe080000000000000);
91 // This is bad?
92
93 // inf
94 try test__extenddfxf2(makeInf64(), 0x7fff8000000000000000);
95
96 // zero
97 try test__extenddfxf2(0.0, 0x0);
98
99 try test__extenddfxf2(0x0.a3456789abcdefp+6, 0x4004a3456789abcdf000);
100
101 try test__extenddfxf2(0x0.edcba987654321fp-8, 0x3ff6edcba98765432000);
102
103 try test__extenddfxf2(0x0.a3456789abcdefp+46, 0x402ca3456789abcdf000);
104
105 try test__extenddfxf2(0x0.edcba987654321fp-44, 0x3fd2edcba98765432000);
106
107 // subnormal
108 try test__extenddfxf2(0x1.8000000000001p-1022, 0x3c01c000000000000800);
109 try test__extenddfxf2(0x1.8000000000002p-1023, 0x3c00c000000000001000);
110}
111
68test "extenddftf2" {112test "extenddftf2" {
69 // qNaN113 // qNaN
70 try test__extenddftf2(makeQNaN64(), 0x7fff800000000000, 0x0);114 try test__extenddftf2(makeQNaN64(), 0x7fff800000000000, 0x0);
...@@ -85,6 +129,10 @@ test "extenddftf2" {...@@ -85,6 +129,10 @@ test "extenddftf2" {
85 try test__extenddftf2(0x1.23456789abcdefp+45, 0x402c23456789abcd, 0xf000000000000000);129 try test__extenddftf2(0x1.23456789abcdefp+45, 0x402c23456789abcd, 0xf000000000000000);
86130
87 try test__extenddftf2(0x1.edcba987654321fp-45, 0x3fd2edcba9876543, 0x2000000000000000);131 try test__extenddftf2(0x1.edcba987654321fp-45, 0x3fd2edcba9876543, 0x2000000000000000);
132
133 // subnormal
134 try test__extenddftf2(0x1.8p-1022, 0x3c01800000000000, 0x0);
135 try test__extenddftf2(0x1.8p-1023, 0x3c00800000000000, 0x0);
88}136}
89137
90test "extendhfsf2" {138test "extendhfsf2" {