gdb: Fix build failure with GCC 7
[deliverable/binutils-gdb.git] / gdb / doublest.c
index 2a118a333f2b2a011fdae178f1dd226bbda70658..e464177bcc77767b06935cbfc7adc32966f90488 100644 (file)
@@ -1,8 +1,6 @@
 /* Floating point routines for GDB, the GNU debugger.
 
-   Copyright (C) 1986, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996,
-   1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2007, 2008, 2009, 2010,
-   2011 Free Software Foundation, Inc.
+   Copyright (C) 1986-2017 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
 #include "defs.h"
 #include "doublest.h"
 #include "floatformat.h"
-#include "gdb_assert.h"
-#include "gdb_string.h"
 #include "gdbtypes.h"
 #include <math.h>              /* ldexp */
+#include <algorithm>
 
 /* The odds that CHAR_BIT will be anything but 8 are low enough that I'm not
    going to bother with trying to muck around with whether it is defined in
@@ -60,11 +57,11 @@ get_field (const bfd_byte *data, enum floatformat_byteorders order,
     {
       /* We start counting from the other end (i.e, from the high bytes
         rather than the low bytes).  As such, we need to be concerned
-        with what happens if bit 0 doesn't start on a byte boundary. 
+        with what happens if bit 0 doesn't start on a byte boundary.
         I.e, we need to properly handle the case where total_len is
         not evenly divisible by 8.  So we compute ``excess'' which
         represents the number of bits from the end of our starting
-        byte needed to get to bit 0. */
+        byte needed to get to bit 0.  */
       int excess = FLOATFORMAT_CHAR_BIT - (total_len % FLOATFORMAT_CHAR_BIT);
 
       cur_byte = (total_len / FLOATFORMAT_CHAR_BIT) 
@@ -104,7 +101,7 @@ get_field (const bfd_byte *data, enum floatformat_byteorders order,
        }
     }
   if (len < sizeof(result) * FLOATFORMAT_CHAR_BIT)
-    /* Mask out bits which are not part of the field */
+    /* Mask out bits which are not part of the field */
     result &= ((1UL << len) - 1);
   return result;
 }
