Richi has asked the we break the wide-int patch so that the individual port and 
front end maintainers can review their parts without have to go through the 
entire patch.    This patch covers the real.c code.

Ok?

        * real.c: Include wide-int.h.
        (real_to_integer2): Delete.
        (real_to_integer): New function, returning a wide_int.
        (real_from_integer): Take a wide_int rather than two HOST_WIDE_INTs.
        (ten_to_ptwo): Update call to real_from_integer.
        (real_digit): Likewise.
        * real.h: Include signop.h, wide-int.h and insn-modes.h.
        (real_to_integer2, REAL_VALUE_FROM_INT, REAL_VALUE_FROM_UNSIGNED_INT)
        (REAL_VALUE_TO_INT): Delete.
        (real_to_integer): Declare a wide-int form.
        (real_from_integer): Take a wide_int rather than two HOST_WIDE_INTs.


diff --git a/gcc/real.c b/gcc/real.c
index c1af548..93dfc35 100644
--- a/gcc/real.c
+++ b/gcc/real.c
@@ -29,6 +29,7 @@
 #include "realmpfr.h"
 #include "tm_p.h"
 #include "dfp.h"
+#include "wide-int.h"
 
 /* The floating point model used internally is not exactly IEEE 754
    compliant, and close to the description in the ISO C99 standard,
@@ -1370,42 +1371,37 @@ real_to_integer (const REAL_VALUE_TYPE *r)
     }
 }
 
-/* Likewise, but to an integer pair, HI+LOW.  */
+/* Likewise, but producing a wide-int of PRECISION.  If the value cannot
+   be represented in precision, *FAIL is set to TRUE.  */
 
