diff options
author | Keith Packard <keithp@keithp.com> | 2025-01-07 14:54:11 -0700 |
---|---|---|
committer | Jeff Law <jlaw@ventanamicro.com> | 2025-01-07 14:54:11 -0700 |
commit | 0115ef57efa9966fa7f448185dd5c741f58d4fac (patch) | |
tree | 7613074f36ed82ca92190b366e5c4efc7a9ea72c /libgcc | |
parent | d953c2c5714ed8503c4ae1b7d059a62e4e9a0624 (diff) | |
download | gcc-0115ef57efa9966fa7f448185dd5c741f58d4fac.zip gcc-0115ef57efa9966fa7f448185dd5c741f58d4fac.tar.gz gcc-0115ef57efa9966fa7f448185dd5c741f58d4fac.tar.bz2 |
[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.
Diffstat (limited to 'libgcc')
-rw-r--r-- | libgcc/config/m68k/fpgnulib.c | 78 | ||||
-rw-r--r-- | libgcc/config/m68k/lb1sf68.S | 17 |
2 files changed, 47 insertions, 48 deletions
diff --git a/libgcc/config/m68k/fpgnulib.c b/libgcc/config/m68k/fpgnulib.c index 70bfd44..a7d4258 100644 --- a/libgcc/config/m68k/fpgnulib.c +++ b/libgcc/config/m68k/fpgnulib.c @@ -449,34 +449,37 @@ __extenddfxf2 (double d) } 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) - { - ldl.l.middle = 0; - ldl.l.lower = 0; - } - else if (exp < -30) - { - ldl.l.lower = (ldl.l.middle & MANTXMASK) >> ((1 - exp) - 32); - ldl.l.middle &= ~MANTXMASK; - } - else + exp++; + while ((dl.l.upper & HIDDEND) == 0) { - 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--; + dl.l.upper = (dl.l.upper << 1) | (dl.l.lower >> 31); + dl.l.lower = dl.l.lower << 1; } - exp = 0; } + /* Handle inf and NaN */ - if (exp == EXPDMASK - EXCESSD + EXCESSX) - exp = EXPXMASK; + else if (exp == EXPDMASK - EXCESSD + EXCESSX) + { + 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.middle = HIDDENX; /* 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 */ ldl.l.middle |= dl.l.lower >> (1 + 20); /* 32 - 21: # bits of dl.l.lower in ldl.l.middle */ @@ -508,21 +511,21 @@ __truncxfdf2 (long double ld) /* Check for underflow and denormals. */ if (exp <= 0) { - if (exp < -53) + long shift = 1 - exp; + if (shift > 52) { ldl.l.middle = 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.middle &= ~MANTXMASK; + ldl.l.lower = (ldl.l.middle) >> (shift - 32); + ldl.l.middle = 0; } 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)); + ldl.l.lower = (ldl.l.middle << (32 - shift)) | (ldl.l.lower >> shift); + ldl.l.middle = ldl.l.middle >> shift; } exp = 0; } @@ -585,7 +588,6 @@ __fixxfsi (long double a) { union long_double_long ldl; long exp; - long l; ldl.ld = a; @@ -593,28 +595,20 @@ __fixxfsi (long double a) if (exp == 0 && ldl.l.middle == 0 && ldl.l.lower == 0) return 0; - exp = exp - EXCESSX - 63; + exp = exp - EXCESSX - 32; - if (exp > 0) + if (exp >= 0) { /* Return largest integer. */ return SIGNX (ldl) ? 0x80000000L : 0x7fffffffL; } - if (exp <= -64) + if (exp <= -32) return 0; - if (exp <= -32) - { - 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); - } + ldl.l.middle >>= -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. */ diff --git a/libgcc/config/m68k/lb1sf68.S b/libgcc/config/m68k/lb1sf68.S index aba8bd3..bcbcaf3 100644 --- a/libgcc/config/m68k/lb1sf68.S +++ b/libgcc/config/m68k/lb1sf68.S @@ -635,7 +635,7 @@ SYM (__modsi3): .globl SYM (_fpCCR) .globl $_exception_handler -QUIET_NaN = 0xffffffff +QUIET_NaN = 0x7fffffff D_MAX_EXP = 0x07ff D_BIAS = 1022 @@ -691,7 +691,7 @@ Ld$den: Ld$infty: 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 (0),d1 orl d7,d0 @@ -700,9 +700,10 @@ Ld$overflow: PICJUMP $_exception_handler Ld$underflow: -| Return 0 and set the exception flags +| Return a properly signed 0 and set the exception flags movel IMM (0),d0 movel d0,d1 + orl d7,d0 movew IMM (INEXACT_RESULT+UNDERFLOW),d7 moveq IMM (DOUBLE_FLOAT),d6 PICJUMP $_exception_handler @@ -711,6 +712,7 @@ Ld$inop: | Return a quiet NaN and set the exception flags movel IMM (QUIET_NaN),d0 movel d0,d1 + bset IMM (31),d1 movew IMM (INEXACT_RESULT+INVALID_OPERATION),d7 moveq IMM (DOUBLE_FLOAT),d6 PICJUMP $_exception_handler @@ -2082,6 +2084,7 @@ Ldivdf$b$nf: | If d2 == 0x7ff00000 we have to check d3. tstl d3 | 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 Ldivdf$a$nf: @@ -2187,6 +2190,7 @@ Lround$exit: #endif beq 2f | if not loop back bra 1b | + movel a0,d7 | get back sign bit into d7 bra Ld$underflow | safety check, shouldn't execute ' 2: orl d6,d2 | this is a trick so we don't lose ' orl d7,d3 | the bits which were flushed right @@ -2549,7 +2553,7 @@ Lround$to$minus: .globl SYM (_fpCCR) .globl $_exception_handler -QUIET_NaN = 0xffffffff +QUIET_NaN = 0x7fffffff SIGNL_NaN = 0x7f800001 INFINITY = 0x7f800000 @@ -2607,7 +2611,7 @@ Lf$den: Lf$infty: 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 orl d7,d0 moveq IMM (INEXACT_RESULT+OVERFLOW),d7 @@ -2615,8 +2619,9 @@ Lf$overflow: PICJUMP $_exception_handler Lf$underflow: -| Return 0 and set the exception flags +| Return a properly signed 0 and set the exception flags moveq IMM (0),d0 + orl d7,d0 moveq IMM (INEXACT_RESULT+UNDERFLOW),d7 moveq IMM (SINGLE_FLOAT),d6 PICJUMP $_exception_handler |