diff options
Diffstat (limited to 'lib/ppc/gcc_qdiv.c')
-rw-r--r-- | lib/ppc/gcc_qdiv.c | 53 |
1 files changed, 53 insertions, 0 deletions
diff --git a/lib/ppc/gcc_qdiv.c b/lib/ppc/gcc_qdiv.c new file mode 100644 index 000000000..53e6c55ec --- /dev/null +++ b/lib/ppc/gcc_qdiv.c @@ -0,0 +1,53 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// long double __gcc_qdiv(long double x, long double y); +// This file implements the PowerPC 128-bit double-double division operation. +// This implementation is shamelessly cribbed from Apple's DDRT, circa 1993(!) + +#include "DD.h" + +long double __gcc_qdiv(long double a, long double b) +{ + static const uint32_t infinityHi = UINT32_C(0x7ff00000); + DD dst = { .ld = a }, src = { .ld = b }; + + register double x = dst.hi, x1 = dst.lo, + y = src.hi, y1 = src.lo; + + double yHi, yLo, qHi, qLo; + double yq, tmp, q; + + q = x / y; + + // Detect special cases + if (q == 0.0) { + dst.hi = q; + dst.lo = 0.0; + return dst.ld; + } + + const doublebits qBits = { .d = q }; + if (((uint32_t)(qBits.x >> 32) & infinityHi) == infinityHi) { + dst.hi = q; + dst.lo = 0.0; + return dst.ld; + } + + yHi = high26bits(y); + qHi = high26bits(q); + + yq = y * q; + yLo = y - yHi; + qLo = q - qHi; + + tmp = LOWORDER(yq, yHi, yLo, qHi, qLo); + tmp = (x - yq) - tmp; + tmp = ((tmp + x1) - y1 * q) / y; + x = q + tmp; + + dst.lo = (q - x) + tmp; + dst.hi = x; + + return dst.ld; +} |