[PATCH] libgcc/m68k: More fixes for soft float

Fix __extenddfxf2:

  * Remove bogus denorm handling block which would never execute --
    the converted exp value is always positive as EXCESSX > EXCESSD.

  * Compute the whole significand in dl instead of doing part of it in
    ldl.

    * Mask off exponent from dl.l.upper so the denorm shift test
      works.

    * Insert the hidden one bit into dl.l.upper as needed.

Fix __truncxfdf2 denorm handling. All that is required is to shift the
significand right by the correct amount; it already has all of the
necessary bits set including the explicit one. Compute the shift
amount, then perform the wide shift across both elements of the
significand.

Fix __fixxfsi:

  * The value  was off by a factor of two as the significand contains
    32 bits, not 31 so we need to shift by one more than the equivalent
    code in __fixdfsi.

  * Simplify the code having realized that the lower 32 bits of the
    significand can never appear in the results.

Return positive qNaN instead of negative. For floats, qNaN is 0x7fff_ffff. For
doubles, qNaN is 0x7fff_ffff_ffff_ffff.

Return correctly signed zero on float and double divide underflow. This means
that Ld$underflow now expects d7 to contain the sign bit, just like the other
return paths.

libgcc/
	* config/m68k/fpgnulib.c (extenddfxf2): Simplify code by removing code
	that should never execute.  Fix denorm shift test and insert hidden bit
	as needed.
	(__truncxfdf2): Properly compue and shift the significant right.
	* config/m68k/lb1sf68.S (__fixxfsi): Correct shift counts and simplify.
	(QUIET_NAN): Make it a positive quiet NaN and fix return values to inject
	sign properly.
This commit is contained in:
Keith Packard 2025-01-07 14:54:11 -07:00 committed by Jeff Law
parent d953c2c571
commit 0115ef57ef
2 changed files with 47 additions and 48 deletions

View File

