From 07b08b96389a1dd60bc150a5ed72586ee57b2303 Mon Sep 17 00:00:00 2001 From: Chris Boesch Date: Fri, 13 Feb 2026 20:49:14 +0100 Subject: [PATCH] compiler_rt: Implemented missing handling of denormal numbers when dividing f128 (#30198) Replaces the "flush denormals to zero" placeholder in divtf3.zig with IEEE 754 denormal support including rounding. fixes #30179 Reviewed-on: https://codeberg.org/ziglang/zig/pulls/30198 Reviewed-by: Andrew Kelley Co-authored-by: Chris Boesch Co-committed-by: Chris Boesch --- lib/compiler_rt/divtf3.zig | 25 ++++++++++++++++++++++--- lib/compiler_rt/divtf3_test.zig | 5 +++++ 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/lib/compiler_rt/divtf3.zig b/lib/compiler_rt/divtf3.zig index db495ee0a4..d5d76c3c8c 100644 --- a/lib/compiler_rt/divtf3.zig +++ b/lib/compiler_rt/divtf3.zig @@ -222,10 +222,29 @@ inline fn div(a: f128, b: f128) f128 { // The rounded result is normal; return it. return @bitCast(absResult | quotientSign); } + // Result is denormal with exponent 0 + return @bitCast(absResult | quotientSign); + } else { + // For denormals with writtenExponent < 0, + // the implicit bit must be shifted into the mantissa (IEEE 754) + const shiftAmount = @as(u7, @intCast(1 - writtenExponent)); + + // Check for underflow + if (shiftAmount > significandBits) { + return @bitCast(quotientSign); + } + + // Round the quotient before pushing + const shouldRound = (residual << 1) > bSignificand; + const roundedQuotient = quotient +% @as(u113, @intFromBool(shouldRound)); + + // Move to the denormal range and apply the mask + const denormQuotient = roundedQuotient >> shiftAmount; + const absResult = denormQuotient & significandMask; + + // Add sign to denormal mantissa and return + 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); } else { const round = @intFromBool((residual << 1) >= bSignificand); // Clear the implicit bit diff --git a/lib/compiler_rt/divtf3_test.zig b/lib/compiler_rt/divtf3_test.zig index f8f2b0d188..4573d2ed85 100644 --- a/lib/compiler_rt/divtf3_test.zig +++ b/lib/compiler_rt/divtf3_test.zig @@ -46,4 +46,9 @@ test "divtf3" { try test__divtf3(0x1.2345f6b77b7a8953365433abcdefp+234, 0x1.edcba987d6bb3aa467754354321fp-4055, 0x50bf2e02f0798d36, 0x5e6fcb6b60044078); try test__divtf3(6.72420628622418701252535563464350521E-4932, 2.0, 0x0001000000000000, 0); try test__divtf3(1.0, 0x1.ffffffffffffffffffffffffffffp-1, 0x3FFF000000000000, 1); + + try test__divtf3(std.math.floatMin(f128), 2.0, 0x0000800000000000, 0x0000000000000000); + try test__divtf3(std.math.floatMin(f128), 4.0, 0x0000400000000000, 0x0000000000000000); + try test__divtf3(1.0, 0x1.0000000000000000000000000001p16382, 0x0000ffffffffffff, 0xfffffffffffffffe); + try test__divtf3(1.2, std.math.floatMax(f128), 0x00004ccccccccccc, 0xcccccccccccccccd); }