@@ -176,7 +173,7 @@ convert_floatformat_to_doublest (const struct floatformat *fmt,
   unsigned long mant;
   unsigned int mant_bits, mant_off;
   int mant_bits_left;
-  int special_exponent;                /* It's a NaN, denorm or zero */
+  int special_exponent;                /* It's a NaN, denorm or zero */
   enum floatformat_byteorders order;
   unsigned char newfrom[FLOATFORMAT_LARGEST_BYTES];
   enum float_kind kind;
@@ -187,12 +184,13 @@ convert_floatformat_to_doublest (const struct floatformat *fmt,
   /* For non-numbers, reuse libiberty's logic to find the correct
      format.  We do not lose any precision in this case by passing
      through a double.  */
-  kind = floatformat_classify (fmt, from);
+  kind = floatformat_classify (fmt, (const bfd_byte *) from);
   if (kind == float_infinite || kind == float_nan)
     {
       double dto;
 
-      floatformat_to_double (fmt, from, &dto);
+      floatformat_to_double (fmt->split_half ? fmt->split_half : fmt,
+                            from, &dto);
       *to = (DOUBLEST) dto;
       return;
     }
@@ -233,17 +231,17 @@ convert_floatformat_to_doublest (const struct floatformat *fmt,
 
   special_exponent = exponent == 0 || exponent == fmt->exp_nan;
 
-  /* Don't bias NaNs. Use minimum exponent for denorms. For simplicity,
-     we don't check for zero as the exponent doesn't matter.  Note the cast
-     to int; exp_bias is unsigned, so it's important to make sure the
-     operation is done in signed arithmetic.  */
+  /* Don't bias NaNs.  Use minimum exponent for denorms.  For
+     simplicity, we don't check for zero as the exponent doesn't matter.
+     Note the cast to int; exp_bias is unsigned, so it's important to
+     make sure the operation is done in signed arithmetic.  */
   if (!special_exponent)
     exponent -= fmt->exp_bias;
   else if (exponent == 0)
     exponent = 1 - fmt->exp_bias;
 
   /* Build the result algebraically.  Might go infinite, underflow, etc;
-     who cares. */
+     who cares.  */
 
 /* If this format uses a hidden bit, explicitly add it in now.  Otherwise,
    increment the exponent by one to account for the integer bit.  */
@@ -258,7 +256,7 @@ convert_floatformat_to_doublest (const struct floatformat *fmt,
 
   while (mant_bits_left > 0)
     {
-      mant_bits = min (mant_bits_left, 32);
+      mant_bits = std::min (mant_bits_left, 32);
 
       mant = get_field (ufrom, order, fmt->totalsize, mant_off, mant_bits);
 
@@ -274,10 +272,6 @@ convert_floatformat_to_doublest (const struct floatformat *fmt,
   *to = dto;
 }
 \f
-static void put_field (unsigned char *, enum floatformat_byteorders,
-                      unsigned int,
-                      unsigned int, unsigned int, unsigned long);
-
 /* Set a field which starts at START and is LEN bytes long.  DATA and
    TOTAL_LEN are the thing we are extracting it from, in byteorder ORDER.  */
 static void
@@ -342,59 +336,12 @@ put_field (unsigned char *data, enum floatformat_byteorders order,
     }
 }
 
-#ifdef HAVE_LONG_DOUBLE
-/* Return the fractional part of VALUE, and put the exponent of VALUE in *EPTR.
-   The range of the returned value is >= 0.5 and < 1.0.  This is equivalent to
-   frexp, but operates on the long double data type.  */
-
-static long double ldfrexp (long double value, int *eptr);
-
-static long double
-ldfrexp (long double value, int *eptr)
-{
-  long double tmp;
-  int exp;
-
-  /* Unfortunately, there are no portable functions for extracting the
-     exponent of a long double, so we have to do it iteratively by
-     multiplying or dividing by two until the fraction is between 0.5
-     and 1.0.  */
-
-  if (value < 0.0l)
-    value = -value;
-
-  tmp = 1.0l;
-  exp = 0;
-
-  if (value >= tmp)            /* Value >= 1.0 */
-    while (value >= tmp)
-      {
-       tmp *= 2.0l;
-       exp++;
-      }
-  else if (value != 0.0l)      /* Value < 1.0  and > 0.0 */
-    {
-      while (value < tmp)
-       {
-         tmp /= 2.0l;
-         exp--;
-       }
-      tmp *= 2.0l;
-      exp++;
-    }
-
-  *eptr = exp;
-  return value / tmp;
-}
-#endif /* HAVE_LONG_DOUBLE */
-
-
 /* The converse: convert the DOUBLEST *FROM to an extended float and
    store where TO points.  Neither FROM nor TO have any alignment
    restrictions.  */
 
 static void
-convert_doublest_to_floatformat (CONST struct floatformat *fmt,
+convert_doublest_to_floatformat (const struct floatformat *fmt,
                                 const DOUBLEST *from, void *to)
 {
   DOUBLEST dfrom;
@@ -413,8 +360,7 @@ convert_doublest_to_floatformat (CONST struct floatformat *fmt,
     uto = newto;
 
   memcpy (&dfrom, from, sizeof (dfrom));
-  memset (uto, 0, (fmt->totalsize + FLOATFORMAT_CHAR_BIT - 1) 
-                    / FLOATFORMAT_CHAR_BIT);
+  memset (uto, 0, floatformat_totalsize_bytes (fmt));
 
   if (fmt->split_half)
     {
@@ -447,9 +393,9 @@ convert_doublest_to_floatformat (CONST struct floatformat *fmt,
       /* From is NaN */
       put_field (uto, order, fmt->totalsize, fmt->exp_start,
                 fmt->exp_len, fmt->exp_nan);
-      /* Be sure it's not infinity, but NaN value is irrel */
+      /* Be sure it's not infinity, but NaN value is irrel */
       put_field (uto, order, fmt->totalsize, fmt->man_start,
-                32, 1);
+                fmt->man_len, 1);
       goto finalize_byteorder;
     }
 
@@ -460,7 +406,7 @@ convert_doublest_to_floatformat (CONST struct floatformat *fmt,
       dfrom = -dfrom;
     }
 
-  if (dfrom + dfrom == dfrom && dfrom != 0.0)  /* Result is Infinity */
+  if (dfrom + dfrom == dfrom && dfrom != 0.0)  /* Result is Infinity */
     {
       /* Infinity exponent is same as NaN's.  */
       put_field (uto, order, fmt->totalsize, fmt->exp_start,
@@ -472,11 +418,33 @@ convert_doublest_to_floatformat (CONST struct floatformat *fmt,
     }
 
 #ifdef HAVE_LONG_DOUBLE
-  mant = ldfrexp (dfrom, &exponent);
+  mant = frexpl (dfrom, &exponent);
 #else
   mant = frexp (dfrom, &exponent);
 #endif
 
+  if (exponent + fmt->exp_bias <= 0)
+    {
+      /* The value is too small to be expressed in the destination
+        type (not enough bits in the exponent.  Treat as 0.  */
+      put_field (uto, order, fmt->totalsize, fmt->exp_start,
+                fmt->exp_len, 0);
+      put_field (uto, order, fmt->totalsize, fmt->man_start,
+                fmt->man_len, 0);
+      goto finalize_byteorder;
+    }
+
+  if (exponent + fmt->exp_bias >= (1 << fmt->exp_len))
+    {
+      /* The value is too large to fit into the destination.
+        Treat as infinity.  */
+      put_field (uto, order, fmt->totalsize, fmt->exp_start,
+                fmt->exp_len, fmt->exp_nan);
+      put_field (uto, order, fmt->totalsize, fmt->man_start,
+                fmt->man_len, 0);
+      goto finalize_byteorder;
+    }
+
   put_field (uto, order, fmt->totalsize, fmt->exp_start, fmt->exp_len,
             exponent + fmt->exp_bias - 1);
 
@@ -545,6 +513,11 @@ floatformat_is_negative (const struct floatformat *fmt,
   gdb_assert (fmt->totalsize
              <= FLOATFORMAT_LARGEST_BYTES * FLOATFORMAT_CHAR_BIT);
 
+  /* An IBM long double (a two element array of double) always takes the
+     sign of the first double.  */
+  if (fmt->split_half)
+    fmt = fmt->split_half;
+
   order = floatformat_normalize_byteorder (fmt, uval, newfrom);
 
   if (order != fmt->byteorder)
@@ -571,6 +544,13 @@ floatformat_classify (const struct floatformat *fmt,
   gdb_assert (fmt->totalsize
              <= FLOATFORMAT_LARGEST_BYTES * FLOATFORMAT_CHAR_BIT);
 
+  /* An IBM long double (a two element array of double) can be classified
+     by looking at the first double.  inf and nan are specified as
+     ignoring the second double.  zero and subnormal will always have
+     the second double 0.0 if the long double is correctly rounded.  */
+  if (fmt->split_half)
+    fmt = fmt->split_half;
+
   order = floatformat_normalize_byteorder (fmt, uval, newfrom);
 
   if (order != fmt->byteorder)
@@ -585,7 +565,7 @@ floatformat_classify (const struct floatformat *fmt,
   mant_zero = 1;
   while (mant_bits_left > 0)
     {
-      mant_bits = min (mant_bits_left, 32);
+      mant_bits = std::min (mant_bits_left, 32);
 
       mant = get_field (uval, order, fmt->totalsize, mant_off, mant_bits);
 
@@ -653,6 +633,16 @@ floatformat_mantissa (const struct floatformat *fmt,
   gdb_assert (fmt->totalsize
              <= FLOATFORMAT_LARGEST_BYTES * FLOATFORMAT_CHAR_BIT);
 
+  /* For IBM long double (a two element array of double), return the
+     mantissa of the first double.  The problem with returning the
+     actual mantissa from both doubles is that there can be an
+     arbitrary number of implied 0's or 1's between the mantissas
+     of the first and second double.  In any case, this function
+     is only used for dumping out nans, and a nan is specified to
+     ignore the value in the second double.  */
+  if (fmt->split_half)
+    fmt = fmt->split_half;
+
   order = floatformat_normalize_byteorder (fmt, uval, newfrom);
 
   if (order != fmt->byteorder)
@@ -696,37 +686,55 @@ floatformat_mantissa (const struct floatformat *fmt,
    If the host and target formats agree, we just copy the raw data
    into the appropriate type of variable and return, letting the host
    increase precision as necessary.  Otherwise, we call the conversion
-   routine and let it do the dirty work.  */
+   routine and let it do the dirty work.  Note that even if the target
+   and host floating-point formats match, the length of the types
+   might still be different, so the conversion routines must make sure
+   to not overrun any buffers.  For example, on x86, long double is
+   the 80-bit extended precision type on both 32-bit and 64-bit ABIs,
+   but by default it is stored as 12 bytes on 32-bit, and 16 bytes on
+   64-bit, for alignment reasons.  See comment in store_typed_floating
+   for a discussion about zeroing out remaining bytes in the target
+   buffer.  */
 
 static const struct floatformat *host_float_format = GDB_HOST_FLOAT_FORMAT;
 static const struct floatformat *host_double_format = GDB_HOST_DOUBLE_FORMAT;
 static const struct floatformat *host_long_double_format
   = GDB_HOST_LONG_DOUBLE_FORMAT;
 
+/* See doublest.h.  */
+
+size_t
+floatformat_totalsize_bytes (const struct floatformat *fmt)
+{
+  return ((fmt->totalsize + FLOATFORMAT_CHAR_BIT - 1)
+         / FLOATFORMAT_CHAR_BIT);
+}
+
 void
 floatformat_to_doublest (const struct floatformat *fmt,
                         const void *in, DOUBLEST *out)
 {
   gdb_assert (fmt != NULL);
+
   if (fmt == host_float_format)
     {
-      float val;
+      float val = 0;
 
-      memcpy (&val, in, sizeof (val));
+      memcpy (&val, in, floatformat_totalsize_bytes (fmt));
       *out = val;
     }
   else if (fmt == host_double_format)
     {
-      double val;
+      double val = 0;
 
-      memcpy (&val, in, sizeof (val));
+      memcpy (&val, in, floatformat_totalsize_bytes (fmt));
       *out = val;
     }
   else if (fmt == host_long_double_format)
     {
-      long double val;
+      long double val = 0;
 
-      memcpy (&val, in, sizeof (val));
+      memcpy (&val, in, floatformat_totalsize_bytes (fmt));
       *out = val;
     }
   else
@@ -738,86 +746,44 @@ floatformat_from_doublest (const struct floatformat *fmt,
                           const DOUBLEST *in, void *out)
 {
   gdb_assert (fmt != NULL);
+
   if (fmt == host_float_format)
     {
       float val = *in;
 
-      memcpy (out, &val, sizeof (val));
+      memcpy (out, &val, floatformat_totalsize_bytes (fmt));
     }
   else if (fmt == host_double_format)
     {
       double val = *in;
 
-      memcpy (out, &val, sizeof (val));
+      memcpy (out, &val, floatformat_totalsize_bytes (fmt));
     }
   else if (fmt == host_long_double_format)
     {
       long double val = *in;
 
-      memcpy (out, &val, sizeof (val));
+      memcpy (out, &val, floatformat_totalsize_bytes (fmt));
     }
   else
     convert_doublest_to_floatformat (fmt, in, out);
 }
 
 \f
-/* Return a floating-point format for a floating-point variable of
-   length LEN.  If no suitable floating-point format is found, an
-   error is thrown.
-
-   We need this functionality since information about the
-   floating-point format of a type is not always available to GDB; the
-   debug information typically only tells us the size of a
-   floating-point type.
-
-   FIXME: kettenis/2001-10-28: In many places, particularly in
-   target-dependent code, the format of floating-point types is known,
-   but not passed on by GDB.  This should be fixed.  */
-
-static const struct floatformat *
-floatformat_from_length (struct gdbarch *gdbarch, int len)
-{
-  const struct floatformat *format;
-
-  if (len * TARGET_CHAR_BIT == gdbarch_half_bit (gdbarch))
-    format = gdbarch_half_format (gdbarch)
-              [gdbarch_byte_order (gdbarch)];
-  else if (len * TARGET_CHAR_BIT == gdbarch_float_bit (gdbarch))
-    format = gdbarch_float_format (gdbarch)
-              [gdbarch_byte_order (gdbarch)];
-  else if (len * TARGET_CHAR_BIT == gdbarch_double_bit (gdbarch))
-    format = gdbarch_double_format (gdbarch)
-              [gdbarch_byte_order (gdbarch)];
-  else if (len * TARGET_CHAR_BIT == gdbarch_long_double_bit (gdbarch))
-    format = gdbarch_long_double_format (gdbarch)
-              [gdbarch_byte_order (gdbarch)];
-  /* On i386 the 'long double' type takes 96 bits,
-     while the real number of used bits is only 80,
-     both in processor and in memory.  
-     The code below accepts the real bit size.  */ 
-  else if ((gdbarch_long_double_format (gdbarch) != NULL)
-          && (len * TARGET_CHAR_BIT
-               == gdbarch_long_double_format (gdbarch)[0]->totalsize))
-    format = gdbarch_long_double_format (gdbarch)
-              [gdbarch_byte_order (gdbarch)];
-  else
-    format = NULL;
-  if (format == NULL)
-    error (_("Unrecognized %d-bit floating-point type."),
-          len * TARGET_CHAR_BIT);
-  return format;
-}
+/* Return the floating-point format for a floating-point variable of
+   type TYPE.  */
 
 const struct floatformat *
 floatformat_from_type (const struct type *type)
 {
   struct gdbarch *gdbarch = get_type_arch (type);
+  const struct floatformat *fmt;
 
   gdb_assert (TYPE_CODE (type) == TYPE_CODE_FLT);
-  if (TYPE_FLOATFORMAT (type) != NULL)
-    return TYPE_FLOATFORMAT (type)[gdbarch_byte_order (gdbarch)];
-  else
-    return floatformat_from_length (gdbarch, TYPE_LENGTH (type));
+  gdb_assert (TYPE_FLOATFORMAT (type));
+  fmt = TYPE_FLOATFORMAT (type)[gdbarch_byte_order (gdbarch)];
+  gdb_assert (TYPE_LENGTH (type) >= floatformat_totalsize_bytes (fmt));
+  return fmt;
 }
 
 /* Extract a floating-point number of type TYPE from a target-order
@@ -896,7 +862,8 @@ convert_typed_floating (const void *from, const struct type *from_type,
          comment in store_typed_floating for a discussion about
          zeroing out remaining bytes in the target buffer.  */
       memset (to, 0, TYPE_LENGTH (to_type));
-      memcpy (to, from, min (TYPE_LENGTH (from_type), TYPE_LENGTH (to_type)));
+      memcpy (to, from, std::min (TYPE_LENGTH (from_type),
+                                 TYPE_LENGTH (to_type)));
     }
   else
     {
@@ -910,27 +877,3 @@ convert_typed_floating (const void *from, const struct type *from_type,
       floatformat_from_doublest (to_fmt, &d, to);
     }
 }
-
-const struct floatformat *floatformat_ieee_single[BFD_ENDIAN_UNKNOWN];
-const struct floatformat *floatformat_ieee_double[BFD_ENDIAN_UNKNOWN];
-const struct floatformat *floatformat_ieee_quad[BFD_ENDIAN_UNKNOWN];
-const struct floatformat *floatformat_arm_ext[BFD_ENDIAN_UNKNOWN];
-const struct floatformat *floatformat_ia64_spill[BFD_ENDIAN_UNKNOWN];
-
-extern void _initialize_doublest (void);
-
-extern void
-_initialize_doublest (void)
-{
-  floatformat_ieee_single[BFD_ENDIAN_LITTLE] = &floatformat_ieee_single_little;
-  floatformat_ieee_single[BFD_ENDIAN_BIG] = &floatformat_ieee_single_big;
-  floatformat_ieee_double[BFD_ENDIAN_LITTLE] = &floatformat_ieee_double_little;
-  floatformat_ieee_double[BFD_ENDIAN_BIG] = &floatformat_ieee_double_big;
-  floatformat_arm_ext[BFD_ENDIAN_LITTLE]
-    = &floatformat_arm_ext_littlebyte_bigword;
-  floatformat_arm_ext[BFD_ENDIAN_BIG] = &floatformat_arm_ext_big;
-  floatformat_ia64_spill[BFD_ENDIAN_LITTLE] = &floatformat_ia64_spill_little;
-  floatformat_ia64_spill[BFD_ENDIAN_BIG] = &floatformat_ia64_spill_big;
-  floatformat_ieee_quad[BFD_ENDIAN_LITTLE] = &floatformat_ia64_quad_little;
-  floatformat_ieee_quad[BFD_ENDIAN_BIG] = &floatformat_ia64_quad_big;
-}
This page took 0.030529 seconds and 4 git commands to generate.