real.c (sticky_rshift_significand): Return inexact, don't or it in immediately.
authorRichard Henderson <rth@redhat.com>
Tue, 22 Oct 2002 00:17:15 +0000 (17:17 -0700)
committerRichard Henderson <rth@gcc.gnu.org>
Tue, 22 Oct 2002 00:17:15 +0000 (17:17 -0700)
        * real.c (sticky_rshift_significand): Return inexact, don't
        or it in immediately.
        (sub_significands): Accept incomming carry.
        (div_significands, rtd_divmod): Update for sub_significands change.
        (round_for_format): Update for sticky_rshift_significand change.
        (do_add): Don't involve the inexact bit in addition, do give the
        inexact bit as the subtraction carry-in.
        (encode_internal, decode_internal, real_internal_format): New.
        * real.h (real_internal_format): Declare.

From-SVN: r58396

gcc/ChangeLog
gcc/real.c
gcc/real.h

index 2dc6568c74e3a74895e8a9b1f9406c99ca0ca572..de0f8b509934c698ff16e66151b1385d8b38e6c0 100644 (file)
@@ -1,3 +1,15 @@
+2002-10-21  Richard Henderson  <rth@redhat.com>
+
+       * real.c (sticky_rshift_significand): Return inexact, don't
+       or it in immediately.
+       (sub_significands): Accept incomming carry.
+       (div_significands, rtd_divmod): Update for sub_significands change.
+       (round_for_format): Update for sticky_rshift_significand change.
+       (do_add): Don't involve the inexact bit in addition, do give the
+       inexact bit as the subtraction carry-in.
+       (encode_internal, decode_internal, real_internal_format): New.
+       * real.h (real_internal_format): Declare.
+
 2002-10-21  Ulrich Weigand  <uweigand@de.ibm.com>
 
        * libgcc2.c: Fix __udiv_w_sdiv breakage on platforms that
index 458a3c691b84233ba32ca0e74edbd6d3916861ec..a2c9d8af71a92632c880a120600541828eac9b07 100644 (file)
@@ -81,7 +81,7 @@ static void get_zero PARAMS ((REAL_VALUE_TYPE *, int));
 static void get_canonical_qnan PARAMS ((REAL_VALUE_TYPE *, int));
 static void get_canonical_snan PARAMS ((REAL_VALUE_TYPE *, int));
 static void get_inf PARAMS ((REAL_VALUE_TYPE *, int));
