* defs.h: Provide prototypes for floatformat_is_negative,
authorMark Kettenis <kettenis@gnu.org>
Wed, 7 Mar 2001 16:09:03 +0000 (16:09 +0000)
committerMark Kettenis <kettenis@gnu.org>
Wed, 7 Mar 2001 16:09:03 +0000 (16:09 +0000)
floatformat_is_nan and floatformat_mantissa.
* utils.c: Include "gdb_assert.h".
(floatformat_is_negative): New function.
(floatformat_is_nan): New function.
(floatformat_mantissa): New function.
* valprint.c: Include "floatformat.h".
(print_floating): Get rid of the Linux-specific
TARGET_ANALYZE_FLOATING macro and rewrite NaN detection with the
help these new functions.  Print NaN's in a format conforming to
ISO C99.

gdb/ChangeLog
gdb/defs.h
gdb/utils.c
gdb/valprint.c

index e3737d75602dcf1dbc9bf152b9779764040f5033..32e592f6a6481a933e4599213a35accde33e1876 100644 (file)
@@ -1,3 +1,17 @@
+2001-03-07  Mark Kettenis  <kettenis@gnu.org>
+
+       * defs.h: Provide prototypes for floatformat_is_negative,
+       floatformat_is_nan and floatformat_mantissa.
+       * utils.c: Include "gdb_assert.h".
+       (floatformat_is_negative): New function.
+       (floatformat_is_nan): New function.
+       (floatformat_mantissa): New function.
+       * valprint.c: Include "floatformat.h".
+       (print_floating): Get rid of the Linux-specific
+       TARGET_ANALYZE_FLOATING macro and rewrite NaN detection with the
+       help these new functions.  Print NaN's in a format conforming to
+       ISO C99.
+
 2001-03-07  Eli Zaretskii  <eliz@is.elta.co.il>
 
        * top.c (init_main): Make `set history file name' complete on file
index 6974fe285079fb1a1975bccbab12260c2abb3876..c6a4637c4d610b84750e18fd5a5f40596eaf49ca 100644 (file)
@@ -1124,8 +1124,12 @@ extern void floatformat_to_doublest (const struct floatformat *,
                                     char *, DOUBLEST *);
 extern void floatformat_from_doublest (const struct floatformat *,
                                       DOUBLEST *, char *);
-extern DOUBLEST extract_floating (void *, int);
 
+extern int floatformat_is_negative (const struct floatformat *, char *);
+extern int floatformat_is_nan (const struct floatformat *, char *);
+extern char *floatformat_mantissa (const struct floatformat *, char *);
+
+extern DOUBLEST extract_floating (void *, int);
 extern void store_floating (void *, int, DOUBLEST);
 \f
 /* On some machines there are bits in addresses which are not really
index df6046a93e66d3b0f4ec939551de63a8f40c8a28..5ece78ded48ffbd8f5e1637184b0d2d2220efe79 100644 (file)
@@ -21,6 +21,7 @@
    Boston, MA 02111-1307, USA.  */
 
 #include "defs.h"
+#include "gdb_assert.h"
 #include <ctype.h>
 #include "gdb_string.h"
 #include "event-top.h"
@@ -2741,6 +2742,106 @@ floatformat_from_doublest (CONST struct floatformat *fmt, DOUBLEST *from,
     }
 }
 
+/* Check if VAL (which is assumed to be a floating point number whose
+   format is described by FMT) is negative.  */
+
+int
+floatformat_is_negative (const struct floatformat *fmt, char *val)
+{
+  unsigned char *uval = (unsigned char *) val;
+
+  return get_field (uval, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1);
+}
+
+/* Check if VAL is "not a number" (NaN) for FMT.  */
+
+int
+floatformat_is_nan (const struct floatformat *fmt, char *val)
+{
+  unsigned char *uval = (unsigned char *) val;
+  long exponent;
+  unsigned long mant;
+  unsigned int mant_bits, mant_off;
+  int mant_bits_left;
+
+  if (! fmt->exp_nan)
+    return 0;
+
+  exponent = get_field (uval, fmt->byteorder, fmt->totalsize,
+                       fmt->exp_start, fmt->exp_len);
+
+  if (exponent != fmt->exp_nan)
+    return 0;
+
+  mant_bits_left = fmt->man_len;
+  mant_off = fmt->man_start;
+
+  while (mant_bits_left > 0)
+    {
+      mant_bits = min (mant_bits_left, 32);
+
+      mant = get_field (uval, fmt->byteorder, fmt->totalsize,
+                       mant_off, mant_bits);
+
+      /* If there is an explicit integer bit, mask it off.  */
+      if (mant_off == fmt->man_start
+         && fmt->intbit == floatformat_intbit_yes)
+       mant &= ~(1 << (mant_bits - 1));
+
+      if (mant)
+       return 1;
+
+      mant_off += mant_bits;
+      mant_bits_left -= mant_bits;
+    }
+
+  return 0;
+}
+
+/* Convert the mantissa of VAL (which is assumed to be a floating
+   point number whose format is described by FMT) into a hexadecimal
+   and store it in a static string.  Return a pointer to that string.  */
+
+char *
+floatformat_mantissa (const struct floatformat *fmt, char *val)
+{
+  unsigned char *uval = (unsigned char *) val;
+  unsigned long mant;
+  unsigned int mant_bits, mant_off;
+  int mant_bits_left;
+  static char res[50];
+  char buf[9];
+
+  /* Make sure we have enough room to store the mantissa.  */
+  gdb_assert (sizeof res > ((fmt->man_len + 7) / 8) * 2);
+
+  mant_off = fmt->man_start;
+  mant_bits_left = fmt->man_len;
+  mant_bits = (mant_bits_left % 32) > 0 ? mant_bits_left % 32 : 32;
+
+  mant = get_field (uval, fmt->byteorder, fmt->totalsize,
+                   mant_off, mant_bits);
+
+  sprintf (res, "%lx", mant);
+
+  mant_off += mant_bits;
+  mant_bits_left -= mant_bits;
+  
+  while (mant_bits_left > 0)
+    {
+      mant = get_field (uval, fmt->byteorder, fmt->totalsize,
+                       mant_off, 32);
+
+      sprintf (buf, "%08lx", mant);
+      strcat (res, buf);
+
+      mant_off += 32;
+      mant_bits_left -= 32;
+    }
+
+  return res;
+}
+
 /* print routines to handle variable size regs, etc. */
 
 /* temporary storage using circular buffer */
index 2a80b9c7c0ab33e735f31c4391088f458329d33f..ccd4542eb07e7b60daee54cae4018b4d9dcabf48 100644 (file)
@@ -32,6 +32,7 @@
 #include "language.h"
 #include "annotate.h"
 #include "valprint.h"
+#include "floatformat.h"
 
 #include <errno.h>
 
@@ -538,92 +539,39 @@ longest_to_int (LONGEST arg)
   return (rtnval);
 }
 
-
-/* Print a floating point value of type TYPE, pointed to in GDB by VALADDR,
-   on STREAM.  */
+/* Print a floating point value of type TYPE, pointed to in GDB by
+   VALADDR, on STREAM.  */
 
 void
 print_floating (char *valaddr, struct type *type, struct ui_file *stream)
 {
   DOUBLEST doub;
   int inv;
+  const struct floatformat *fmt = &floatformat_unknown;
   unsigned len = TYPE_LENGTH (type);
 
-  /* Check for NaN's.  Note that this code does not depend on us being
-     on an IEEE conforming system.  It only depends on the target
-     machine using IEEE representation.  This means (a)
-     cross-debugging works right, and (2) IEEE_FLOAT can (and should)
-     be non-zero for systems like the 68881, which uses IEEE
-     representation, but is not IEEE conforming.  */
-  if (IEEE_FLOAT)
-    {
-      unsigned long low, high;
-      /* Is the sign bit 0?  */
-      int nonnegative;
-      /* Is it is a NaN (i.e. the exponent is all ones and
-        the fraction is nonzero)?  */
-      int is_nan;
-
-      /* For lint, initialize these two variables to suppress warning: */
-      low = high = nonnegative = 0;
-      if (len == 4)
-       {
-         /* It's single precision.  */
-         /* Assume that floating point byte order is the same as
-            integer byte order.  */
-         low = extract_unsigned_integer (valaddr, 4);
-         nonnegative = ((low & 0x80000000) == 0);
-         is_nan = ((((low >> 23) & 0xFF) == 0xFF)
-                   && 0 != (low & 0x7FFFFF));
-         low &= 0x7fffff;
-         high = 0;
-       }
-      else if (len == 8)
-       {
-         /* It's double precision.  Get the high and low words.  */
+  /* FIXME: kettenis/2001-01-20: The check for IEEE_FLOAT is probably
+     still necessary since GDB by default assumes that the target uses
+     the IEEE 754 representation for its floats and doubles.  Of
+     course this is all crock and should be cleaned up.  */
 
-         /* Assume that floating point byte order is the same as
-            integer byte order.  */
-         if (TARGET_BYTE_ORDER == BIG_ENDIAN)
-           {
-             low = extract_unsigned_integer (valaddr + 4, 4);
-             high = extract_unsigned_integer (valaddr, 4);
-           }
-         else
-           {
-             low = extract_unsigned_integer (valaddr, 4);
-             high = extract_unsigned_integer (valaddr + 4, 4);
-           }
-         nonnegative = ((high & 0x80000000) == 0);
-         is_nan = (((high >> 20) & 0x7ff) == 0x7ff
-                   && !((((high & 0xfffff) == 0)) && (low == 0)));
-         high &= 0xfffff;
-       }
-      else
-       {
-#ifdef TARGET_ANALYZE_FLOATING
-         TARGET_ANALYZE_FLOATING;
-#else
-         /* Extended.  We can't detect extended NaNs for this target.
-            Also note that currently extendeds get nuked to double in
-            REGISTER_CONVERTIBLE.  */
-         is_nan = 0;
-#endif 
-       }
+  if (len == TARGET_FLOAT_BIT / TARGET_CHAR_BIT && IEEE_FLOAT)
+    fmt = TARGET_FLOAT_FORMAT;
+  else if (len == TARGET_DOUBLE_BIT / TARGET_CHAR_BIT && IEEE_FLOAT)
+    fmt = TARGET_DOUBLE_FORMAT;
+  else if (len == TARGET_LONG_DOUBLE_BIT / TARGET_CHAR_BIT)
+    fmt = TARGET_LONG_DOUBLE_FORMAT;
 
-      if (is_nan)
-       {
-         /* The meaning of the sign and fraction is not defined by IEEE.
-            But the user might know what they mean.  For example, they
-            (in an implementation-defined manner) distinguish between
-            signaling and quiet NaN's.  */
-         if (high)
-           fprintf_filtered (stream, "-NaN(0x%lx%.8lx)" + !!nonnegative,
-                             high, low);
-         else
-           fprintf_filtered (stream, "-NaN(0x%lx)" + nonnegative, low);
-         return;
-       }
+  if (floatformat_is_nan (fmt, valaddr))
+    {
+      if (floatformat_is_negative (fmt, valaddr))
+       fprintf_filtered (stream, "-");
+      fprintf_filtered (stream, "nan(");
+      fprintf_filtered (stream, local_hex_format_prefix ());
+      fprintf_filtered (stream, floatformat_mantissa (fmt, valaddr));
+      fprintf_filtered (stream, local_hex_format_suffix ());
+      fprintf_filtered (stream, ")");
+      return;
     }
 
   doub = unpack_double (type, valaddr, &inv);
@@ -633,6 +581,9 @@ print_floating (char *valaddr, struct type *type, struct ui_file *stream)
       return;
     }
 
+  /* FIXME: kettenis/2001-01-20: The following code makes too much
+     assumptions about the host and target floating point format.  */
+
   if (len < sizeof (double))
       fprintf_filtered (stream, "%.9g", (double) doub);
   else if (len == sizeof (double))
@@ -641,7 +592,8 @@ print_floating (char *valaddr, struct type *type, struct ui_file *stream)
 #ifdef PRINTF_HAS_LONG_DOUBLE
     fprintf_filtered (stream, "%.35Lg", doub);
 #else
-    /* This at least wins with values that are representable as doubles */
+    /* This at least wins with values that are representable as
+       doubles.  */
     fprintf_filtered (stream, "%.17g", (double) doub);
 #endif
 }