-void
-real_to_integer2 (HOST_WIDE_INT *plow, HOST_WIDE_INT *phigh,
-                 const REAL_VALUE_TYPE *r)
+wide_int
+real_to_integer (const REAL_VALUE_TYPE *r, bool *fail, int precision)
 {
-  REAL_VALUE_TYPE t;
-  HOST_WIDE_INT low, high;
+  HOST_WIDE_INT val[2 * MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT];
   int exp;
+  int words;
+  wide_int result;
+  int w;
 
   switch (r->cl)
     {
     case rvc_zero:
     underflow:
-      low = high = 0;
-      break;
+      return wi::zero (precision);
 
     case rvc_inf:
     case rvc_nan:
     overflow:
-      high = (unsigned HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1);
+      *fail = true;
+
       if (r->sign)
-       low = 0;
+       return wi::set_bit_in_zero (precision - 1, precision);
       else
-       {
-         high--;
-         low = -1;
-       }
-      break;
+       return ~wi::set_bit_in_zero (precision - 1, precision);
 
     case rvc_normal:
       if (r->decimal)
-       {
-         decimal_real_to_integer2 (plow, phigh, r);
-         return;
-       }
+       return decimal_real_to_integer (r, fail, precision);
 
       exp = REAL_EXP (r);
       if (exp <= 0)
@@ -1414,42 +1410,49 @@ real_to_integer2 (HOST_WIDE_INT *plow, HOST_WIDE_INT 
*phigh,
         undefined, so it doesn't matter what we return, and some callers
         expect to be able to use this routine for both signed and
         unsigned conversions.  */
-      if (exp > HOST_BITS_PER_DOUBLE_INT)
+      if (exp > precision)
        goto overflow;
 
-      rshift_significand (&t, r, HOST_BITS_PER_DOUBLE_INT - exp);
-      if (HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONG)
+      words = (precision + HOST_BITS_PER_WIDE_INT - 1) / 
HOST_BITS_PER_WIDE_INT;
+
+      for (unsigned int i = 0; i < ARRAY_SIZE (val); i++)
+       val[i] = 0;
+
+#if (HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONG)
+      for (int i = 0; i < words; i++)
        {
-         high = t.sig[SIGSZ-1];
-         low = t.sig[SIGSZ-2];
+         int j = SIGSZ - words + i;
+         val[i] = (j < 0) ? 0 : r->sig[j];
        }
-      else
+#else
+      gcc_assert (HOST_BITS_PER_WIDE_INT == 2*HOST_BITS_PER_LONG);
+      for (int i = 0; i < words; i++)
        {
-         gcc_assert (HOST_BITS_PER_WIDE_INT == 2*HOST_BITS_PER_LONG);
-         high = t.sig[SIGSZ-1];
-         high = high << (HOST_BITS_PER_LONG - 1) << 1;
-         high |= t.sig[SIGSZ-2];
-
-         low = t.sig[SIGSZ-3];
-         low = low << (HOST_BITS_PER_LONG - 1) << 1;
-         low |= t.sig[SIGSZ-4];
+         int j = SIGSZ - (words * 2) + (i + 2) + 1;
+         if (j < 0)
+           val[i] = 0;
+         else
+           {
+             val[i] = r->sig[j];
+             val[i] <<= HOST_BITS_PER_LONG;
+             val[i] |= r->sig[j - 1];
+           }
        }
+#endif
+      w = SIGSZ * HOST_BITS_PER_LONG + words * HOST_BITS_PER_WIDE_INT;
+      result = wide_int::from_array
+       (val, (w + HOST_BITS_PER_WIDE_INT - 1) / HOST_BITS_PER_WIDE_INT, w);
+      result = wi::lrshift (result, (words * HOST_BITS_PER_WIDE_INT) - exp);
+      result = wide_int::from (result, precision, UNSIGNED);
 
       if (r->sign)
-       {
-         if (low == 0)
-           high = -high;
-         else
-           low = -low, high = ~high;
-       }
-      break;
+       return -result;
+      else
+       return result;
 
     default:
       gcc_unreachable ();
     }
-
-  *plow = low;
-  *phigh = high;
 }
 
 /* A subroutine of real_to_decimal.  Compute the quotient and remainder
@@ -2112,43 +2115,88 @@ real_from_string3 (REAL_VALUE_TYPE *r, const char *s, 
enum machine_mode mode)
     real_convert (r, mode, r);
 }
 
-/* Initialize R from the integer pair HIGH+LOW.  */
+/* Initialize R from the wide_int VAL_IN.  The MODE is not VOIDmode,*/
 
 void
 real_from_integer (REAL_VALUE_TYPE *r, enum machine_mode mode,
-                  unsigned HOST_WIDE_INT low, HOST_WIDE_INT high,
-                  int unsigned_p)
+                  const wide_int_ref &val_in, signop sgn)
 {
-  if (low == 0 && high == 0)
+  if (val_in == 0)
     get_zero (r, 0);
   else
     {
+      unsigned int len = val_in.get_precision ();
+      int i, j, e = 0;
+      int maxbitlen = MAX_BITSIZE_MODE_ANY_INT + HOST_BITS_PER_WIDE_INT;
+      const unsigned int realmax = (SIGNIFICAND_BITS / HOST_BITS_PER_WIDE_INT
+                                   * HOST_BITS_PER_WIDE_INT);
+
       memset (r, 0, sizeof (*r));
       r->cl = rvc_normal;
-      r->sign = high < 0 && !unsigned_p;
-      SET_REAL_EXP (r, HOST_BITS_PER_DOUBLE_INT);
+      r->sign = wi::neg_p (val_in, sgn);
+
+      /* We have to ensure we can negate the largest negative number.  */
+      wide_int val = wide_int::from (val_in, maxbitlen, sgn);
 
       if (r->sign)
+       val = -val;
+
+      /* Ensure a multiple of HOST_BITS_PER_WIDE_INT, ceiling, as elt
+        won't work with precisions that are not a multiple of
+        HOST_BITS_PER_WIDE_INT.  */
+      len += HOST_BITS_PER_WIDE_INT - 1;
+
+      /* Ensure we can represent the largest negative number.  */
+      len += 1;
+
+      len = len/HOST_BITS_PER_WIDE_INT * HOST_BITS_PER_WIDE_INT;
+
+      /* Cap the size to the size allowed by real.h.  */
+      if (len > realmax)
        {
-         high = ~high;
-         if (low == 0)
-           high += 1;
-         else
-           low = -low;
+         HOST_WIDE_INT cnt_l_z;
+         cnt_l_z = wi::clz (val);
+
+         if (maxbitlen - cnt_l_z > realmax)
+           {
+             e = maxbitlen - cnt_l_z - realmax;
+
+             /* This value is too large, we must shift it right to
+                preserve all the bits we can, and then bump the
+                exponent up by that amount.  */
+             val = wi::lrshift (val, e);
+           }
+         len = realmax;
        }
 
+      /* Clear out top bits so elt will work with precisions that aren't
+        a multiple of HOST_BITS_PER_WIDE_INT.  */
+      val = wide_int::from (val, len, sgn);
+      len = len / HOST_BITS_PER_WIDE_INT;
+
+      SET_REAL_EXP (r, len * HOST_BITS_PER_WIDE_INT + e);
+
+      j = SIGSZ - 1;
       if (HOST_BITS_PER_LONG == HOST_BITS_PER_WIDE_INT)
-       {
-         r->sig[SIGSZ-1] = high;
-         r->sig[SIGSZ-2] = low;
-       }
+       for (i = len - 1; i >= 0; i--)
+         {
+           r->sig[j--] = val.elt (i);
+           if (j < 0)
+             break;
+         }
       else
        {
          gcc_assert (HOST_BITS_PER_LONG*2 == HOST_BITS_PER_WIDE_INT);
-         r->sig[SIGSZ-1] = high >> (HOST_BITS_PER_LONG - 1) >> 1;
-         r->sig[SIGSZ-2] = high;
-         r->sig[SIGSZ-3] = low >> (HOST_BITS_PER_LONG - 1) >> 1;
-         r->sig[SIGSZ-4] = low;
+         for (i = len - 1; i >= 0; i--)
+           {
+             HOST_WIDE_INT e = val.elt (i);
+             r->sig[j--] = e >> (HOST_BITS_PER_LONG - 1) >> 1;
+             if (j < 0)
+               break;
+             r->sig[j--] = e;
+             if (j < 0)
+               break;
+           }
        }
 
       normalize (r);
@@ -2238,7 +2286,7 @@ ten_to_ptwo (int n)
          for (i = 0; i < n; ++i)
            t *= t;
 
-         real_from_integer (&tens[n], VOIDmode, t, 0, 1);
+         real_from_integer (&tens[n], VOIDmode, t, UNSIGNED);
        }
       else
        {
@@ -2277,7 +2325,7 @@ real_digit (int n)
   gcc_assert (n <= 9);
 
   if (n > 0 && num[n].cl == rvc_zero)
-    real_from_integer (&num[n], VOIDmode, n, 0, 1);
+    real_from_integer (&num[n], VOIDmode, n, UNSIGNED);
 
   return &num[n];
 }
diff --git a/gcc/real.h b/gcc/real.h
index c4e036e..23908c9 100644
--- a/gcc/real.h
+++ b/gcc/real.h
@@ -21,6 +21,9 @@
 #define GCC_REAL_H
 
 #include "machmode.h"
+#include "signop.h"
+#include "wide-int.h"
+#include "insn-modes.h"
 
 /* An expanded form of the represented number.  */
 
@@ -267,8 +270,6 @@ extern void real_to_hexadecimal (char *, const 
REAL_VALUE_TYPE *,
 
 /* Render R as an integer.  */
 extern HOST_WIDE_INT real_to_integer (const REAL_VALUE_TYPE *);
-extern void real_to_integer2 (HOST_WIDE_INT *, HOST_WIDE_INT *,
-                             const REAL_VALUE_TYPE *);
 
 /* Initialize R from a decimal or hexadecimal string.  Return -1 if
    the value underflows, +1 if overflows, and 0 otherwise.  */
@@ -276,10 +277,6 @@ extern int real_from_string (REAL_VALUE_TYPE *, const char 
*);
 /* Wrapper to allow different internal representation for decimal floats. */
 extern void real_from_string3 (REAL_VALUE_TYPE *, const char *, enum 
machine_mode);
 
-/* Initialize R from an integer pair HIGH/LOW.  */
-extern void real_from_integer (REAL_VALUE_TYPE *, enum machine_mode,
-                              unsigned HOST_WIDE_INT, HOST_WIDE_INT, int);
-
 extern long real_to_target_fmt (long *, const REAL_VALUE_TYPE *,
                                const struct real_format *);
 extern long real_to_target (long *, const REAL_VALUE_TYPE *, enum 
machine_mode);
@@ -361,12 +358,6 @@ extern const struct real_format arm_half_format;
 #define REAL_VALUE_TO_TARGET_SINGLE(IN, OUT) \
   ((OUT) = real_to_target (NULL, &(IN), mode_for_size (32, MODE_FLOAT, 0)))
 
-#define REAL_VALUE_FROM_INT(r, lo, hi, mode) \
-  real_from_integer (&(r), mode, lo, hi, 0)
-
-#define REAL_VALUE_FROM_UNSIGNED_INT(r, lo, hi, mode) \
-  real_from_integer (&(r), mode, lo, hi, 1)
-
 /* Real values to IEEE 754 decimal floats.  */
 
 /* IN is a REAL_VALUE_TYPE.  OUT is an array of longs.  */
@@ -383,9 +374,6 @@ extern const struct real_format arm_half_format;
 extern REAL_VALUE_TYPE real_value_truncate (enum machine_mode,
                                            REAL_VALUE_TYPE);
 
-#define REAL_VALUE_TO_INT(plow, phigh, r) \
-  real_to_integer2 (plow, phigh, &(r))
-
 extern REAL_VALUE_TYPE real_value_negate (const REAL_VALUE_TYPE *);
 extern REAL_VALUE_TYPE real_value_abs (const REAL_VALUE_TYPE *);
 
@@ -485,4 +473,12 @@ extern bool real_isinteger (const REAL_VALUE_TYPE *c, enum 
machine_mode mode);
    number, (1 - b**-p) * b**emax for a given FP format FMT as a hex
    float string.  BUF must be large enough to contain the result.  */
 extern void get_max_float (const struct real_format *, char *, size_t);
+
+#ifndef GENERATOR_FILE
+/* real related routines.  */
+extern wide_int real_to_integer (const REAL_VALUE_TYPE *, bool *, int);
+extern void real_from_integer (REAL_VALUE_TYPE *, enum machine_mode,
+                              const wide_int_ref &, signop);
+#endif
+
 #endif /* ! GCC_REAL_H */

Reply via email to