Target FP: Introduce target-float.{c,h}
authorUlrich Weigand <ulrich.weigand@de.ibm.com>
Mon, 6 Nov 2017 14:55:11 +0000 (15:55 +0100)
committerUlrich Weigand <ulrich.weigand@de.ibm.com>
Mon, 6 Nov 2017 14:56:02 +0000 (15:56 +0100)
This patch introduces the new set of target floating-point handling routines
in target-float.{c,h}.  In the end, the intention is that this file will
contain support for all operations in target FP format, fully replacing
both the current doublest.{c,h} and dfp.{c,h}.

To begin with, this patch only adds a target_float_is_zero routine,
which handles the equivalent of decimal_is_zero for both binary and
decimal FP.  For the binary case, to avoid conversion to DOUBLEST,
this is implemented using the floatformat_classify routine.

However, it turns out that floatformat_classify actually has a bug
(it was not used to check for zero before), so this is fixed as well.

The new routine is used in both value_logical_not and valpy_nonzero.

There is one extra twist: the code previously used value_as_double
to convert to DOUBLEST and then compare against zero.  That routine
performs an extra task: it detects invalid floating-point values
and raises an error.  In any place where value_as_double is removed
in favor of some target-float.c routine, we need to replace that check.

To keep this check centralized in one place, I've added a new routine
is_floating_value, which returns a boolean determining whether a
value's type is floating point (binary or decimal), and if so, also
performs the validity check.  Since we need to check whether a value
is FP before calling any of the target-float routines anyway, this
seems a good place to add the check without much code size overhead.

In some places where we only want to check for floating-point types
and not perform a validity check (e.g. for the *output* of an operation),
we can use the new is_floating_type routine (in gdbarch) instead.

The validity check itself is done by a new target_float_is_valid
routine in target-float, encapsulating floatformat_is_valid.

ChangeLog:
2017-11-06  Ulrich Weigand  <uweigand@de.ibm.com>

* Makefile.c (SFILES): Add target-float.c.
(HFILES_NO_SRCDIR): Add target-float.h.
(COMMON_OBS): Add target-float.o.
* target-float.h: New file.
* target-float.c: New file.

* doublest.c (floatformat_classify): Fix detection of float_zero.

* gdbtypes.c (is_floating_type): New function.
* gdbtypes.h (is_floating_type): Add prototype.

* value.c: Do not include "floatformat.h".
(unpack_double): Use target_float_is_valid.
(is_floating_value): New function.
* value.h (is_floating_value): Add prototype-

* valarith.c: Include "target-float.h".
(value_logical_not): Use target_float_is_zero.

* python/py-value.c: Include "target-float.h".
(valpy_nonzero): Use target_float_is_zero.

gdb/ChangeLog
gdb/Makefile.in
gdb/doublest.c
gdb/gdbtypes.c
gdb/gdbtypes.h
gdb/python/py-value.c
gdb/target-float.c [new file with mode: 0644]
gdb/target-float.h [new file with mode: 0644]
gdb/valarith.c
gdb/value.c
gdb/value.h

index a4a88800c8e80c84191349b8b8f32d05cd54a630..df06c84e29c9434f4c23a540922e94ef8fdbaf33 100644 (file)
@@ -1,3 +1,27 @@
+2017-11-06  Ulrich Weigand  <uweigand@de.ibm.com>
+
+       * Makefile.c (SFILES): Add target-float.c.
+       (HFILES_NO_SRCDIR): Add target-float.h.
+       (COMMON_OBS): Add target-float.o.
+       * target-float.h: New file.
+       * target-float.c: New file.
+
+       * doublest.c (floatformat_classify): Fix detection of float_zero.
+
+       * gdbtypes.c (is_floating_type): New function.
+       * gdbtypes.h (is_floating_type): Add prototype.
+
+       * value.c: Do not include "floatformat.h".
+       (unpack_double): Use target_float_is_valid.
+       (is_floating_value): New function.
+       * value.h (is_floating_value): Add prototype-
+
+       * valarith.c: Include "target-float.h".
+       (value_logical_not): Use target_float_is_zero.
+
+       * python/py-value.c: Include "target-float.h".
+       (valpy_nonzero): Use target_float_is_zero.
+
 2017-11-04  Tom Tromey  <tom@tromey.com>
 
        * h8300-tdep.c (h8300_push_dummy_call): Use std::vector.
index 1a68746faf54d84b90251fde68d91e986049cc08..9e8cdf7571361903fcb7bee98c58d3d47cc08594 100644 (file)
@@ -1224,6 +1224,7 @@ SFILES = \
        tracepoint.c \
        trad-frame.c \
        tramp-frame.c \
+       target-float.c \
        typeprint.c \
        ui-file.c \
        ui-file.h \
@@ -1492,6 +1493,7 @@ HFILES_NO_SRCDIR = \
        tracefile.h \
        tracepoint.h \
        trad-frame.h \
+       target-float.h \
        tramp-frame.h \
        typeprint.h \
        ui-file.h \
