crosstool-ng/packages/gcc/13.2.0/0012-libgcc-m68k-Fixes-for-soft-float.patch
Keith Packard 5a09578b67 gcc/13.2.0: Add patch with fixes for m68k soft float code
Here's a patch I've sent upstream which fixes a range of floating
point bugs in libgcc.

Signed-off-by: Keith Packard <keithp@keithp.com>
2023-08-25 18:13:37 +12:00

349 lines
8.8 KiB
Diff

From 3393fcce1e6b18e580b712c0855bba13fb622531 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 | 162 +++++++++++++++++++++++++++-------
libgcc/config/m68k/lb1sf68.S | 20 +++--
2 files changed, 143 insertions(+), 39 deletions(-)
diff --git a/libgcc/config/m68k/fpgnulib.c b/libgcc/config/m68k/fpgnulib.c
index fe41edf26aa..eaa7858493c 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,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 8ba85c53656..e12888bd7f8 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
--
2.40.1