| author | |
| committer | |
| log | 07b08b96389a1dd60bc150a5ed72586ee57b2303 |
| tree | fc9cc3fbb8ee85d14d75bada735a3e308027f919 |
| parent | fd74c5742d3c8343868516c03a6a0695280744d1 |
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 <andrew@ziglang.org>
Co-authored-by: Chris Boesch <chrboesch@noreply.codeberg.org>
Co-committed-by: Chris Boesch <chrboesch@noreply.codeberg.org>2 files changed, 27 insertions(+), 3 deletions(-)
lib/compiler_rt/divtf3.zig+22-3| ... | ... | @@ -222,10 +222,29 @@ inline fn div(a: f128, b: f128) f128 { |
| 222 | 222 | // The rounded result is normal; return it. |
| 223 | 223 | return @bitCast(absResult | quotientSign); |
| 224 | 224 | } |
| 225 | // Result is denormal with exponent 0 | |
| 226 | return @bitCast(absResult | quotientSign); | |
| 227 | } else { | |
| 228 | // For denormals with writtenExponent < 0, | |
| 229 | // the implicit bit must be shifted into the mantissa (IEEE 754) | |
| 230 | const shiftAmount = @as(u7, @intCast(1 - writtenExponent)); | |
| 231 | ||
| 232 | // Check for underflow | |
| 233 | if (shiftAmount > significandBits) { | |
| 234 | return @bitCast(quotientSign); | |
| 235 | } | |
| 236 | ||
| 237 | // Round the quotient before pushing | |
| 238 | const shouldRound = (residual << 1) > bSignificand; | |
| 239 | const roundedQuotient = quotient +% @as(u113, @intFromBool(shouldRound)); | |
| 240 | ||
| 241 | // Move to the denormal range and apply the mask | |
| 242 | const denormQuotient = roundedQuotient >> shiftAmount; | |
| 243 | const absResult = denormQuotient & significandMask; | |
| 244 | ||
| 245 | // Add sign to denormal mantissa and return | |
| 246 | return @bitCast(absResult | quotientSign); | |
| 225 | 247 | } |
| 226 | // Flush denormals to zero. In the future, it would be nice to add | |
| 227 | // code to round them correctly. | |
| 228 | return @bitCast(quotientSign); | |
| 229 | 248 | } else { |
| 230 | 249 | const round = @intFromBool((residual << 1) >= bSignificand); |
| 231 | 250 | // Clear the implicit bit |
lib/compiler_rt/divtf3_test.zig+5| ... | ... | @@ -46,4 +46,9 @@ test "divtf3" { |
| 46 | 46 | try test__divtf3(0x1.2345f6b77b7a8953365433abcdefp+234, 0x1.edcba987d6bb3aa467754354321fp-4055, 0x50bf2e02f0798d36, 0x5e6fcb6b60044078); |
| 47 | 47 | try test__divtf3(6.72420628622418701252535563464350521E-4932, 2.0, 0x0001000000000000, 0); |
| 48 | 48 | try test__divtf3(1.0, 0x1.ffffffffffffffffffffffffffffp-1, 0x3FFF000000000000, 1); |
| 49 | ||
| 50 | try test__divtf3(std.math.floatMin(f128), 2.0, 0x0000800000000000, 0x0000000000000000); | |
| 51 | try test__divtf3(std.math.floatMin(f128), 4.0, 0x0000400000000000, 0x0000000000000000); | |
| 52 | try test__divtf3(1.0, 0x1.0000000000000000000000000001p16382, 0x0000ffffffffffff, 0xfffffffffffffffe); | |
| 53 | try test__divtf3(1.2, std.math.floatMax(f128), 0x00004ccccccccccc, 0xcccccccccccccccd); | |
| 49 | 54 | } |