@ -449,34 +449,37 @@ __extenddfxf2 (double d)
} }
exp = EXPD (dl) - EXCESSD + EXCESSX; exp = EXPD (dl) - EXCESSD + EXCESSX;
/* Check for underflow and denormals. */
if (exp < 0) dl.l.upper &= MANTDMASK;
/* Recover from a denorm. */
if (exp == -EXCESSD + EXCESSX)
{ {
if (exp < -53) exp++;
while ((dl.l.upper & HIDDEND) == 0)
{ {
ldl.l.middle = 0; exp--;
ldl.l.lower = 0; dl.l.upper = (dl.l.upper << 1) | (dl.l.lower >> 31);
dl.l.lower = dl.l.lower << 1;
} }
else if (exp < -30)
{
ldl.l.lower = (ldl.l.middle & MANTXMASK) >> ((1 - exp) - 32);
ldl.l.middle &= ~MANTXMASK;
}
else
{
ldl.l.lower >>= 1 - exp;
ldl.l.lower |= (ldl.l.middle & MANTXMASK) << (32 - (1 - exp));
ldl.l.middle = (ldl.l.middle & ~MANTXMASK) | (ldl.l.middle & MANTXMASK >> (1 - exp));
}
exp = 0;
} }
/* Handle inf and NaN */ /* Handle inf and NaN */
if (exp == EXPDMASK - EXCESSD + EXCESSX) else if (exp == EXPDMASK - EXCESSD + EXCESSX)
exp = EXPXMASK; {
exp = EXPXMASK;
/* Add hidden one bit for NaN */
if (dl.l.upper != 0 || dl.l.lower != 0)
dl.l.upper |= HIDDEND;
}
else
{
dl.l.upper |= HIDDEND;
}
ldl.l.upper |= exp << 16; ldl.l.upper |= exp << 16;
ldl.l.middle = HIDDENX;
/* 31-20: # mantissa bits in ldl.l.middle - # mantissa bits in dl.l.upper */ /* 31-20: # mantissa bits in ldl.l.middle - # mantissa bits in dl.l.upper */
ldl.l.middle |= (dl.l.upper & MANTDMASK) << (31 - 20); ldl.l.middle = dl.l.upper << (31 - 20);
/* 1+20: explicit-integer-bit + # mantissa bits in dl.l.upper */ /* 1+20: explicit-integer-bit + # mantissa bits in dl.l.upper */
ldl.l.middle |= dl.l.lower >> (1 + 20); ldl.l.middle |= dl.l.lower >> (1 + 20);
/* 32 - 21: # bits of dl.l.lower in ldl.l.middle */ /* 32 - 21: # bits of dl.l.lower in ldl.l.middle */
@ -508,21 +511,21 @@ __truncxfdf2 (long double ld)
/* Check for underflow and denormals. */ /* Check for underflow and denormals. */
if (exp <= 0) if (exp <= 0)
{ {
if (exp < -53) long shift = 1 - exp;
if (shift > 52)
{ {
ldl.l.middle = 0; ldl.l.middle = 0;
ldl.l.lower = 0; ldl.l.lower = 0;
} }
else if (exp < -30) else if (shift >= 32)
{ {
ldl.l.lower = (ldl.l.middle & MANTXMASK) >> ((1 - exp) - 32); ldl.l.lower = (ldl.l.middle) >> (shift - 32);
ldl.l.middle &= ~MANTXMASK; ldl.l.middle = 0;
} }
else else
{ {
ldl.l.lower >>= 1 - exp; ldl.l.lower = (ldl.l.middle << (32 - shift)) | (ldl.l.lower >> shift);
ldl.l.lower |= (ldl.l.middle & MANTXMASK) << (32 - (1 - exp)); ldl.l.middle = ldl.l.middle >> shift;
ldl.l.middle = (ldl.l.middle & ~MANTXMASK) | (ldl.l.middle & MANTXMASK >> (1 - exp));
} }
exp = 0; exp = 0;
} }
@ -585,7 +588,6 @@ __fixxfsi (long double a)
{ {
union long_double_long ldl; union long_double_long ldl;
long exp; long exp;
long l;
ldl.ld = a; ldl.ld = a;
@ -593,28 +595,20 @@ __fixxfsi (long double a)
if (exp == 0 && ldl.l.middle == 0 && ldl.l.lower == 0) if (exp == 0 && ldl.l.middle == 0 && ldl.l.lower == 0)
return 0; return 0;
exp = exp - EXCESSX - 63; exp = exp - EXCESSX - 32;
if (exp > 0) if (exp >= 0)
{ {
/* Return largest integer. */ /* Return largest integer. */
return SIGNX (ldl) ? 0x80000000L : 0x7fffffffL; return SIGNX (ldl) ? 0x80000000L : 0x7fffffffL;
} }
if (exp <= -64) if (exp <= -32)
return 0; return 0;
if (exp <= -32) ldl.l.middle >>= -exp;
{
ldl.l.lower = ldl.l.middle >> (-exp - 32);
}
else if (exp < 0)
{
ldl.l.lower = ldl.l.lower >> -exp;
ldl.l.lower |= ldl.l.middle << (32 + exp);
}
return SIGNX (ldl) ? -ldl.l.lower : ldl.l.lower; return SIGNX (ldl) ? -ldl.l.middle : ldl.l.middle;
} }
/* The remaining provide crude math support by working in double precision. */ /* The remaining provide crude math support by working in double precision. */

View File

