Target FP: Add conversion routines to target-float.{c,h}
authorUlrich Weigand <ulrich.weigand@de.ibm.com>
Mon, 6 Nov 2017 14:57:31 +0000 (15:57 +0100)
committerUlrich Weigand <ulrich.weigand@de.ibm.com>
Mon, 6 Nov 2017 14:57:31 +0000 (15:57 +0100)
This patch adds the following conversion routines:
 - target_float_to_longest
 - target_float_from_longest
 - target_float_from_ulongest
 - target_float_convert
which call the equivalent decimal_ routines to handle decimal FP,
and call helper routines that currently still go via DOUBLEST to
handle binary FP.

The target_float_convert routine not only handles BFP<->BFP and
DFP<->DFP conversions, but also BFP<->DFP, which are implemented
by converting to a string and back.

These helpers are used in particular to implement conversion
from and to FP in value_cast, without going through DOUBLEST there.
In order to implement this for the FP<-integer case, the
pack_long / pack_unsigned_long routines are extended to support
floating-point values as output (thereby allowing use of
value_from_[u]longest with a floating-point target type).

This latter change also allows simplification of value_one.

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

* target-float.c (floatformat_to_longest): New function.
(floatformat_from_longest, floatformat_from_ulongest): Likewise.
(floatformat_convert): Likewise.
(target_float_to_longest): Likewise.
(target_float_from_longest, target_float_from_ulongest): Likewise.
(target_float_convert): Likewise.
* target-float.h (target_float_to_longest): Add prototype.
(target_float_from_longest, target_float_from_ulongest): Likewise.
(target_float_convert): Likewise.

* value.c (unpack_long): Use target_float_to_longest.
(pack_long): Allow FP types.  Use target_float_from_longest.
(pack_unsigned_long): Likewise using target_float_from_ulongest.
* valops.c: Include "target-float.h".  Do not include "dfp.h".
(value_cast): Handle conversions to FP using target_float_convert,
value_from_ulongest, and value_from_longest.
(value_one): Use value_from_longest for FP types as well.

gdb/target-float.c
gdb/target-float.h
gdb/valops.c
gdb/value.c

index e90cf03786803e1f24d5bd64a6b2bbb4f2925c65..117892161f9e00d58a02e093c2fa916b937529ee 100644 (file)
 #include "target-float.h"
 
 
