mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-21 16:29:59 +00:00
![Kumar Gala](/assets/img/avatar_default.png)
The math emulation code is centered around a set of generic macros that provide the core of the emulation that are shared by the various architectures and other projects (like glibc). Each arch implements its own sfp-machine.h to specific various arch specific details. For historic reasons that are now lost the powerpc math-emu code had its own version of the common headers. This moves us to using the kernel generic version and thus getting fixes when those are updated. Also cleaned up exception/error reporting from the FP emulation functions. Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
191 lines
3.4 KiB
C
191 lines
3.4 KiB
C
/* This has so very few changes over libgcc2's __udivmoddi4 it isn't funny. */
|
|
|
|
#include <math-emu/soft-fp.h>
|
|
|
|
#undef count_leading_zeros
|
|
#define count_leading_zeros __FP_CLZ
|
|
|
|
void
|
|
_fp_udivmodti4(_FP_W_TYPE q[2], _FP_W_TYPE r[2],
|
|
_FP_W_TYPE n1, _FP_W_TYPE n0,
|
|
_FP_W_TYPE d1, _FP_W_TYPE d0)
|
|
{
|
|
_FP_W_TYPE q0, q1, r0, r1;
|
|
_FP_I_TYPE b, bm;
|
|
|
|
if (d1 == 0)
|
|
{
|
|
#if !UDIV_NEEDS_NORMALIZATION
|
|
if (d0 > n1)
|
|
{
|
|
/* 0q = nn / 0D */
|
|
|
|
udiv_qrnnd (q0, n0, n1, n0, d0);
|
|
q1 = 0;
|
|
|
|
/* Remainder in n0. */
|
|
}
|
|
else
|
|
{
|
|
/* qq = NN / 0d */
|
|
|
|
if (d0 == 0)
|
|
d0 = 1 / d0; /* Divide intentionally by zero. */
|
|
|
|
udiv_qrnnd (q1, n1, 0, n1, d0);
|
|
udiv_qrnnd (q0, n0, n1, n0, d0);
|
|
|
|
/* Remainder in n0. */
|
|
}
|
|
|
|
r0 = n0;
|
|
r1 = 0;
|
|
|
|
#else /* UDIV_NEEDS_NORMALIZATION */
|
|
|
|
if (d0 > n1)
|
|
{
|
|
/* 0q = nn / 0D */
|
|
|
|
count_leading_zeros (bm, d0);
|
|
|
|
if (bm != 0)
|
|
{
|
|
/* Normalize, i.e. make the most significant bit of the
|
|
denominator set. */
|
|
|
|
d0 = d0 << bm;
|
|
n1 = (n1 << bm) | (n0 >> (_FP_W_TYPE_SIZE - bm));
|
|
n0 = n0 << bm;
|
|
}
|
|
|
|
udiv_qrnnd (q0, n0, n1, n0, d0);
|
|
q1 = 0;
|
|
|
|
/* Remainder in n0 >> bm. */
|
|
}
|
|
else
|
|
{
|
|
/* qq = NN / 0d */
|
|
|
|
if (d0 == 0)
|
|
d0 = 1 / d0; /* Divide intentionally by zero. */
|
|
|
|
count_leading_zeros (bm, d0);
|
|
|
|
if (bm == 0)
|
|
{
|
|
/* From (n1 >= d0) /\ (the most significant bit of d0 is set),
|
|
conclude (the most significant bit of n1 is set) /\ (the
|
|
leading quotient digit q1 = 1).
|
|
|
|
This special case is necessary, not an optimization.
|
|
(Shifts counts of SI_TYPE_SIZE are undefined.) */
|
|
|
|
n1 -= d0;
|
|
q1 = 1;
|
|
}
|
|
else
|
|
{
|
|
_FP_W_TYPE n2;
|
|
|
|
/* Normalize. */
|
|
|
|
b = _FP_W_TYPE_SIZE - bm;
|
|
|
|
d0 = d0 << bm;
|
|
n2 = n1 >> b;
|
|
n1 = (n1 << bm) | (n0 >> b);
|
|
n0 = n0 << bm;
|
|
|
|
udiv_qrnnd (q1, n1, n2, n1, d0);
|
|
}
|
|
|
|
/* n1 != d0... */
|
|
|
|
udiv_qrnnd (q0, n0, n1, n0, d0);
|
|
|
|
/* Remainder in n0 >> bm. */
|
|
}
|
|
|
|
r0 = n0 >> bm;
|
|
r1 = 0;
|
|
#endif /* UDIV_NEEDS_NORMALIZATION */
|
|
}
|
|
else
|
|
{
|
|
if (d1 > n1)
|
|
{
|
|
/* 00 = nn / DD */
|
|
|
|
q0 = 0;
|
|
q1 = 0;
|
|
|
|
/* Remainder in n1n0. */
|
|
r0 = n0;
|
|
r1 = n1;
|
|
}
|
|
else
|
|
{
|
|
/* 0q = NN / dd */
|
|
|
|
count_leading_zeros (bm, d1);
|
|
if (bm == 0)
|
|
{
|
|
/* From (n1 >= d1) /\ (the most significant bit of d1 is set),
|
|
conclude (the most significant bit of n1 is set) /\ (the
|
|
quotient digit q0 = 0 or 1).
|
|
|
|
This special case is necessary, not an optimization. */
|
|
|
|
/* The condition on the next line takes advantage of that
|
|
n1 >= d1 (true due to program flow). */
|
|
if (n1 > d1 || n0 >= d0)
|
|
{
|
|
q0 = 1;
|
|
sub_ddmmss (n1, n0, n1, n0, d1, d0);
|
|
}
|
|
else
|
|
q0 = 0;
|
|
|
|
q1 = 0;
|
|
|
|
r0 = n0;
|
|
r1 = n1;
|
|
}
|
|
else
|
|
{
|
|
_FP_W_TYPE m1, m0, n2;
|
|
|
|
/* Normalize. */
|
|
|
|
b = _FP_W_TYPE_SIZE - bm;
|
|
|
|
d1 = (d1 << bm) | (d0 >> b);
|
|
d0 = d0 << bm;
|
|
n2 = n1 >> b;
|
|
n1 = (n1 << bm) | (n0 >> b);
|
|
n0 = n0 << bm;
|
|
|
|
udiv_qrnnd (q0, n1, n2, n1, d1);
|
|
umul_ppmm (m1, m0, q0, d0);
|
|
|
|
if (m1 > n1 || (m1 == n1 && m0 > n0))
|
|
{
|
|
q0--;
|
|
sub_ddmmss (m1, m0, m1, m0, d1, d0);
|
|
}
|
|
|
|
q1 = 0;
|
|
|
|
/* Remainder in (n1n0 - m1m0) >> bm. */
|
|
sub_ddmmss (n1, n0, n1, n0, m1, m0);
|
|
r0 = (n1 << b) | (n0 >> bm);
|
|
r1 = n1 >> bm;
|
|
}
|
|
}
|
|
}
|
|
|
|
q[0] = q0; q[1] = q1;
|
|
r[0] = r0, r[1] = r1;
|
|
}
|