]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
[PATCH] libgcc/m68k: Fixes for soft float
authorKeith Packard <keithp@keithp.com>
Fri, 10 Nov 2023 23:41:19 +0000 (16:41 -0700)
committerJeff Law <jlaw@ventanamicro.com>
Fri, 10 Nov 2023 23:47:22 +0000 (16:47 -0700)
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.

libgcc/config/m68k/fpgnulib.c
libgcc/config/m68k/lb1sf68.S

index d5c3411e947fd33d4dec69757823e9defcc6a1ce..986750e052350c13f7aa1a895879ad0a4e3aeb5a 100644 (file)
@@ -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.  */
index 8ba85c53656d9e68473fb96f279f69b1ac6f0e0a..736a9a7872f8b54e06076d85945bf4a5b0cf73fe 100644 (file)
@@ -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