diff --git a/libgcc/config/m68k/fpgnulib.c b/libgcc/config/m68k/fpgnulib.c index fe41edf26aa03..d7388d06b0d20 100644 --- a/libgcc/config/m68k/fpgnulib.c +++ b/libgcc/config/m68k/fpgnulib.c @@ -54,6 +54,7 @@ #define SIGNBIT 0x80000000L #define HIDDEN (1L << 23L) #define SIGN(fp) ((fp) & SIGNBIT) +#define EXPMASK 0xFFL #define EXP(fp) (((fp) >> 23L) & 0xFF) #define MANT(fp) (((fp) & 0x7FFFFFL) | HIDDEN) #define PACK(s,e,m) ((s) | ((e) << 23L) | (m)) @@ -262,6 +263,9 @@ __extendsfdf2 (float a1) mant &= ~HIDDEN; } exp = exp - EXCESS + EXCESSD; + /* Handle inf and NaN */ + if (exp == EXPMASK - EXCESS + EXCESSD) + exp = EXPDMASK; dl.l.upper |= exp << 20; dl.l.upper |= mant >> 3; dl.l.lower = mant << 29; @@ -295,40 +299,52 @@ __truncdfsf2 (double a1) /* shift double mantissa 6 bits so we can round */ sticky |= mant & ((1 << 6) - 1); mant >>= 6; - - /* Check for underflow and denormals. */ - if (exp <= 0) + if (exp == EXPDMASK - EXCESSD + EXCESS) + { + exp = EXPMASK; + mant = mant >> 1 | (mant & 1) | !!sticky; + } + else { - if (exp < -24) + /* Check for underflow and denormals. */ + if (exp <= 0) { - sticky |= mant; - mant = 0; + if (exp < -24) + { + sticky |= mant; + mant = 0; + } + else + { + sticky |= mant & ((1 << (1 - exp)) - 1); + mant >>= 1 - exp; + } + exp = 0; } - else + + /* now round */ + shift = 1; + if ((mant & 1) && (sticky || (mant & 2))) { - sticky |= mant & ((1 << (1 - exp)) - 1); - mant >>= 1 - exp; - } - exp = 0; - } - - /* now round */ - shift = 1; - if ((mant & 1) && (sticky || (mant & 2))) - { - int rounding = exp ? 2 : 1; + int rounding = exp ? 2 : 1; - mant += 1; + mant += 1; - /* did the round overflow? */ - if (mant >= (HIDDEN << rounding)) + /* did the round overflow? */ + if (mant >= (HIDDEN << rounding)) + { + exp++; + shift = rounding; + } + } + /* shift down */ + mant >>= shift; + if (exp >= EXPMASK) { - exp++; - shift = rounding; + exp = EXPMASK; + mant = 0; } } - /* shift down */ - mant >>= shift; mant &= ~HIDDEN; @@ -432,6 +448,24 @@ __extenddfxf2 (double d) } exp = EXPD (dl) - EXCESSD + EXCESSX; + dl.l.upper &= MANTDMASK; + + /* Recover from a denorm. */ + if (exp == -EXCESSD + EXCESSX) + { + exp++; + while ((dl.l.upper & HIDDEND) == 0) + { + exp--; + dl.l.upper = (dl.l.upper << 1) | (dl.l.lower >> 31); + dl.l.lower = dl.l.lower << 1; + } + } + + /* Handle inf and NaN */ + else if (exp == EXPDMASK - EXCESSD + EXCESSX) + exp = EXPXMASK; + ldl.l.upper |= exp << 16; ldl.l.middle = HIDDENX; /* 31-20: # mantissa bits in ldl.l.middle - # mantissa bits in dl.l.upper */ @@ -464,9 +498,38 @@ __truncxfdf2 (long double ld) } exp = EXPX (ldl) - EXCESSX + EXCESSD; - /* ??? quick and dirty: keep `exp' sane */ - if (exp >= EXPDMASK) - exp = EXPDMASK - 1; + /* Check for underflow and denormals. */ + if (exp <= 0) + { + 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 + { + 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; + } + else if (exp == EXPXMASK - EXCESSX + EXCESSD) + { + exp = EXPDMASK; + ldl.l.middle |= ldl.l.lower; + } + else if (exp >= EXPDMASK) + { + exp = EXPDMASK; + ldl.l.middle = 0; + ldl.l.lower = 0; + } dl.l.upper |= exp << (32 - (EXPDBITS + 1)); /* +1-1: add one for sign bit, but take one off for explicit-integer-bit */ dl.l.upper |= (ldl.l.middle & MANTXMASK) >> (EXPDBITS + 1 - 1); @@ -511,10 +574,40 @@ __floatunsixf (unsigned long l) /* convert a long double to an int */ long -__fixxfsi (long double ld) +__fixxfsi (long double a) { - long foo = __fixdfsi ((double) ld); - return foo; + union long_double_long ldl; + long exp; + long l; + + ldl.ld = a; + + exp = EXPX(ldl); + if (exp == 0 && ldl.l.middle == 0 && ldl.l.lower == 0) + return 0; + + exp = exp - EXCESSX - 64; + + if (exp > 0) + { + /* Return largest integer. */ + return SIGNX (ldl) ? 0x80000000L : 0x7fffffffL; + } + + if (exp <= -64) + 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); + } + + return SIGNX(ldl) ? -ldl.l.lower : ldl.l.lower; } /* 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 8ba85c53656d9..e12888bd7f893 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 @@ -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 @@ -1383,6 +1385,8 @@ Ladddf$a: bge 2f | movel d0,d0 | check for zero, since we don't ' bne Ladddf$ret | want to return -0 by mistake + movel d1,d1 | + bne Ladddf$ret | bclr IMM (31),d7 | bra Ladddf$ret | 2: @@ -2080,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: @@ -2090,8 +2095,7 @@ Ldivdf$a$nf: | If a is INFINITY we have to check b cmpl d7,d2 | compare b with INFINITY bge Ld$inop | if b is NaN or INFINITY return NaN - tstl d3 | - bne Ld$inop | + movl a0,d7 | restore sign bit to d7 bra Ld$overflow | else return overflow | If a number is denormalized we put an exponent of 1 but do not put the @@ -2186,6 +2190,7 @@ Lround$exit: #endif beq 2f | if not loop back bra 1b | + movel a0,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 @@ -2548,7 +2553,7 @@ Lround$to$minus: .globl SYM (_fpCCR) .globl $_exception_handler -QUIET_NaN = 0xffffffff +QUIET_NaN = 0x7fffffff SIGNL_NaN = 0x7f800001 INFINITY = 0x7f800000 @@ -2614,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 @@ -2936,7 +2942,7 @@ Laddsf$4: #else cmpl IMM (0xff),d2 #endif - bhi 1f + bge 1f bclr IMM (FLT_MANT_DIG-1),d0 #ifndef __mcoldfire__ lslw IMM (7),d2