aboutsummaryrefslogtreecommitdiff
path: root/libgcc
diff options
context:
space:
mode:
authorKeith Packard <keithp@keithp.com>2023-11-10 16:41:19 -0700
committerJeff Law <jlaw@ventanamicro.com>2023-11-10 16:47:22 -0700
commite0c1476d5d7c450b1b16a40364cea4e91237ea93 (patch)
treec40f92bbbf2880981a097d185c574d7f94cba35e /libgcc
parentb42dd1379048fd9cc7eb7039b9dfee02d6884df7 (diff)
downloadgcc-e0c1476d5d7c450b1b16a40364cea4e91237ea93.zip
gcc-e0c1476d5d7c450b1b16a40364cea4e91237ea93.tar.gz
gcc-e0c1476d5d7c450b1b16a40364cea4e91237ea93.tar.bz2
[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. libgcc/ * config/m68k/lb1sf68.S (__adddf3): Properly check for non-zero denorm. (__divdf3): Restore sign bit properly. (__addsf3): Correct exponent check. * config/m68k/fpgnulib.c (EXPMASK): Define. (__extendsfdf2): Handle Inf and NaN properly. (__truncdfsf2): Handle underflow and overflow correctly. (__extenddfxf2): Handle underflow, denorms, Inf and NaN correctly. (__truncxfdf2): Handle underflow and denorms correctly. (__fixxfsi): Reimplement.
Diffstat (limited to 'libgcc')
-rw-r--r--libgcc/config/m68k/fpgnulib.c161
-rw-r--r--libgcc/config/m68k/lb1sf68.S7
2 files changed, 134 insertions, 34 deletions
diff --git a/libgcc/config/m68k/fpgnulib.c b/libgcc/config/m68k/fpgnulib.c
index d5c3411..986750e 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;
@@ -433,6 +449,30 @@ __extenddfxf2 (double d)
}
exp = EXPD (dl) - EXCESSD + EXCESSX;
+ /* 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;
+ }
+ /* Handle inf and NaN */
+ 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 */
@@ -465,9 +505,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);
@@ -512,10 +581,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 - 63;
+
+ 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 8ba85c5..736a9a7 100644
--- a/libgcc/config/m68k/lb1sf68.S
+++ b/libgcc/config/m68k/lb1sf68.S
@@ -1383,6 +1383,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:
@@ -2090,8 +2092,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
@@ -2936,7 +2937,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