From 203890574da95d16f8c453491026d349be4b2721 Mon Sep 17 00:00:00 2001 From: Daniel Jacobowitz Date: Fri, 30 Mar 2007 14:31:44 +0000 Subject: [PATCH] * 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. --- gdb/ChangeLog | 12 +++++++ gdb/doublest.c | 58 +++++++++++++++++++++++++------ gdb/doublest.h | 14 +++++++- gdb/testsuite/ChangeLog | 4 +++ gdb/testsuite/gdb.base/infnan.c | 30 ++++++++++++++++ gdb/testsuite/gdb.base/infnan.exp | 36 +++++++++++++++++++ gdb/valprint.c | 28 ++++++++++----- 7 files changed, 162 insertions(+), 20 deletions(-) create mode 100644 gdb/testsuite/gdb.base/infnan.c create mode 100644 gdb/testsuite/gdb.base/infnan.exp diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 97171403a2..1cb44c71f8 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,15 @@ +2007-03-30 Daniel Jacobowitz + + * 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. + 2007-03-30 Daniel Jacobowitz * README: Mention ISO C library requirement. diff --git a/gdb/doublest.c b/gdb/doublest.c index 3b640f5519..77e7ef9c78 100644 --- a/gdb/doublest.c +++ b/gdb/doublest.c @@ -180,10 +180,23 @@ convert_floatformat_to_doublest (const struct floatformat *fmt, 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 floatformat *fmt, /* 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 floatformat *fmt, 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 floatformat *fmt, 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 floatformat *fmt, 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 diff --git a/gdb/doublest.h b/gdb/doublest.h index 058b4a34e6..983c7be0af 100644 --- a/gdb/doublest.h +++ b/gdb/doublest.h @@ -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 (const struct floatformat *, 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 *); diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index beea1bcda7..74d754d18d 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2007-03-30 Daniel Jacobowitz + + * gdb.base/infnan.c, gdb.base/infnan.exp: New files. + 2007-03-30 Daniel Jacobowitz * config/netware.exp: Delete file. diff --git a/gdb/testsuite/gdb.base/infnan.c b/gdb/testsuite/gdb.base/infnan.c new file mode 100644 index 0000000000..49736633af --- /dev/null +++ b/gdb/testsuite/gdb.base/infnan.c @@ -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; +} diff --git a/gdb/testsuite/gdb.base/infnan.exp b/gdb/testsuite/gdb.base/infnan.exp new file mode 100644 index 0000000000..b14b6f353a --- /dev/null +++ b/gdb/testsuite/gdb.base/infnan.exp @@ -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.*\\)" diff --git a/gdb/valprint.c b/gdb/valprint.c index c2663e12e3..ff6f5d673e 100644 --- a/gdb/valprint.c +++ b/gdb/valprint.c @@ -442,19 +442,31 @@ print_floating (const gdb_byte *valaddr, struct type *type, 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() -- 2.34.1