This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
[rfc] Improve infinity and NaN support
- From: Daniel Jacobowitz <drow at false dot org>
- To: gdb-patches at sourceware dot org
- Date: Mon, 19 Mar 2007 11:57:41 -0400
- Subject: [rfc] Improve infinity and NaN support
This patch is along the same lines as a patch posted by Dwayne Grant
McConnell <dgm69@us.ibm.com> in August 2005. It improves the handling
of floating point numbers in two ways:
- Infinity is more reliably printed as inf.
- Infinity and NaN are converted to host DOUBLEST infinity and NaN.
While we're still being rather sloppy in implementing target
floating point arithmetic, this fixes the most obvious problem.
Any comments? I'm sure my new test will fail on some platforms,
e.g. vax; I do not see a better way than listing insufficiently IEEE
targets in the .exp file.
--
Daniel Jacobowitz
CodeSourcery
2007-03-19 Daniel Jacobowitz <dan@codesourcery.com>
* doublest.c (convert_floatformat_to_doublest): Use
floatformat_classify.
(floatformat_is_nan): Rename to...
(floatformat_classify): ...this. Return more information.
* doublest.h (enum float_kind): New.
(floatformat_is_nan): Replace prototype...
(floatformat_classify): ...with this one.
* valprint.c (print_floating): Use floatformat_classify. Handle
infinity.
* gdb.base/infnan.c, gdb.base/infnan.exp: New files.
Index: doublest.c
===================================================================
RCS file: /cvs/src/src/gdb/doublest.c,v
retrieving revision 1.30
diff -u -p -r1.30 doublest.c
--- doublest.c 29 Jan 2007 17:31:05 -0000 1.30
+++ doublest.c 19 Mar 2007 15:30:48 -0000
@@ -180,10 +180,23 @@ convert_floatformat_to_doublest (const s
int special_exponent; /* It's a NaN, denorm or zero */
enum floatformat_byteorders order;
unsigned char newfrom[FLOATFORMAT_LARGEST_BYTES];
+ enum float_kind kind;
gdb_assert (fmt->totalsize
<= FLOATFORMAT_LARGEST_BYTES * FLOATFORMAT_CHAR_BIT);
+ /* 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);
+ if (kind == float_infinite || kind == float_nan)
+ {
+ double dto;
+ floatformat_to_double (fmt, from, &dto);
+ *to = (DOUBLEST) dto;
+ return;
+ }
+
order = floatformat_normalize_byteorder (fmt, ufrom, newfrom);
if (order != fmt->byteorder)
@@ -495,9 +508,9 @@ floatformat_is_negative (const struct fl
/* Check if VAL is "not a number" (NaN) for FMT. */
-int
-floatformat_is_nan (const struct floatformat *fmt,
- const bfd_byte *uval)
+enum float_kind
+floatformat_classify (const struct floatformat *fmt,
+ const bfd_byte *uval)
{
long exponent;
unsigned long mant;
@@ -505,6 +518,7 @@ floatformat_is_nan (const struct floatfo
int mant_bits_left;
enum floatformat_byteorders order;
unsigned char newfrom[FLOATFORMAT_LARGEST_BYTES];
+ int mant_zero;
gdb_assert (fmt != NULL);
gdb_assert (fmt->totalsize
@@ -515,18 +529,13 @@ floatformat_is_nan (const struct floatfo
if (order != fmt->byteorder)
uval = newfrom;
- if (! fmt->exp_nan)
- return 0;
-
exponent = get_field (uval, order, 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;
+ mant_zero = 1;
while (mant_bits_left > 0)
{
mant_bits = min (mant_bits_left, 32);
@@ -539,13 +548,40 @@ floatformat_is_nan (const struct floatfo
mant &= ~(1 << (mant_bits - 1));
if (mant)
- return 1;
+ {
+ mant_zero = 0;
+ break;
+ }
mant_off += mant_bits;
mant_bits_left -= mant_bits;
}
- return 0;
+ /* If exp_nan is not set, assume that inf, NaN, and subnormals are not
+ supported. */
+ if (! fmt->exp_nan)
+ {
+ if (mant_zero)
+ return float_zero;
+ else
+ return float_normal;
+ }
+
+ if (exponent == 0 && !mant_zero)
+ return float_subnormal;
+
+ if (exponent == fmt->exp_nan)
+ {
+ if (mant_zero)
+ return float_infinite;
+ else
+ return float_nan;
+ }
+
+ if (mant_zero)
+ return float_zero;
+
+ return float_normal;
}
/* Convert the mantissa of VAL (which is assumed to be a floating
Index: doublest.h
===================================================================
RCS file: /cvs/src/src/gdb/doublest.h,v
retrieving revision 1.20
diff -u -p -r1.20 doublest.h
--- doublest.h 29 Jan 2007 17:31:05 -0000 1.20
+++ doublest.h 19 Mar 2007 15:30:48 -0000
@@ -64,6 +64,17 @@ typedef double DOUBLEST;
# undef SCANF_HAS_LONG_DOUBLE
#endif
+/* Different kinds of floatformat numbers recognized by
+ floatformat_classify. To avoid portability issues, we use local
+ values instead of the C99 macros (FP_NAN et cetera). */
+enum float_kind {
+ float_nan,
+ float_infinite,
+ float_zero,
+ float_normal,
+ float_subnormal
+};
+
extern void floatformat_to_doublest (const struct floatformat *,
const void *in, DOUBLEST *out);
extern void floatformat_from_doublest (const struct floatformat *,
@@ -71,7 +82,8 @@ extern void floatformat_from_doublest (c
extern int floatformat_is_negative (const struct floatformat *,
const bfd_byte *);
-extern int floatformat_is_nan (const struct floatformat *, const bfd_byte *);
+extern enum float_kind floatformat_classify (const struct floatformat *,
+ const bfd_byte *);
extern const char *floatformat_mantissa (const struct floatformat *,
const bfd_byte *);
Index: valprint.c
===================================================================
RCS file: /cvs/src/src/gdb/valprint.c,v
retrieving revision 1.64
diff -u -p -r1.64 valprint.c
--- valprint.c 9 Jan 2007 17:58:59 -0000 1.64
+++ valprint.c 19 Mar 2007 15:30:49 -0000
@@ -442,19 +442,31 @@ print_floating (const gdb_byte *valaddr,
int inv;
const struct floatformat *fmt = NULL;
unsigned len = TYPE_LENGTH (type);
+ enum float_kind kind;
/* If it is a floating-point, check for obvious problems. */
if (TYPE_CODE (type) == TYPE_CODE_FLT)
fmt = floatformat_from_type (type);
- if (fmt != NULL && floatformat_is_nan (fmt, valaddr))
+ if (fmt != NULL)
{
- if (floatformat_is_negative (fmt, valaddr))
- fprintf_filtered (stream, "-");
- fprintf_filtered (stream, "nan(");
- fputs_filtered ("0x", stream);
- fputs_filtered (floatformat_mantissa (fmt, valaddr), stream);
- fprintf_filtered (stream, ")");
- return;
+ kind = floatformat_classify (fmt, valaddr);
+ if (kind == float_nan)
+ {
+ if (floatformat_is_negative (fmt, valaddr))
+ fprintf_filtered (stream, "-");
+ fprintf_filtered (stream, "nan(");
+ fputs_filtered ("0x", stream);
+ fputs_filtered (floatformat_mantissa (fmt, valaddr), stream);
+ fprintf_filtered (stream, ")");
+ return;
+ }
+ else if (kind == float_infinite)
+ {
+ if (floatformat_is_negative (fmt, valaddr))
+ fputs_filtered ("-", stream);
+ fputs_filtered ("inf", stream);
+ return;
+ }
}
/* NOTE: cagney/2002-01-15: The TYPE passed into print_floating()
Index: testsuite/gdb.base/infnan.c
===================================================================
RCS file: testsuite/gdb.base/infnan.c
diff -N testsuite/gdb.base/infnan.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ testsuite/gdb.base/infnan.c 19 Mar 2007 15:30:49 -0000
@@ -0,0 +1,30 @@
+/* This test file is part of GDB, the GNU debugger.
+
+ Copyright 2007
+ Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA. */
+
+double a = 1.0/0.0;
+double b = 0.0/0.0;
+double c;
+
+int
+main()
+{
+ c = a + b;
+ return 0;
+}
Index: testsuite/gdb.base/infnan.exp
===================================================================
RCS file: testsuite/gdb.base/infnan.exp
diff -N testsuite/gdb.base/infnan.exp
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ testsuite/gdb.base/infnan.exp 19 Mar 2007 15:30:49 -0000
@@ -0,0 +1,36 @@
+# Copyright 2007 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+# Script to test floating point infinities and NaNs.
+
+set testfile "infnan"
+set srcfile ${testfile}.c
+set binfile ${objdir}/${subdir}/${testfile}
+
+if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } {
+ untested infnan.exp
+ return -1
+}
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+runto_main
+
+gdb_test "print a" "\\\$$decimal = inf"
+gdb_test "print b" "\\\$$decimal = nan\\(0x.*\\)"