-static void sticky_rshift_significand PARAMS ((REAL_VALUE_TYPE *,
+static bool sticky_rshift_significand PARAMS ((REAL_VALUE_TYPE *,
                                               const REAL_VALUE_TYPE *,
                                               unsigned int));
 static void rshift_significand PARAMS ((REAL_VALUE_TYPE *,
@@ -97,7 +97,7 @@ static bool add_significands PARAMS ((REAL_VALUE_TYPE *r,
                                      const REAL_VALUE_TYPE *));
 static bool sub_significands PARAMS ((REAL_VALUE_TYPE *,
                                      const REAL_VALUE_TYPE *,
-                                     const REAL_VALUE_TYPE *));
+                                     const REAL_VALUE_TYPE *, int));
 static void neg_significand PARAMS ((REAL_VALUE_TYPE *,
                                     const REAL_VALUE_TYPE *));
 static int cmp_significands PARAMS ((const REAL_VALUE_TYPE *,
@@ -182,10 +182,9 @@ get_inf (r, sign)
 
 \f
 /* Right-shift the significand of A by N bits; put the result in the
-   significand of R.  If any one bits are shifted out, set the least
-   significant bit of R.  */
+   significand of R.  If any one bits are shifted out, return true.  */
 
-static void
+static bool
 sticky_rshift_significand (r, a, n)
      REAL_VALUE_TYPE *r;
      const REAL_VALUE_TYPE *a;
@@ -220,7 +219,7 @@ sticky_rshift_significand (r, a, n)
        r->sig[i] = 0;
     }
 
-  r->sig[0] |= (sticky != 0);
+  return sticky != 0;
 }
 
 /* Right-shift the significand of A by N bits; put the result in the
@@ -327,15 +326,16 @@ add_significands (r, a, b)
   return carry;
 }
 
-/* Subtract the significands of A and B, placing the result in R.
-   Return true if there was carry out of the most significant word.  */
+/* Subtract the significands of A and B, placing the result in R.  CARRY is
+   true if there's a borrow incoming to the least significant word.
+   Return true if there was borrow out of the most significant word.  */
 
 static inline bool
-sub_significands (r, a, b)
+sub_significands (r, a, b, carry)
      REAL_VALUE_TYPE *r;
      const REAL_VALUE_TYPE *a, *b;
+     int carry;
 {
-  bool carry = false;
   int i;
 
   for (i = 0; i < SIGSZ; ++i)
@@ -500,7 +500,7 @@ div_significands (r, a, b)
     start:
       if (msb || cmp_significands (&u, b) >= 0)
        {
-         sub_significands (&u, &u, b);
+         sub_significands (&u, &u, b, 0);
          set_significand_bit (r, bit);
        }
     }
@@ -570,6 +570,7 @@ do_add (r, a, b, subtract_p)
 {
   int dexp, sign, exp;
   REAL_VALUE_TYPE t;
+  bool inexact = false;
 
   /* Determine if we need to add or subtract.  */
   sign = a->sign;
@@ -648,13 +649,13 @@ do_add (r, a, b, subtract_p)
          return;
        }
 
-      sticky_rshift_significand (&t, b, dexp);
+      inexact |= sticky_rshift_significand (&t, b, dexp);
       b = &t;
     }
 
   if (subtract_p)
     {
-      if (sub_significands (r, a, b))
+      if (sub_significands (r, a, b, inexact))
        {
          /* We got a borrow out of the subtraction.  That means that
             A and B had the same exponent, and B had the larger
@@ -671,7 +672,7 @@ do_add (r, a, b, subtract_p)
          /* We got carry out of the addition.  This means we need to
             shift the significand back down one bit and increase the
             exponent.  */
-         sticky_rshift_significand (r, r, 1);
+         inexact |= sticky_rshift_significand (r, r, 1);
          r->sig[SIGSZ-1] |= SIG_MSB;
          if (++exp > MAX_EXP)
            {
@@ -692,6 +693,8 @@ do_add (r, a, b, subtract_p)
      is positive.  */
   if (r->class == rvc_zero)
     r->sign = 0;
+  else
+    r->sig[0] |= inexact;
 }
 
 /* Return R = A * B.  */
@@ -1430,7 +1433,7 @@ rtd_divmod (num, den)
     start:
       if (msb || cmp_significands (num, den) >= 0)
        {
-         sub_significands (num, num, den);
+         sub_significands (num, num, den, 0);
          q |= 1;
        }
     }
@@ -2329,7 +2332,7 @@ round_for_format (fmt, r)
       if (shift)
        {
          shift = fmt->log2_b - shift;
-         sticky_rshift_significand (r, r, shift);
+         r->sig[0] |= sticky_rshift_significand (r, r, shift);
          r->exp += shift;
        }
     }
@@ -2355,7 +2358,7 @@ round_for_format (fmt, r)
            goto underflow;
 
          /* De-normalize the significand.  */
-         sticky_rshift_significand (r, r, diff);
+         r->sig[0] |= sticky_rshift_significand (r, r, diff);
          r->exp += diff;
        }
     }
@@ -2395,7 +2398,7 @@ round_for_format (fmt, r)
              if (shift)
                {
                  shift = fmt->log2_b - shift;
-                 sticky_rshift_significand (r, r, shift);
+                 rshift_significand (r, r, shift);
                  r->exp += shift;
                  if (r->exp > emax2)
                    goto overflow;
@@ -4308,6 +4311,51 @@ const struct real_format c4x_extended_format =
     false,
     false
   };
+
+\f
+/* A synthetic "format" for internal arithmetic.  It's the size of the
+   internal significand minus the two bits needed for proper rounding.
+   The encode and decode routines exist only to satisfy our paranoia
+   harness.  */
+
+static void encode_internal PARAMS ((const struct real_format *fmt,
+                                    long *, const REAL_VALUE_TYPE *));
+static void decode_internal PARAMS ((const struct real_format *,
+                                    REAL_VALUE_TYPE *, const long *));
+
+static void
+encode_internal (fmt, buf, r)
+     const struct real_format *fmt ATTRIBUTE_UNUSED;
+     long *buf;
+     const REAL_VALUE_TYPE *r;
+{
+  memcpy (buf, r, sizeof (*r));
+}
+
+static void
+decode_internal (fmt, r, buf)
+     const struct real_format *fmt ATTRIBUTE_UNUSED;
+     REAL_VALUE_TYPE *r;
+     const long *buf;
+{
+  memcpy (r, buf, sizeof (*r));
+}
+
+const struct real_format real_internal_format = 
+  {
+    encode_internal,
+    decode_internal,
+    2,
+    1,
+    SIGNIFICAND_BITS - 2,
+    -MAX_EXP,
+    MAX_EXP,
+    true,
+    true,
+    false,
+    true,
+    true 
+  };
 \f
 /* Set up default mode to format mapping for IEEE.  Everyone else has
    to set these values in OVERRIDE_OPTIONS.  */
index 2bdca76081fc1f8ff512f8ba5997758fbac8c684..a979cea67ac1a3265722d49194dbe5aa345a1103 100644 (file)
@@ -231,6 +231,7 @@ extern const struct real_format i370_single_format;
 extern const struct real_format i370_double_format;
 extern const struct real_format c4x_single_format;
 extern const struct real_format c4x_extended_format;
+extern const struct real_format real_internal_format;
 
 
 /* ====================================================================== */