@@ -1845,6 +1847,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
        top.o \
        trad-frame.o \
        tramp-frame.o \
+       target-float.o \
        typeprint.o \
        ui-file.o \
        ui-out.o \
index ef98dde8cbdc2076afd800c9b39a600b8dfb5eb6..79c15feb069cfe9570037cb54fe37f8495cb20a7 100644 (file)
@@ -594,8 +594,13 @@ floatformat_classify (const struct floatformat *fmt,
        return float_normal;
     }
 
-  if (exponent == 0 && !mant_zero)
-    return float_subnormal;
+  if (exponent == 0)
+    {
+      if (mant_zero)
+       return float_zero;
+      else
+       return float_subnormal;
+    }
 
   if (exponent == fmt->exp_nan)
     {
@@ -605,9 +610,6 @@ floatformat_classify (const struct floatformat *fmt,
        return float_nan;
     }
 
-  if (mant_zero)
-    return float_zero;
-
   return float_normal;
 }
 
index 73d445361dd1028695447e141a6bcabb3a2422b5..01ab6fa8c7683427d88d0df3fdc9ffb13439de20 100644 (file)
@@ -2935,6 +2935,16 @@ is_integral_type (struct type *t)
         || (TYPE_CODE (t) == TYPE_CODE_BOOL)));
 }
 
+int
+is_floating_type (struct type *t)
+{
+  t = check_typedef (t);
+  return
+    ((t != NULL)
+     && ((TYPE_CODE (t) == TYPE_CODE_FLT)
+        || (TYPE_CODE (t) == TYPE_CODE_DECFLOAT)));
+}
+
 /* Return true if TYPE is scalar.  */
 
 int
index 5c1aecd211b16d21ae2f7618b4953e9e6aa96a38..03709aa1458f6a70051aaa4d0ca3f922920a72f5 100644 (file)
@@ -1938,6 +1938,8 @@ extern int can_dereference (struct type *);
 
 extern int is_integral_type (struct type *);
 
+extern int is_floating_type (struct type *);
+
 extern int is_scalar_type (struct type *type);
 
 extern int is_scalar_type_recursive (struct type *);
index cbbb9362ec9afcdcafd5f25a79442aac1f9ca1a5..16c765094a090c37464f96242ba10bf70cd6b17d 100644 (file)
@@ -21,7 +21,7 @@
 #include "charset.h"
 #include "value.h"
 #include "language.h"
-#include "dfp.h"
+#include "target-float.h"
 #include "valprint.h"
 #include "infcall.h"
 #include "expression.h"
@@ -1317,12 +1317,9 @@ valpy_nonzero (PyObject *self)
 
       if (is_integral_type (type) || TYPE_CODE (type) == TYPE_CODE_PTR)
        nonzero = !!value_as_long (self_value->value);
-      else if (TYPE_CODE (type) == TYPE_CODE_FLT)
-       nonzero = value_as_double (self_value->value) != 0;
-      else if (TYPE_CODE (type) == TYPE_CODE_DECFLOAT)
-       nonzero = !decimal_is_zero (value_contents (self_value->value),
-                                TYPE_LENGTH (type),
-                                gdbarch_byte_order (get_type_arch (type)));
+      else if (is_floating_value (self_value->value))
+       nonzero = !target_float_is_zero (value_contents (self_value->value),
+                                        type);
       else
        /* All other values are True.  */
        nonzero = 1;