@ -635,7 +635,7 @@ SYM (__modsi3):
.globl SYM (_fpCCR) .globl SYM (_fpCCR)
.globl $_exception_handler .globl $_exception_handler
QUIET_NaN = 0xffffffff QUIET_NaN = 0x7fffffff
D_MAX_EXP = 0x07ff D_MAX_EXP = 0x07ff
D_BIAS = 1022 D_BIAS = 1022
@ -691,7 +691,7 @@ Ld$den:
Ld$infty: Ld$infty:
Ld$overflow: Ld$overflow:
| Return a properly signed INFINITY and set the exception flags | Return a properly signed INFINITY and set the exception flags
movel IMM (0x7ff00000),d0 movel IMM (0x7ff00000),d0
movel IMM (0),d1 movel IMM (0),d1
orl d7,d0 orl d7,d0
@ -700,9 +700,10 @@ Ld$overflow:
PICJUMP $_exception_handler PICJUMP $_exception_handler
Ld$underflow: Ld$underflow:
| Return 0 and set the exception flags | Return a properly signed 0 and set the exception flags
movel IMM (0),d0 movel IMM (0),d0
movel d0,d1 movel d0,d1
orl d7,d0
movew IMM (INEXACT_RESULT+UNDERFLOW),d7 movew IMM (INEXACT_RESULT+UNDERFLOW),d7
moveq IMM (DOUBLE_FLOAT),d6 moveq IMM (DOUBLE_FLOAT),d6
PICJUMP $_exception_handler PICJUMP $_exception_handler
@ -711,6 +712,7 @@ Ld$inop:
| Return a quiet NaN and set the exception flags | Return a quiet NaN and set the exception flags
movel IMM (QUIET_NaN),d0 movel IMM (QUIET_NaN),d0
movel d0,d1 movel d0,d1
bset IMM (31),d1
movew IMM (INEXACT_RESULT+INVALID_OPERATION),d7 movew IMM (INEXACT_RESULT+INVALID_OPERATION),d7
moveq IMM (DOUBLE_FLOAT),d6 moveq IMM (DOUBLE_FLOAT),d6
PICJUMP $_exception_handler PICJUMP $_exception_handler
@ -2082,6 +2084,7 @@ Ldivdf$b$nf:
| If d2 == 0x7ff00000 we have to check d3. | If d2 == 0x7ff00000 we have to check d3.
tstl d3 | tstl d3 |
bne Ld$inop | if d3 <> 0, b is NaN bne Ld$inop | if d3 <> 0, b is NaN
movel a0,d7 | put a's sign
bra Ld$underflow | else b is +/-INFINITY, so signal underflow bra Ld$underflow | else b is +/-INFINITY, so signal underflow
Ldivdf$a$nf: Ldivdf$a$nf:
@ -2187,6 +2190,7 @@ Lround$exit:
#endif #endif
beq 2f | if not loop back beq 2f | if not loop back
bra 1b | bra 1b |
movel a0,d7 | get back sign bit into d7
bra Ld$underflow | safety check, shouldn't execute ' bra Ld$underflow | safety check, shouldn't execute '
2: orl d6,d2 | this is a trick so we don't lose ' 2: orl d6,d2 | this is a trick so we don't lose '
orl d7,d3 | the bits which were flushed right orl d7,d3 | the bits which were flushed right
@ -2549,7 +2553,7 @@ Lround$to$minus:
.globl SYM (_fpCCR) .globl SYM (_fpCCR)
.globl $_exception_handler .globl $_exception_handler
QUIET_NaN = 0xffffffff QUIET_NaN = 0x7fffffff
SIGNL_NaN = 0x7f800001 SIGNL_NaN = 0x7f800001
INFINITY = 0x7f800000 INFINITY = 0x7f800000
@ -2607,7 +2611,7 @@ Lf$den:
Lf$infty: Lf$infty:
Lf$overflow: Lf$overflow:
| Return a properly signed INFINITY and set the exception flags | Return a properly signed INFINITY and set the exception flags
movel IMM (INFINITY),d0 movel IMM (INFINITY),d0
orl d7,d0 orl d7,d0
moveq IMM (INEXACT_RESULT+OVERFLOW),d7 moveq IMM (INEXACT_RESULT+OVERFLOW),d7
@ -2615,8 +2619,9 @@ Lf$overflow:
PICJUMP $_exception_handler PICJUMP $_exception_handler
Lf$underflow: Lf$underflow:
| Return 0 and set the exception flags | Return a properly signed 0 and set the exception flags
moveq IMM (0),d0 moveq IMM (0),d0
orl d7,d0
moveq IMM (INEXACT_RESULT+UNDERFLOW),d7 moveq IMM (INEXACT_RESULT+UNDERFLOW),d7
moveq IMM (SINGLE_FLOAT),d6 moveq IMM (SINGLE_FLOAT),d6
PICJUMP $_exception_handler PICJUMP $_exception_handler