diff options
Diffstat (limited to 'packages/gcc/13.3.0/0012-libgcc-m68k-Fixes-for-soft-float.patch')
-rw-r--r-- | packages/gcc/13.3.0/0012-libgcc-m68k-Fixes-for-soft-float.patch | 349 |
1 files changed, 349 insertions, 0 deletions
diff --git a/packages/gcc/13.3.0/0012-libgcc-m68k-Fixes-for-soft-float.patch b/packages/gcc/13.3.0/0012-libgcc-m68k-Fixes-for-soft-float.patch new file mode 100644 index 00000000..caa6664a --- /dev/null +++ b/packages/gcc/13.3.0/0012-libgcc-m68k-Fixes-for-soft-float.patch @@ -0,0 +1,349 @@ +From 51345476fc2f83c77736fab8e29ff4ac358d0f2e Mon Sep 17 00:00:00 2001 +From: Keith Packard <keithp@keithp.com> +Date: Tue, 22 Aug 2023 12:28:53 -0700 +Subject: [PATCH] libgcc/m68k: Fixes for soft float + +Check for non-zero denorm in __adddf3. Need to check both the upper and +lower 32-bit chunks of a 64-bit float for a non-zero value when +checking to see if the value is -0. + +Fix __addsf3 when the sum exponent is exactly 0xff to ensure that +produces infinity and not nan. + +Handle converting NaN/inf values between formats. + +Handle underflow and overflow when truncating. + +Write a replacement for __fixxfsi so that it does not raise extra +exceptions during an extra conversion from long double to double. + +Return correctly signed zero on float and double divide underflow + +Return positive qNaN instead of negative. + +Signed-off-by: Keith Packard <keithp@keithp.com> +--- + libgcc/config/m68k/fpgnulib.c | 170 +++++++++++++++++++++++++++------- + libgcc/config/m68k/lb1sf68.S | 20 ++-- + 2 files changed, 147 insertions(+), 43 deletions(-) + +diff --git a/libgcc/config/m68k/fpgnulib.c b/libgcc/config/m68k/fpgnulib.c +index fe41edf26aa0..eaa7858493c9 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) + { +- if (exp < -24) ++ exp = EXPMASK; ++ mant = mant >> 1 | (mant & 1) | !!sticky; ++ } ++ else ++ { ++ /* Check for underflow and denormals. */ ++ if (exp <= 0) + { +- sticky |= mant; ++ if (exp < -24) ++ { ++ sticky |= mant; ++ mant = 0; ++ } ++ else ++ { ++ 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; ++ ++ mant += 1; ++ ++ /* did the round overflow? */ ++ if (mant >= (HIDDEN << rounding)) ++ { ++ exp++; ++ shift = rounding; ++ } ++ } ++ /* shift down */ ++ mant >>= shift; ++ if (exp >= EXPMASK) ++ { ++ exp = EXPMASK; + mant = 0; + } +- else +- { +- 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; +- +- mant += 1; +- +- /* did the round overflow? */ +- if (mant >= (HIDDEN << rounding)) +- { +- exp++; +- shift = rounding; +- } +- } +- /* shift down */ +- mant >>= shift; + + mant &= ~HIDDEN; + +@@ -432,8 +448,31 @@ __extenddfxf2 (double d) + } + + exp = EXPD (dl) - EXCESSD + EXCESSX; +- ldl.l.upper |= exp << 16; ++ dl.l.upper &= MANTDMASK; + ldl.l.middle = HIDDENX; ++ ++ /* 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; ++ /* No hidden one bit for INF */ ++ if (dl.l.upper == 0 && dl.l.lower == 0) ++ ldl.l.middle = 0; ++ } ++ ++ ldl.l.upper |= exp << 16; + /* 31-20: # mantissa bits in ldl.l.middle - # mantissa bits in dl.l.upper */ + ldl.l.middle |= (dl.l.upper & MANTDMASK) << (31 - 20); + /* 1+20: explicit-integer-bit + # mantissa bits in dl.l.upper */ +@@ -464,9 +503,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 +579,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 8ba85c53656d..e12888bd7f89 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 |