diff --git a/gdb/target-float.c b/gdb/target-float.c
new file mode 100644 (file)
index 0000000..a082b9c
--- /dev/null
@@ -0,0 +1,62 @@
+/* Floating point routines for GDB, the GNU debugger.
+
+   Copyright (C) 2017 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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 3 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, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "dfp.h"
+#include "doublest.h"
+#include "gdbtypes.h"
+#include "floatformat.h"
+#include "target-float.h"
+
+
+/* Typed floating-point routines.  These routines operate on floating-point
+   values in target format, represented by a byte buffer interpreted as a
+   "struct type", which may be either a binary or decimal floating-point
+   type (TYPE_CODE_FLT or TYPE_CODE_DECFLOAT).  */
+
+/* Return whether the byte-stream ADDR holds a valid value of
+   floating-point type TYPE.  */
+bool
+target_float_is_valid (const gdb_byte *addr, const struct type *type)
+{
+  if (TYPE_CODE (type) == TYPE_CODE_FLT)
+    return floatformat_is_valid (floatformat_from_type (type), addr);
+
+  if (TYPE_CODE (type) == TYPE_CODE_DECFLOAT)
+    return true;
+
+  gdb_assert_not_reached ("unexpected type code");
+}
+
+/* Return whether the byte-stream ADDR, interpreted as floating-point
+   type TYPE, is numerically equal to zero (of either sign).  */
+bool
+target_float_is_zero (const gdb_byte *addr, const struct type *type)
+{
+  if (TYPE_CODE (type) == TYPE_CODE_FLT)
+    return (floatformat_classify (floatformat_from_type (type), addr)
+           == float_zero);
+
+  if (TYPE_CODE (type) == TYPE_CODE_DECFLOAT)
+    return decimal_is_zero (addr, TYPE_LENGTH (type),
+                           gdbarch_byte_order (get_type_arch (type)));
+
+  gdb_assert_not_reached ("unexpected type code");
+}
+
diff --git a/gdb/target-float.h b/gdb/target-float.h
new file mode 100644 (file)
index 0000000..43709f7
--- /dev/null
@@ -0,0 +1,28 @@
+/* Floating point definitions for GDB.
+
+   Copyright (C) 1986-2017 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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 3 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, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef TYPED_FLOAT_H
+#define TYPED_FLOAT_H
+
+extern bool target_float_is_valid (const gdb_byte *addr,
+                                  const struct type *type);
+extern bool target_float_is_zero (const gdb_byte *addr,
+                                 const struct type *type);
+
+#endif
index ede60e4b68e35bb82fce7434a5626fd69f97deff..3e52e9d566d8fe9ffa5a4465c8009100eb3af1e6 100644 (file)
@@ -26,6 +26,7 @@
 #include "language.h"
 #include "doublest.h"
 #include "dfp.h"
+#include "target-float.h"
 #include <math.h>
 #include "infcall.h"
 
@@ -1514,11 +1515,8 @@ value_logical_not (struct value *arg1)
   arg1 = coerce_array (arg1);
   type1 = check_typedef (value_type (arg1));
 
-  if (TYPE_CODE (type1) == TYPE_CODE_FLT)
-    return 0 == value_as_double (arg1);
-  else if (TYPE_CODE (type1) == TYPE_CODE_DECFLOAT)
-    return decimal_is_zero (value_contents (arg1), TYPE_LENGTH (type1),
-                           gdbarch_byte_order (get_type_arch (type1)));
+  if (is_floating_value (arg1))
+    return target_float_is_zero (value_contents (arg1), type1);
 
   len = TYPE_LENGTH (type1);
   p = value_contents (arg1);
index 7d0966c8fe19dea8c99da8c2aaac2efa4f804c90..88ba18e4ddae136c659cb16071b8245c68d845aa 100644 (file)
 #include "language.h"
 #include "demangle.h"
 #include "doublest.h"
-#include "floatformat.h"
 #include "regcache.h"
 #include "block.h"
 #include "dfp.h"
+#include "target-float.h"
 #include "objfiles.h"
 #include "valprint.h"
 #include "cli/cli-decode.h"
@@ -2961,24 +2961,7 @@ unpack_double (struct type *type, const gdb_byte *valaddr, int *invp)
   nosign = TYPE_UNSIGNED (type);
   if (code == TYPE_CODE_FLT)
     {
-      /* NOTE: cagney/2002-02-19: There was a test here to see if the
-        floating-point value was valid (using the macro
-        INVALID_FLOAT).  That test/macro have been removed.
-
-        It turns out that only the VAX defined this macro and then
-        only in a non-portable way.  Fixing the portability problem
-        wouldn't help since the VAX floating-point code is also badly
-        bit-rotten.  The target needs to add definitions for the
-        methods gdbarch_float_format and gdbarch_double_format - these
-        exactly describe the target floating-point format.  The
-        problem here is that the corresponding floatformat_vax_f and
-        floatformat_vax_d values these methods should be set to are
-        also not defined either.  Oops!
-
-         Hopefully someone will add both the missing floatformat
-         definitions and the new cases for floatformat_is_valid ().  */
-
-      if (!floatformat_is_valid (floatformat_from_type (type), valaddr))
+      if (!target_float_is_valid (valaddr, type))
        {
          *invp = 1;
          return 0.0;
@@ -3021,6 +3004,21 @@ unpack_pointer (struct type *type, const gdb_byte *valaddr)
   return unpack_long (type, valaddr);
 }
 
+bool
+is_floating_value (struct value *val)
+{
+  struct type *type = check_typedef (value_type (val));
+
+  if (is_floating_type (type))
+    {
+      if (!target_float_is_valid (value_contents (val), type))
+       error (_("Invalid floating value found in program."));
+      return true;
+    }
+
+  return false;
+}
+
 \f
 /* Get the value of the FIELDNO'th field (which must be static) of
    TYPE.  */
index cfc8caea05285dec92e467fac45e3416337cde9f..237d5dbde16bf6d3d099af5bb07f0eff599bc287 100644 (file)
@@ -608,6 +608,10 @@ extern int print_address_demangle (const struct value_print_options *,
                                   struct gdbarch *, CORE_ADDR,
                                   struct ui_file *, int);
 
+/* Returns true if VAL is of floating-point type.  In addition,
+   throws an error if the value is an invalid floating-point value.  */
+extern bool is_floating_value (struct value *val);
+
 extern LONGEST value_as_long (struct value *val);
 extern DOUBLEST value_as_double (struct value *val);
 extern CORE_ADDR value_as_address (struct value *val);