Fixes to divsf3 (#2186)
* Fixes to divsf3 Embarrassingly failed to notice a section that was unchanged from where it was copied from mulXf3.zig. The test cases for this function series div{s,d,t}f3 are very incomplete and don't exercise all code paths. Remove unnecessary switch from divsf3 left during development from when I tried to make it generic to support f32, f64, and f128 in one go. Make runtime safety dependent on whether a test is being run. * divsf3: switch plus to minus
This commit is contained in:
parent
aecbd1892a
commit
c24a49a1a7
@ -3,8 +3,10 @@
|
||||
// https://github.com/llvm/llvm-project/commit/d674d96bc56c0f377879d01c9d8dfdaaa7859cdb/compiler-rt/lib/builtins/divsf3.c
|
||||
|
||||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
|
||||
pub extern fn __divsf3(a: f32, b: f32) f32 {
|
||||
@setRuntimeSafety(builtin.is_test);
|
||||
const Z = @IntType(false, f32.bit_count);
|
||||
|
||||
const typeWidth = f32.bit_count;
|
||||
@ -37,41 +39,43 @@ pub extern fn __divsf3(a: f32, b: f32) f32 {
|
||||
const aAbs: Z = @bitCast(Z, a) & absMask;
|
||||
const bAbs: Z = @bitCast(Z, b) & absMask;
|
||||
|
||||
// NaN * anything = qNaN
|
||||
// NaN / anything = qNaN
|
||||
if (aAbs > infRep) return @bitCast(f32, @bitCast(Z, a) | quietBit);
|
||||
// anything * NaN = qNaN
|
||||
// anything / NaN = qNaN
|
||||
if (bAbs > infRep) return @bitCast(f32, @bitCast(Z, b) | quietBit);
|
||||
|
||||
if (aAbs == infRep) {
|
||||
// infinity * non-zero = +/- infinity
|
||||
if (bAbs != 0) {
|
||||
// infinity / infinity = NaN
|
||||
if (bAbs == infRep) {
|
||||
return @bitCast(f32, qnanRep);
|
||||
}
|
||||
// infinity / anything else = +/- infinity
|
||||
else {
|
||||
return @bitCast(f32, aAbs | quotientSign);
|
||||
} else {
|
||||
// infinity * zero = NaN
|
||||
return @bitCast(f32, qnanRep);
|
||||
}
|
||||
}
|
||||
|
||||
if (bAbs == infRep) {
|
||||
//? non-zero * infinity = +/- infinity
|
||||
if (aAbs != 0) {
|
||||
return @bitCast(f32, bAbs | quotientSign);
|
||||
} else {
|
||||
// zero * infinity = NaN
|
||||
// anything else / infinity = +/- 0
|
||||
if (bAbs == infRep) return @bitCast(f32, quotientSign);
|
||||
|
||||
if (aAbs == 0) {
|
||||
// zero / zero = NaN
|
||||
if (bAbs == 0) {
|
||||
return @bitCast(f32, qnanRep);
|
||||
}
|
||||
// zero / anything else = +/- zero
|
||||
else {
|
||||
return @bitCast(f32, quotientSign);
|
||||
}
|
||||
}
|
||||
|
||||
// zero * anything = +/- zero
|
||||
if (aAbs == 0) return @bitCast(f32, quotientSign);
|
||||
// anything * zero = +/- zero
|
||||
if (bAbs == 0) return @bitCast(f32, quotientSign);
|
||||
// anything else / zero = +/- infinity
|
||||
if (bAbs == 0) return @bitCast(f32, infRep | quotientSign);
|
||||
|
||||
// one or both of a or b is denormal, the other (if applicable) is a
|
||||
// normal number. Renormalize one or both of a and b, and set scale to
|
||||
// include the necessary exponent adjustment.
|
||||
if (aAbs < implicitBit) scale +%= normalize(f32, &aSignificand);
|
||||
if (bAbs < implicitBit) scale +%= normalize(f32, &bSignificand);
|
||||
if (bAbs < implicitBit) scale -%= normalize(f32, &bSignificand);
|
||||
}
|
||||
|
||||
// Or in the implicit significand bit. (If we fell through from the
|
||||
@ -85,11 +89,7 @@ pub extern fn __divsf3(a: f32, b: f32) f32 {
|
||||
// [1, 2.0) and get a Q32 approximate reciprocal using a small minimax
|
||||
// polynomial approximation: reciprocal = 3/4 + 1/sqrt(2) - b/2. This
|
||||
// is accurate to about 3.5 binary digits.
|
||||
const q31b = switch (f32) {
|
||||
f32 => bSignificand << 8,
|
||||
f64 => bSignificand >> 21,
|
||||
else => @compileError("Type not implemented."),
|
||||
};
|
||||
const q31b = bSignificand << 8;
|
||||
var reciprocal = u32(0x7504f333) -% q31b;
|
||||
|
||||
// Now refine the reciprocal estimate using a Newton-Raphson iteration:
|
||||
@ -186,6 +186,7 @@ pub extern fn __divsf3(a: f32, b: f32) f32 {
|
||||
}
|
||||
|
||||
fn normalize(comptime T: type, significand: *@IntType(false, T.bit_count)) i32 {
|
||||
@setRuntimeSafety(builtin.is_test);
|
||||
const Z = @IntType(false, T.bit_count);
|
||||
const significandBits = std.math.floatMantissaBits(T);
|
||||
const implicitBit = Z(1) << significandBits;
|
||||
|
Loading…
x
Reference in New Issue
Block a user