+/* Helper routines operating on binary floating-point data.  */
+
+/* Convert the byte-stream ADDR, interpreted as floating-point format FMT,
+   to an integer value (rounding towards zero).  */
+static LONGEST
+floatformat_to_longest (const struct floatformat *fmt, const gdb_byte *addr)
+{
+  DOUBLEST d;
+  floatformat_to_doublest (fmt, addr, &d);
+  return (LONGEST) d;
+}
+
+/* Convert signed integer VAL to a target floating-number of format FMT
+   and store it as byte-stream ADDR.  */
+static void
+floatformat_from_longest (const struct floatformat *fmt, gdb_byte *addr,
+                         LONGEST val)
+{
+  DOUBLEST d = (DOUBLEST) val;
+  floatformat_from_doublest (fmt, &d, addr);
+}
+
+/* Convert unsigned integer VAL to a target floating-number of format FMT
+   and store it as byte-stream ADDR.  */
+static void
+floatformat_from_ulongest (const struct floatformat *fmt, gdb_byte *addr,
+                          ULONGEST val)
+{
+  DOUBLEST d = (DOUBLEST) val;
+  floatformat_from_doublest (fmt, &d, addr);
+}
+
+/* Convert a floating-point number of format FROM_FMT from the target
+   byte-stream FROM to a floating-point number of format TO_FMT, and
+   store it to the target byte-stream TO.  */
+static void
+floatformat_convert (const gdb_byte *from, const struct floatformat *from_fmt,
+                    gdb_byte *to, const struct floatformat *to_fmt)
+{
+  if (from_fmt == to_fmt)
+    {
+      /* The floating-point formats match, so we simply copy the data.  */
+      memcpy (to, from, floatformat_totalsize_bytes (to_fmt));
+    }
+  else
+    {
+      /* The floating-point formats don't match.  The best we can do
+        (apart from simulating the target FPU) is converting to the
+        widest floating-point type supported by the host, and then
+        again to the desired type.  */
+      DOUBLEST d;
+
+      floatformat_to_doublest (from_fmt, from, &d);
+      floatformat_from_doublest (to_fmt, &d, to);
+    }
+}
+
+
 /* 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
@@ -97,3 +155,114 @@ target_float_from_string (gdb_byte *addr, const struct type *type,
 
   gdb_assert_not_reached ("unexpected type code");
 }
+
+/* Convert the byte-stream ADDR, interpreted as floating-point type TYPE,
+   to an integer value (rounding towards zero).  */
+LONGEST
+target_float_to_longest (const gdb_byte *addr, const struct type *type)
+{
+  if (TYPE_CODE (type) == TYPE_CODE_FLT)
+    return floatformat_to_longest (floatformat_from_type (type), addr);
+
+  if (TYPE_CODE (type) == TYPE_CODE_DECFLOAT)
+    return decimal_to_longest (addr, TYPE_LENGTH (type),
+                              gdbarch_byte_order (get_type_arch (type)));
+
+  gdb_assert_not_reached ("unexpected type code");
+}
+
+/* Convert signed integer VAL to a target floating-number of type TYPE
+   and store it as byte-stream ADDR.  */
+void
+target_float_from_longest (gdb_byte *addr, const struct type *type,
+                          LONGEST val)
+{
+  /* Ensure possible padding bytes in the target buffer are zeroed out.  */
+  memset (addr, 0, TYPE_LENGTH (type));
+
+  if (TYPE_CODE (type) == TYPE_CODE_FLT)
+    {
+      floatformat_from_longest (floatformat_from_type (type), addr, val);
+      return;
+    }
+
+  if (TYPE_CODE (type) == TYPE_CODE_DECFLOAT)
+    {
+      decimal_from_longest (val, addr, TYPE_LENGTH (type),
+                           gdbarch_byte_order (get_type_arch (type)));
+      return;
+    }
+
+  gdb_assert_not_reached ("unexpected type code");
+}
+
+/* Convert unsigned integer VAL to a target floating-number of type TYPE
+   and store it as byte-stream ADDR.  */
+void
+target_float_from_ulongest (gdb_byte *addr, const struct type *type,
+                           ULONGEST val)
+{
+  /* Ensure possible padding bytes in the target buffer are zeroed out.  */
+  memset (addr, 0, TYPE_LENGTH (type));
+
+  if (TYPE_CODE (type) == TYPE_CODE_FLT)
+    {
+      floatformat_from_ulongest (floatformat_from_type (type), addr, val);
+      return;
+    }
+
+  if (TYPE_CODE (type) == TYPE_CODE_DECFLOAT)
+    {
+      decimal_from_ulongest (val, addr, TYPE_LENGTH (type),
+                            gdbarch_byte_order (get_type_arch (type)));
+      return;
+    }
+
+  gdb_assert_not_reached ("unexpected type code");
+}
+
+/* Convert a floating-point number of type FROM_TYPE from the target
+   byte-stream FROM to a floating-point number of type TO_TYPE, and
+   store it to the target byte-stream TO.  */
+void
+target_float_convert (const gdb_byte *from, const struct type *from_type,
+                     gdb_byte *to, const struct type *to_type)
+{
+  /* Ensure possible padding bytes in the target buffer are zeroed out.  */
+  memset (to, 0, TYPE_LENGTH (to_type));
+
+  /* Use direct conversion routines if we have them.  */
+
+  if (TYPE_CODE (from_type) == TYPE_CODE_FLT
+      && TYPE_CODE (to_type) == TYPE_CODE_FLT)
+    {
+      floatformat_convert (from, floatformat_from_type (from_type),
+                          to, floatformat_from_type (to_type));
+      return;
+    }
+
+  if (TYPE_CODE (from_type) == TYPE_CODE_DECFLOAT
+      && TYPE_CODE (to_type) == TYPE_CODE_DECFLOAT)
+    {
+      decimal_convert (from, TYPE_LENGTH (from_type),
+                      gdbarch_byte_order (get_type_arch (from_type)),
+                      to, TYPE_LENGTH (to_type),
+                      gdbarch_byte_order (get_type_arch (to_type)));
+      return;
+    }
+
+  /* We cannot directly convert between binary and decimal floating-point
+     types, so go via an intermediary string.  */
+
+  if ((TYPE_CODE (from_type) == TYPE_CODE_FLT
+       && TYPE_CODE (to_type) == TYPE_CODE_DECFLOAT)
+      || (TYPE_CODE (from_type) == TYPE_CODE_DECFLOAT
+         && TYPE_CODE (to_type) == TYPE_CODE_FLT))
+    {
+      std::string str = target_float_to_string (from, from_type);
+      target_float_from_string (to, to_type, str);
+      return;
+    }
+
+  gdb_assert_not_reached ("unexpected type code");
+}
index 317e98e33228654927778f2c0ee36b5cf1dd5ac2..9ea1812035c31269cc3e9a61ad40b88515ce7809 100644 (file)
@@ -32,4 +32,16 @@ extern bool target_float_from_string (gdb_byte *addr,
                                      const struct type *type,
                                      const std::string &string);
 
+extern LONGEST target_float_to_longest (const gdb_byte *addr,
+                                       const struct type *type);
+extern void target_float_from_longest (gdb_byte *addr,
+                                      const struct type *type,
+                                      LONGEST val);
+extern void target_float_from_ulongest (gdb_byte *addr,
+                                       const struct type *type,
+                                       ULONGEST val);
+extern void target_float_convert (const gdb_byte *from,
+                                 const struct type *from_type,
+                                 gdb_byte *to, const struct type *to_type);
+
 #endif
