[PATCH] NaN detection patch

Mark Kettenis kettenis@wins.uva.nl
Wed Mar 7 08:10:00 GMT 2001


Since nobody objected, I checked in the attached patch.

Mark


Index: ChangeLog
from  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.

Index: defs.h
===================================================================
RCS file: /cvs/src/src/gdb/defs.h,v
retrieving revision 1.41
diff -u -p -r1.41 defs.h
--- defs.h 2001/03/07 02:57:08 1.41
+++ defs.h 2001/03/07 16:07:16
@@ -1124,8 +1124,12 @@ extern void floatformat_to_doublest (con
 				     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);
 
 /* On some machines there are bits in addresses which are not really
Index: utils.c
===================================================================
RCS file: /cvs/src/src/gdb/utils.c,v
retrieving revision 1.33
diff -u -p -r1.33 utils.c
--- utils.c 2001/03/07 02:57:08 1.33
+++ utils.c 2001/03/07 16:07:17
@@ -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"
@@ -2739,6 +2740,106 @@ floatformat_from_doublest (CONST struct 
 	  *swaphigh++ = tmp;
 	}
     }
+}
+
+/* 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. */
Index: valprint.c
===================================================================
RCS file: /cvs/src/src/gdb/valprint.c,v
retrieving revision 1.12
diff -u -p -r1.12 valprint.c
--- valprint.c 2001/03/07 02:57:08 1.12
+++ valprint.c 2001/03/07 16:07:17
@@ -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.  */
 
-	  /* 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 (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;
-	}
+  /* 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.  */
+
+  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 (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 ty
       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 ty
 #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
 }



More information about the Gdb-patches mailing list