diff --git a/lib/compiler_rt/divdf3.zig b/lib/compiler_rt/divdf3.zig index 489c556186e2b3c2edd865efc26adcbf16b2e179..3ad767dbf2292d403aa0e2aafbdaf20f80ff9571 100644 --- a/lib/compiler_rt/divdf3.zig +++ b/lib/compiler_rt/divdf3.zig @@ -4,7 +4,7 @@ const std = @import("std"); const compiler_rt = @import("../compiler_rt.zig"); -const symbol = @import("../compiler_rt.zig").symbol; +const symbol = compiler_rt.symbol; const normalize = compiler_rt.normalize; const wideMultiply = compiler_rt.wideMultiply; @@ -189,14 +189,13 @@ inline fn div(a: f64, b: f64) f64 { const writtenExponent = quotientExponent +% exponentBias; + const round = @intFromBool((residual << 1) >= bSignificand); + if (writtenExponent >= maxExponent) { // If we have overflowed the exponent, return infinity. return @bitCast(infRep | quotientSign); } else if (writtenExponent < 1) { if (writtenExponent == 0) { - // Check whether the rounded result is normal. - const round = @intFromBool((residual << 1) > bSignificand); - // Clear the implicit bit. var absResult = quotient & significandMask; // Round. absResult += round; @@ -205,11 +204,16 @@ inline fn div(a: f64, b: f64) f64 { return @bitCast(absResult | quotientSign); } } - // Flush denormals to zero. In the future, it would be nice to add - // code to round them correctly. - return @bitCast(quotientSign); + + const roundedQuotient = quotient +% round; + const shiftAmount: u32 = @intCast(1 - writtenExponent); + if (shiftAmount > significandBits + 1) { + return @bitCast(quotientSign); + } + + const denormQuotient = roundedQuotient >> @as(std.math.Log2Int(Z), @intCast(shiftAmount)); + return @bitCast((denormQuotient & significandMask) | quotientSign); } else { - const round = @intFromBool((residual << 1) > bSignificand); // Clear the implicit bit var absResult = quotient & significandMask; // Insert the exponent diff --git a/lib/compiler_rt/divdf3_test.zig b/lib/compiler_rt/divdf3_test.zig index 1524f9833fef3a4eb2022e302ee7d697f32b4797..45de9b27ef794706fc6e0e297f4289be3ae549fc 100644 --- a/lib/compiler_rt/divdf3_test.zig +++ b/lib/compiler_rt/divdf3_test.zig @@ -2,8 +2,15 @@ // // https://github.com/llvm/llvm-project/commit/d674d96bc56c0f377879d01c9d8dfdaaa7859cdb/compiler-rt/test/builtins/Unit/divdf3_test.c +const std = @import("std"); +const math = std.math; +const testing = std.testing; + const __divdf3 = @import("divdf3.zig").__divdf3; -const testing = @import("std").testing; + +const nanRep: u64 = @as(u64, @bitCast(math.nan(f64))); +const infRep: u64 = @as(u64, @bitCast(math.inf(f64))); +const negInfRep: u64 = @as(u64, @bitCast(-math.inf(f64))); fn compareResultD(result: f64, expected: u64) bool { const rep: u64 = @bitCast(result); @@ -12,7 +19,7 @@ fn compareResultD(result: f64, expected: u64) bool { return true; } // test other possible NaN representation(signal NaN) - else if (expected == 0x7ff8000000000000) { + else if (expected == nanRep) { if ((rep & 0x7ff0000000000000) == 0x7ff0000000000000 and (rep & 0xfffffffffffff) > 0) { @@ -32,4 +39,28 @@ test "divdf3" { try test__divdf3(1.0, 3.0, 0x3fd5555555555555); try test__divdf3(4.450147717014403e-308, 2.0, 0x10000000000000); try test__divdf3(1.0, 0x1.fffffffffffffp-1, 0x3ff0000000000001); + + try test__divdf3(math.nan(f64), 1.0, nanRep); + try test__divdf3(1.0, math.nan(f64), nanRep); + + try test__divdf3(math.inf(f64), 1.0, infRep); + try test__divdf3(-math.inf(f64), 1.0, negInfRep); + try test__divdf3(1.0, math.inf(f64), 0x0000000000000000); + try test__divdf3(1.0, -math.inf(f64), 0x8000000000000000); + + try test__divdf3(math.inf(f64), math.inf(f64), nanRep); + try test__divdf3(0.0, 0.0, nanRep); + try test__divdf3(-0.0, 0.0, nanRep); + + try test__divdf3(0.0, 1.0, 0x0000000000000000); + try test__divdf3(-0.0, 1.0, 0x8000000000000000); + try test__divdf3(1.0, 0.0, infRep); + try test__divdf3(1.0, -0.0, negInfRep); + + try test__divdf3(0x1p-1022, 0x1p52, 0x0000000000000001); + try test__divdf3(-0x1p-1022, 0x1p52, 0x8000000000000001); + try test__divdf3(0x1p-1022, -0x1p52, 0x8000000000000001); + + try test__divdf3(1.0, 0x1p1023, 0x0008000000000000); + try test__divdf3(-1.0, 0x1p1023, 0x8008000000000000); } diff --git a/lib/compiler_rt/divsf3.zig b/lib/compiler_rt/divsf3.zig index dc017dbde1fee6973e140a25e9b416f701460459..c0fbcb92b743fff4e12db533d7694210e7ebb0a2 100644 --- a/lib/compiler_rt/divsf3.zig +++ b/lib/compiler_rt/divsf3.zig @@ -5,7 +5,7 @@ const std = @import("std"); const compiler_rt = @import("../compiler_rt.zig"); -const symbol = @import("../compiler_rt.zig").symbol; +const symbol = compiler_rt.symbol; const normalize = compiler_rt.normalize; comptime { @@ -170,14 +170,14 @@ inline fn div(a: f32, b: f32) f32 { const writtenExponent = quotientExponent +% exponentBias; + const round = @intFromBool((residual << 1) >= bSignificand); + if (writtenExponent >= maxExponent) { // If we have overflowed the exponent, return infinity. return @bitCast(infRep | quotientSign); } else if (writtenExponent < 1) { if (writtenExponent == 0) { // Check whether the rounded result is normal. - const round = @intFromBool((residual << 1) > bSignificand); - // Clear the implicit bit. var absResult = quotient & significandMask; // Round. absResult += round; @@ -186,11 +186,16 @@ inline fn div(a: f32, b: f32) f32 { return @bitCast(absResult | quotientSign); } } - // Flush denormals to zero. In the future, it would be nice to add - // code to round them correctly. - return @bitCast(quotientSign); + + const roundedQuotient = quotient +% round; + const shiftAmount: u32 = @intCast(1 - writtenExponent); + if (shiftAmount > significandBits + 1) { + return @bitCast(quotientSign); + } + + const denormQuotient = roundedQuotient >> @as(std.math.Log2Int(Z), @intCast(shiftAmount)); + return @bitCast((denormQuotient & significandMask) | quotientSign); } else { - const round = @intFromBool((residual << 1) > bSignificand); // Clear the implicit bit var absResult = quotient & significandMask; // Insert the exponent diff --git a/lib/compiler_rt/divsf3_test.zig b/lib/compiler_rt/divsf3_test.zig index 1af93bc77c80e2c97020d2dd63b17a421a86293e..c457915e49cd41986f1470b2f868398cfad855e9 100644 --- a/lib/compiler_rt/divsf3_test.zig +++ b/lib/compiler_rt/divsf3_test.zig @@ -2,8 +2,15 @@ // // https://github.com/llvm/llvm-project/commit/d674d96bc56c0f377879d01c9d8dfdaaa7859cdb/compiler-rt/test/builtins/Unit/divsf3_test.c +const std = @import("std"); +const math = std.math; +const testing = std.testing; + const __divsf3 = @import("divsf3.zig").__divsf3; -const testing = @import("std").testing; + +const nanRep: u32 = @as(u32, @bitCast(math.nan(f32))); +const infRep: u32 = @as(u32, @bitCast(math.inf(f32))); +const negInfRep: u32 = @as(u32, @bitCast(-math.inf(f32))); fn compareResultF(result: f32, expected: u32) bool { const rep: u32 = @bitCast(result); @@ -12,7 +19,7 @@ fn compareResultF(result: f32, expected: u32) bool { return true; } // test other possible NaN representation(signal NaN) - else if (expected == 0x7fc00000) { + else if (expected == nanRep) { if ((rep & 0x7f800000) == 0x7f800000 and (rep & 0x7fffff) > 0) { @@ -32,4 +39,28 @@ test "divsf3" { try test__divsf3(1.0, 3.0, 0x3EAAAAAB); try test__divsf3(2.3509887e-38, 2.0, 0x00800000); try test__divsf3(1.0, 0x1.fffffep-1, 0x3f800001); + + try test__divsf3(math.nan(f32), 1.0, nanRep); + try test__divsf3(1.0, math.nan(f32), nanRep); + + try test__divsf3(math.inf(f32), 1.0, infRep); + try test__divsf3(-math.inf(f32), 1.0, negInfRep); + try test__divsf3(1.0, math.inf(f32), 0x00000000); + try test__divsf3(1.0, -math.inf(f32), 0x80000000); + + try test__divsf3(math.inf(f32), math.inf(f32), nanRep); + try test__divsf3(0.0, 0.0, nanRep); + try test__divsf3(-0.0, 0.0, nanRep); + + try test__divsf3(0.0, 1.0, 0x00000000); + try test__divsf3(-0.0, 1.0, 0x80000000); + try test__divsf3(1.0, 0.0, infRep); + try test__divsf3(1.0, -0.0, negInfRep); + + try test__divsf3(0x1p-126, 0x1p23, 0x00000001); + try test__divsf3(-0x1p-126, 0x1p23, 0x80000001); + try test__divsf3(0x1p-126, -0x1p23, 0x80000001); + + try test__divsf3(1.0, 0x1p127, 0x00400000); + try test__divsf3(-1.0, 0x1p127, 0x80400000); } diff --git a/lib/compiler_rt/divtf3_test.zig b/lib/compiler_rt/divtf3_test.zig index 4573d2ed85a6d7581a230ccfe5264de463a57ea6..4d10e5c39d7dc61b1c317364750757148635543d 100644 --- a/lib/compiler_rt/divtf3_test.zig +++ b/lib/compiler_rt/divtf3_test.zig @@ -30,14 +30,19 @@ fn test__divtf3(a: f128, b: f128, expectedHi: u64, expectedLo: u64) !void { } test "divtf3" { - // NaN / any = NaN try test__divtf3(math.nan(f128), 0x1.23456789abcdefp+5, 0x7fff800000000000, 0); - // inf / any(except inf and nan) = inf + try test__divtf3(0x1.23456789abcdefp+5, math.nan(f128), 0x7fff800000000000, 0); try test__divtf3(math.inf(f128), 0x1.23456789abcdefp+5, 0x7fff000000000000, 0); - // inf / inf = nan + try test__divtf3(-math.inf(f128), 0x1.23456789abcdefp+5, 0xffff000000000000, 0); + try test__divtf3(0x1.23456789abcdefp+5, math.inf(f128), 0, 0); + try test__divtf3(0x1.23456789abcdefp+5, -math.inf(f128), 0x8000000000000000, 0); try test__divtf3(math.inf(f128), math.inf(f128), 0x7fff800000000000, 0); - // inf / nan = nan - try test__divtf3(math.inf(f128), math.nan(f128), 0x7fff800000000000, 0); + try test__divtf3(0.0, 0.0, 0x7fff800000000000, 0); + try test__divtf3(-0.0, 0.0, 0x7fff800000000000, 0); + try test__divtf3(0.0, 1.0, 0, 0); + try test__divtf3(-0.0, 1.0, 0x8000000000000000, 0); + try test__divtf3(1.0, 0.0, 0x7fff000000000000, 0); + try test__divtf3(1.0, -0.0, 0xffff000000000000, 0); try test__divtf3(0x1.a23b45362464523375893ab4cdefp+5, 0x1.eedcbaba3a94546558237654321fp-1, 0x4004b0b72924d407, 0x0717e84356c6eba2); try test__divtf3(0x1.a2b34c56d745382f9abf2c3dfeffp-50, 0x1.ed2c3ba15935332532287654321fp-9, 0x3fd5b2af3f828c9b, 0x40e51f64cde8b1f2); diff --git a/lib/compiler_rt/divxf3_test.zig b/lib/compiler_rt/divxf3_test.zig index 0aec97b54d07d72c549a5b59f0cfd753807b7507..cb897a1014022d50e8cb93043749b033b56af55d 100644 --- a/lib/compiler_rt/divxf3_test.zig +++ b/lib/compiler_rt/divxf3_test.zig @@ -4,6 +4,10 @@ const testing = std.testing; const __divxf3 = @import("divxf3.zig").__divxf3; +const nanRep: u80 = @as(u80, @bitCast(math.nan(f80))); +const infRep: u80 = @as(u80, @bitCast(math.inf(f80))); +const negInfRep: u80 = @as(u80, @bitCast(-math.inf(f80))); + fn compareResult(result: f80, expected: u80) bool { const rep: u80 = @bitCast(result); @@ -39,14 +43,19 @@ fn test__divxf3(a: f80, b: f80) !void { } test "divxf3" { - // NaN / any = NaN - try expect__divxf3_result(math.nan(f80), 0x1.23456789abcdefp+5, 0x7fffC000000000000000); - // inf / any(except inf and nan) = inf - try expect__divxf3_result(math.inf(f80), 0x1.23456789abcdefp+5, 0x7fff8000000000000000); - // inf / inf = nan - try expect__divxf3_result(math.inf(f80), math.inf(f80), 0x7fffC000000000000000); - // inf / nan = nan - try expect__divxf3_result(math.inf(f80), math.nan(f80), 0x7fffC000000000000000); + try expect__divxf3_result(math.nan(f80), 0x1.23456789abcdefp+5, nanRep); + try expect__divxf3_result(0x1.23456789abcdefp+5, math.nan(f80), nanRep); + try expect__divxf3_result(math.inf(f80), 0x1.23456789abcdefp+5, infRep); + try expect__divxf3_result(-math.inf(f80), 0x1.23456789abcdefp+5, negInfRep); + try expect__divxf3_result(0x1.23456789abcdefp+5, math.inf(f80), 0x0); + try expect__divxf3_result(0x1.23456789abcdefp+5, -math.inf(f80), 0x80000000000000000000); + try expect__divxf3_result(math.inf(f80), math.inf(f80), nanRep); + try expect__divxf3_result(0.0, 0.0, nanRep); + try expect__divxf3_result(-0.0, 0.0, nanRep); + try expect__divxf3_result(0.0, 1.0, 0x0); + try expect__divxf3_result(-0.0, 1.0, 0x80000000000000000000); + try expect__divxf3_result(1.0, 0.0, infRep); + try expect__divxf3_result(1.0, -0.0, negInfRep); try test__divxf3(0x1.a23b45362464523375893ab4cdefp+5, 0x1.eedcbaba3a94546558237654321fp-1); try test__divxf3(0x1.a2b34c56d745382f9abf2c3dfeffp-50, 0x1.ed2c3ba15935332532287654321fp-9); diff --git a/test/libc.zig b/test/libc.zig index ee72cab75302935780851d8a7caf98775c9f4397..6f5590a543fe9966cd82cc3ed5241ae03f6566b6 100644 --- a/test/libc.zig +++ b/test/libc.zig @@ -151,9 +151,9 @@ pub fn addCases(cases: *tests.LibcContext) void { // cases.addLibcTestCase("math/asinhl.c", true, .{}); cases.addLibcTestCase("math/asinl.c", true, .{}); cases.addLibcTestCase("math/atan.c", true, .{}); - // cases.addLibcTestCase("math/atan2.c", true, .{}); - // cases.addLibcTestCase("math/atan2f.c", true, .{}); - // cases.addLibcTestCase("math/atan2l.c", true, .{}); + cases.addLibcTestCase("math/atan2.c", true, .{}); + cases.addLibcTestCase("math/atan2f.c", true, .{}); + cases.addLibcTestCase("math/atan2l.c", true, .{}); cases.addLibcTestCase("math/atanf.c", true, .{}); cases.addLibcTestCase("math/atanh.c", true, .{}); cases.addLibcTestCase("math/atanhf.c", true, .{});