index de4544cd29fd650cb5e12ec0aab91a58262e0b60..ccc2bc2afe6c7bb34eedb5e39217320f32c1117e 100644 (file)
@@ -34,7 +34,7 @@
 #include "infcall.h"
 #include "dictionary.h"
 #include "cp-support.h"
-#include "dfp.h"
+#include "target-float.h"
 #include "tracepoint.h"
 #include "observer.h"
 #include "objfiles.h"
@@ -462,29 +462,21 @@ value_cast (struct type *type, struct value *arg2)
        return v;
     }
 
-  if (code1 == TYPE_CODE_FLT && scalar)
-    return value_from_double (to_type, value_as_double (arg2));
-  else if (code1 == TYPE_CODE_DECFLOAT && scalar)
+  if (is_floating_type (type) && scalar)
     {
-      enum bfd_endian byte_order = gdbarch_byte_order (get_type_arch (type));
-      int dec_len = TYPE_LENGTH (type);
-      gdb_byte dec[16];
+      if (is_floating_value (arg2))
+       {
+         struct value *v = allocate_value (to_type);
+         target_float_convert (value_contents (arg2), type2,
+                               value_contents_raw (v), type);
+         return v;
+       }
 
-      if (code2 == TYPE_CODE_FLT)
-       decimal_from_doublest (value_as_double (arg2),
-                              dec, dec_len, byte_order);
-      else if (code2 == TYPE_CODE_DECFLOAT)
-       decimal_convert (value_contents (arg2), TYPE_LENGTH (type2),
-                        byte_order, dec, dec_len, byte_order);
       /* The only option left is an integral type.  */
-      else if (TYPE_UNSIGNED (type2))
-       decimal_from_ulongest (value_as_long (arg2),
-                              dec, dec_len, byte_order);
+      if (TYPE_UNSIGNED (type2))
+       return value_from_ulongest (to_type, value_as_long (arg2));
       else
-       decimal_from_longest (value_as_long (arg2),
-                             dec, dec_len, byte_order);
-
-      return value_from_decfloat (to_type, dec);
+       return value_from_longest (to_type, value_as_long (arg2));
     }
   else if ((code1 == TYPE_CODE_INT || code1 == TYPE_CODE_ENUM
            || code1 == TYPE_CODE_RANGE)
@@ -868,19 +860,7 @@ value_one (struct type *type)
   struct type *type1 = check_typedef (type);
   struct value *val;
 
-  if (TYPE_CODE (type1) == TYPE_CODE_DECFLOAT)
-    {
-      enum bfd_endian byte_order = gdbarch_byte_order (get_type_arch (type));
-      gdb_byte v[16];
-
-      decimal_from_string (v, TYPE_LENGTH (type), byte_order, "1");
-      val = value_from_decfloat (type, v);
-    }
-  else if (TYPE_CODE (type1) == TYPE_CODE_FLT)
-    {
-      val = value_from_double (type, (DOUBLEST) 1);
-    }
-  else if (is_integral_type (type1))
+  if (is_integral_type (type1) || is_floating_type (type1))
     {
       val = value_from_longest (type, (LONGEST) 1);
     }
index 88ba18e4ddae136c659cb16071b8245c68d845aa..bc211139f77588d31d9f58761fee79f20982251b 100644 (file)
@@ -2922,10 +2922,8 @@ unpack_long (struct type *type, const gdb_byte *valaddr)
        return extract_signed_integer (valaddr, len, byte_order);
 
     case TYPE_CODE_FLT:
-      return (LONGEST) extract_typed_floating (valaddr, type);
-
     case TYPE_CODE_DECFLOAT:
-      return decimal_to_longest (valaddr, len, byte_order);
+      return target_float_to_longest (valaddr, type);
 
     case TYPE_CODE_PTR:
     case TYPE_CODE_REF:
@@ -3539,6 +3537,11 @@ pack_long (gdb_byte *buf, struct type *type, LONGEST num)
       store_typed_address (buf, type, (CORE_ADDR) num);
       break;
 
+    case TYPE_CODE_FLT:
+    case TYPE_CODE_DECFLOAT:
+      target_float_from_longest (buf, type, num);
+      break;
+
     default:
       error (_("Unexpected type (%d) encountered for integer constant."),
             TYPE_CODE (type));
@@ -3576,6 +3579,11 @@ pack_unsigned_long (gdb_byte *buf, struct type *type, ULONGEST num)
       store_typed_address (buf, type, (CORE_ADDR) num);
       break;
 
+    case TYPE_CODE_FLT:
+    case TYPE_CODE_DECFLOAT:
+      target_float_from_ulongest (buf, type, num);
+      break;
+
     default:
       error (_("Unexpected type (%d) encountered "
               "for unsigned integer constant."),