Clean up some DFP interfaces
authorUlrich Weigand <ulrich.weigand@de.ibm.com>
Thu, 5 Oct 2017 17:14:08 +0000 (19:14 +0200)
committerUlrich Weigand <ulrich.weigand@de.ibm.com>
Thu, 5 Oct 2017 17:14:08 +0000 (19:14 +0200)
This cleans up a number of interfaces in dfp.c / dfp.h.  Specifically:

- The decimal_from_string / decimal_to_string routines are C++-ified
  to operate on std::string instead of character buffers.  In the
  decimal_from_string, the boolean return value now actually is bool
  instead of an int.

- The decimal_from_integral and decimal_from_doublest routines take
  an struct value as input.  This is not really appropriate at the low
  level the DFP routines sit, so this replaced them with new routines
  decimal_from_longest / decimal_from_ulongest / decimal_from_doublest
  that operate on contents instead.

- To mirror the decimal_from_[u]longest, a new decimal_to_longest
  routine is added as well, which can be used in unpack_long to
  avoid an unnecessary conversion via DOUBLEST.

Note that the decimal_from_longest / decimal_from_ulongest routines
are actually more powerful than decimal_from_integral: the old routine
would only accept integer *types* of at most four bytes size, while
the new routines accept all integer *values* that fit in an [u]int32_t,
no matter which type they came from.  The DFP tests are updated to
allow for this larger range of integers that can be converted.

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

* dfp.h (MAX_DECIMAL_STRING): Move to dfp.c.
(decimal_to_string): Return std::string object.
(decimal_from_string): Accept std::string object.  Return bool.
(decimal_from_integral, decimal_from_doublest): Remove.
(decimal_from_longest): Add prototype.
(decimal_from_ulongest): Likewise.
(decimal_to_longest): Likewise.
(decimal_from_doublest): Likewise.
* dfp.c: Do not include "gdbtypes.h" or "value.h".
(MAX_DECIMAL_STRING): Move here.
(decimal_to_string): Return std::string object.
(decimal_from_string): Accept std::string object.  Return bool.
(decimal_from_integral): Remove, replace by ...
(decimal_from_longest, decimal_from_ulongest): ... these new functions.
(decimal_to_longest): New function.
(decimal_from_floating): Remove, replace by ...
(decimal_from_doublest): ... this new function.
(decimal_to_doublest): Update to new decimal_to_string interface.

* value.c (unpack_long): Use decimal_to_longest.
* valops.c (value_cast): Use decimal_from_doublest instead of
decimal_from_floating.  Use decimal_from_[u]longest isntead of
decimal_from_integral.
* valarith.c (value_args_as_decimal): Likewise.
* valprint.c (print_decimal_floating): Update to new
decimal_to_string interface.
* printcmd.c (printf_decfloat): Likewise.
* c-exp.y (parse_number): Update to new decimal_from_string interface.

gdb/testsuite/ChangeLog:
2017-10-05  Ulrich Weigand  <uweigand@de.ibm.com>

* gdb.base/dfp-exprs.exp: Update tests to larger range of supported
integer-to-dfp conversion.
* gdb.base/dfp-test.exp: Likewise.

12 files changed:
gdb/ChangeLog
gdb/c-exp.y
gdb/dfp.c
gdb/dfp.h
gdb/printcmd.c
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.base/dfp-exprs.exp
gdb/testsuite/gdb.base/dfp-test.exp
gdb/valarith.c
gdb/valops.c
gdb/valprint.c
gdb/value.c

index 5439ffb2844bfd60022dd28f1cc3cae3a2811177..2fababdef7850e655e7db4f0f7122209210d3947 100644 (file)
@@ -1,3 +1,34 @@
+2017-10-05  Ulrich Weigand  <uweigand@de.ibm.com>
+
+       * dfp.h (MAX_DECIMAL_STRING): Move to dfp.c.
+       (decimal_to_string): Return std::string object.
+       (decimal_from_string): Accept std::string object.  Return bool.
+       (decimal_from_integral, decimal_from_doublest): Remove.
+       (decimal_from_longest): Add prototype.
+       (decimal_from_ulongest): Likewise.
+       (decimal_to_longest): Likewise.
+       (decimal_from_doublest): Likewise.
+       * dfp.c: Do not include "gdbtypes.h" or "value.h".
+       (MAX_DECIMAL_STRING): Move here.
+       (decimal_to_string): Return std::string object.
+       (decimal_from_string): Accept std::string object.  Return bool.
+       (decimal_from_integral): Remove, replace by ...
+       (decimal_from_longest, decimal_from_ulongest): ... these new functions.
+       (decimal_to_longest): New function.
+       (decimal_from_floating): Remove, replace by ...
+       (decimal_from_doublest): ... this new function.
+       (decimal_to_doublest): Update to new decimal_to_string interface.
+
+       * value.c (unpack_long): Use decimal_to_longest.
+       * valops.c (value_cast): Use decimal_from_doublest instead of
+       decimal_from_floating.  Use decimal_from_[u]longest isntead of
+       decimal_from_integral.
+       * valarith.c (value_args_as_decimal): Likewise.
+       * valprint.c (print_decimal_floating): Update to new
+       decimal_to_string interface.
+       * printcmd.c (printf_decfloat): Likewise.
+       * c-exp.y (parse_number): Update to new decimal_from_string interface.
+
 2017-10-05  Ulrich Weigand  <uweigand@de.ibm.com>
 
        * doublest.h: Do not include "floatformat.h".  Remove stale comments.
index 43af80cb19f33188ef3163e10be7ee647888ef86..7c050b4ce7eb172222f6f8e8addb3db897c46de7 100644 (file)
@@ -1791,37 +1791,31 @@ parse_number (struct parser_state *par_state,
 
       if (len >= 2 && p[len - 2] == 'd' && p[len - 1] == 'f')
        {
-         p[len - 2] = '\0';
          putithere->typed_val_decfloat.type
            = parse_type (par_state)->builtin_decfloat;
          decimal_from_string (putithere->typed_val_decfloat.val, 4,
                               gdbarch_byte_order (parse_gdbarch (par_state)),
-                              p);
-         p[len - 2] = 'd';
+                              std::string (p, len - 2));
          return DECFLOAT;
        }
 
       if (len >= 2 && p[len - 2] == 'd' && p[len - 1] == 'd')
        {
-         p[len - 2] = '\0';
          putithere->typed_val_decfloat.type
            = parse_type (par_state)->builtin_decdouble;
          decimal_from_string (putithere->typed_val_decfloat.val, 8,
                               gdbarch_byte_order (parse_gdbarch (par_state)),
-                              p);
-         p[len - 2] = 'd';
+                              std::string (p, len - 2));
          return DECFLOAT;
        }
 
       if (len >= 2 && p[len - 2] == 'd' && p[len - 1] == 'l')
        {
-         p[len - 2] = '\0';
          putithere->typed_val_decfloat.type
            = parse_type (par_state)->builtin_declong;
          decimal_from_string (putithere->typed_val_decfloat.val, 16,
                               gdbarch_byte_order (parse_gdbarch (par_state)),
-                              p);
-         p[len - 2] = 'd';
+                              std::string (p, len - 2));
          return DECFLOAT;
        }
 
index a1b6b0625f8292a54dee6000b6172ba02134a55b..fa2c6db59c8eefc208dc5972ea0aa486a188d755 100644 (file)
--- a/gdb/dfp.c
+++ b/gdb/dfp.c
@@ -19,8 +19,6 @@
 
 #include "defs.h"
 #include "expression.h"
-#include "gdbtypes.h"
-#include "value.h"
 #include "dfp.h"
 
 /* The order of the following headers is important for making sure
 #include "dpd/decimal64.h"
 #include "dpd/decimal32.h"
 
+/* When using decimal128, this is the maximum string length + 1
+   (value comes from libdecnumber's DECIMAL128_String constant).  */
+#define MAX_DECIMAL_STRING  43
+
 /* In GDB, we are using an array of gdb_byte to represent decimal values.
    They are stored in host byte order.  This routine does the conversion if
    the target byte order is different.  */
@@ -142,37 +144,42 @@ decimal_to_number (const gdb_byte *from, int len, decNumber *to)
 /* Convert decimal type to its string representation.  LEN is the length
    of the decimal type, 4 bytes for decimal32, 8 bytes for decimal64 and
    16 bytes for decimal128.  */
-void
+std::string
 decimal_to_string (const gdb_byte *decbytes, int len,
-                  enum bfd_endian byte_order, char *s)
+                  enum bfd_endian byte_order)
 {
   gdb_byte dec[16];
 
   match_endianness (decbytes, len, byte_order, dec);
 
+  std::string result;
+  result.resize (MAX_DECIMAL_STRING);
+
   switch (len)
     {
       case 4:
-       decimal32ToString ((decimal32 *) dec, s);
+       decimal32ToString ((decimal32 *) dec, &result[0]);
        break;
       case 8:
-       decimal64ToString ((decimal64 *) dec, s);
+       decimal64ToString ((decimal64 *) dec, &result[0]);
        break;
       case 16:
-       decimal128ToString ((decimal128 *) dec, s);
+       decimal128ToString ((decimal128 *) dec, &result[0]);
        break;
       default:
        error (_("Unknown decimal floating point type."));
        break;
     }
+
+  return result;
 }
 
 /* Convert the string form of a decimal value to its decimal representation.
    LEN is the length of the decimal type, 4 bytes for decimal32, 8 bytes for
    decimal64 and 16 bytes for decimal128.  */
-int
+bool
 decimal_from_string (gdb_byte *decbytes, int len, enum bfd_endian byte_order,
-                    const char *string)
+                    std::string string)
 {
   decContext set;
   gdb_byte dec[16];
@@ -182,13 +189,13 @@ decimal_from_string (gdb_byte *decbytes, int len, enum bfd_endian byte_order,
   switch (len)
     {
       case 4:
-       decimal32FromString ((decimal32 *) dec, string, &set);
+       decimal32FromString ((decimal32 *) dec, string.c_str (), &set);
        break;
       case 8:
-       decimal64FromString ((decimal64 *) dec, string, &set);
+       decimal64FromString ((decimal64 *) dec, string.c_str (), &set);
        break;
       case 16:
-       decimal128FromString ((decimal128 *) dec, string, &set);
+       decimal128FromString ((decimal128 *) dec, string.c_str (), &set);
        break;
       default:
        error (_("Unknown decimal floating point type."));
@@ -200,66 +207,77 @@ decimal_from_string (gdb_byte *decbytes, int len, enum bfd_endian byte_order,
   /* Check for errors in the DFP operation.  */
   decimal_check_errors (&set);
 
-  return 1;
+  return true;
 }
 
-/* Converts a value of an integral type to a decimal float of
-   specified LEN bytes.  */
+/* Converts a LONGEST to a decimal float of specified LEN bytes.  */
 void
-decimal_from_integral (struct value *from,
-                      gdb_byte *to, int len, enum bfd_endian byte_order)
+decimal_from_longest (LONGEST from,
+                     gdb_byte *to, int len, enum bfd_endian byte_order)
 {
-  LONGEST l;
   gdb_byte dec[16];
   decNumber number;
-  struct type *type;
+  if ((int32_t) from != from)
+    /* libdecnumber can convert only 32-bit integers.  */
+    error (_("Conversion of large integer to a "
+            "decimal floating type is not supported."));
+
+  decNumberFromInt32 (&number, (int32_t) from);
+
+  decimal_from_number (&number, dec, len);
+  match_endianness (dec, len, byte_order, to);
+}
 
-  type = check_typedef (value_type (from));
+/* Converts a ULONGEST to a decimal float of specified LEN bytes.  */
+void
+decimal_from_ulongest (ULONGEST from,
+                      gdb_byte *to, int len, enum bfd_endian byte_order)
+{
+  gdb_byte dec[16];
+  decNumber number;
 
-  if (TYPE_LENGTH (type) > 4)
+  if ((uint32_t) from != from)
     /* libdecnumber can convert only 32-bit integers.  */
     error (_("Conversion of large integer to a "
             "decimal floating type is not supported."));
 
-  l = value_as_long (from);
-
-  if (TYPE_UNSIGNED (type))
-    decNumberFromUInt32 (&number, (unsigned int) l);
-  else
-    decNumberFromInt32 (&number, (int) l);
+  decNumberFromUInt32 (&number, (uint32_t) from);
 
   decimal_from_number (&number, dec, len);
   match_endianness (dec, len, byte_order, to);
 }
 
+/* Converts a decimal float of LEN bytes to a LONGEST.  */
+LONGEST
+decimal_to_longest (const gdb_byte *from, int len, enum bfd_endian byte_order)
+{
+  /* libdecnumber has a function to convert from decimal to integer, but
+     it doesn't work when the decimal number has a fractional part.  */
+  std::string str = decimal_to_string (from, len, byte_order);
+  return strtoll (str.c_str (), NULL, 10);
+}
+
 /* Converts a value of a float type to a decimal float of
    specified LEN bytes.
 
    This is an ugly way to do the conversion, but libdecnumber does
    not offer a direct way to do it.  */
 void
-decimal_from_floating (struct value *from,
+decimal_from_doublest (DOUBLEST from,
                       gdb_byte *to, int len, enum bfd_endian byte_order)
 {
-  char *buffer;
-
-  buffer = xstrprintf ("%.30" DOUBLEST_PRINT_FORMAT, value_as_double (from));
-
-  decimal_from_string (to, len, byte_order, buffer);
-
-  xfree (buffer);
+  std::string str = string_printf ("%.30" DOUBLEST_PRINT_FORMAT, from);
+  decimal_from_string (to, len, byte_order, str);
 }
 
 /* Converts a decimal float of LEN bytes to a double value.  */
 DOUBLEST
 decimal_to_doublest (const gdb_byte *from, int len, enum bfd_endian byte_order)
 {
-  char buffer[MAX_DECIMAL_STRING];
-
   /* This is an ugly way to do the conversion, but libdecnumber does
      not offer a direct way to do it.  */
-  decimal_to_string (from, len, byte_order, buffer);
-  return strtod (buffer, NULL);
+  std::string str = decimal_to_string (from, len, byte_order);
+  return strtod (str.c_str (), NULL);
 }
 
 /* Perform operation OP with operands X and Y with sizes LEN_X and LEN_Y
index c8ff5a1736f6e9b441a12ee0f64d69a5a1f7a220..020b9ac411bbb725eabe602976278f04f2db6919 100644 (file)
--- a/gdb/dfp.h
+++ b/gdb/dfp.h
 #include "doublest.h"    /* For DOUBLEST.  */
 #include "expression.h"  /* For enum exp_opcode.  */
 
-/* When using decimal128, this is the maximum string length + 1
- * (value comes from libdecnumber's DECIMAL128_String constant).  */
-#define MAX_DECIMAL_STRING  43
-
-extern void decimal_to_string (const gdb_byte *, int, enum bfd_endian, char *);
-extern int decimal_from_string (gdb_byte *, int, enum bfd_endian,
-                               const char *);
-extern void decimal_from_integral (struct value *from, gdb_byte *to,
+extern std::string decimal_to_string (const gdb_byte *, int, enum bfd_endian);
+extern bool decimal_from_string (gdb_byte *, int, enum bfd_endian,
+                                std::string string);
+extern void decimal_from_longest (LONGEST from, gdb_byte *to,
+                                 int len, enum bfd_endian byte_order);
+extern void decimal_from_ulongest (ULONGEST from, gdb_byte *to,
                                   int len, enum bfd_endian byte_order);
-extern void decimal_from_floating (struct value *from, gdb_byte *to,
+extern LONGEST decimal_to_longest (const gdb_byte *from, int len,
+                                  enum bfd_endian byte_order);
+extern void decimal_from_doublest (DOUBLEST from, gdb_byte *to,
                                   int len, enum bfd_endian byte_order);
 extern DOUBLEST decimal_to_doublest (const gdb_byte *from, int len,
                                     enum bfd_endian byte_order);
index 994259d2dc58d7350a2f8bdd59884429c9bf455c..a8743f1f71fe8c6073059c9421881fbf7dd494a2 100644 (file)
@@ -2307,7 +2307,6 @@ printf_decfloat (struct ui_file *stream, const char *format,
   int dfp_len = 16;
   gdb_byte dec[16];
   struct type *dfp_type = NULL;
-  char decstr[MAX_DECIMAL_STRING];
 
   /* Points to the end of the string so that we can go back
      and check for DFP length modifiers.  */
@@ -2355,10 +2354,9 @@ printf_decfloat (struct ui_file *stream, const char *format,
 
   dfp_ptr = (gdb_byte *) value_contents (dfp_value);
 
-  decimal_to_string (dfp_ptr, dfp_len, byte_order, decstr);
-
-  /* Print the DFP value.  */
-  fprintf_filtered (stream, "%s", decstr);
+  /* Convert the value to a string and print it.  */
+  std::string str = decimal_to_string (dfp_ptr, dfp_len, byte_order);
+  fputs_filtered (str.c_str (), stream);
 #endif
 }
 
index 73cf40b83942bbebe67f93c364c1ec0828374ed5..a9cd060453f31a7c1d13124f13b4968cbcc714a0 100644 (file)
@@ -1,3 +1,9 @@
+2017-10-05  Ulrich Weigand  <uweigand@de.ibm.com>
+
+       * gdb.base/dfp-exprs.exp: Update tests to larger range of supported
+       integer-to-dfp conversion.
+       * gdb.base/dfp-test.exp: Likewise.
+
 2017-10-04  Pedro Alves  <palves@redhat.com>
 
        * gdb.multi/hangout.c: Include <unistd.h>.
index 8544da4a2eb92e575142fe8bcc714226aeff3482..d9b7d78f0eed991f8a64bc3fcd59c1cfdc1e45f9 100644 (file)
@@ -113,7 +113,10 @@ proc test_dfp_arithmetic_expressions {} {
     gdb_test "ptype 3 + 2.1dl" " = _Decimal128"
 
     # Reject operation with integral larger than 32-bits
-    gdb_test "p 1.2df + 2ll" "Conversion of large integer to a decimal floating type is not supported."
+    gdb_test "p 1.2dd + 2ll" "= 3.2"
+    gdb_test "p 1.2dd + 2147483648ll" "Conversion of large integer to a decimal floating type is not supported."
+    gdb_test "p 1.2dd + 2147483648ull" "= 2147483649.2"
+    gdb_test "p 1.2dd + 4294967296ull" "Conversion of large integer to a decimal floating type is not supported."
 
     # Reject operation with DFP and Binary FP
     gdb_test "p 1.2df + 1.2f" "Mixing decimal floating types with other floating types is not allowed."
index c3a51a4a5444b587c16b53b512909d97cd47b48a..c251ffa2b86b84e841678e63b11c21b654df6ab0 100644 (file)
@@ -282,6 +282,7 @@ gdb_test "whatis d128 + ds.dec64" " = volatile _Decimal128"
 gdb_test "p d32 + 1" " = 1.1"
 gdb_test "p 2 + d64" " = 2.1"
 gdb_test "p ds.int4 + d128" " = 1.1"
+gdb_test "p d32 + ds.long8" " = 2.1"
 gdb_test "ptype d32 + 1" " = volatile _Decimal32"
 gdb_test "ptype ds.int4 + d128" " = volatile _Decimal128"
 
@@ -308,11 +309,6 @@ gdb_test "p ds.dec32 < ds.int4" " = 0"
 gdb_test "p ds.int4 > ds.dec64" " = 0"
 gdb_test "p ds.dec128 > ds.int4" " = 1"
 
-# Reject operation with integral larger than 32-bits
-if { ${sizeof_long} > 4 } {
-  gdb_test "p d32 + ds.long8" "Conversion of large integer to a decimal floating type is not supported."
-}
-
 # Reject operation with DFP and Binary FP
 gdb_test "p d64 + ds.float4" "Mixing decimal floating types with other floating types is not allowed."
 gdb_test "p ds.double8 + d128" "Mixing decimal floating types with other floating types is not allowed."
index a277be42bc03f0dad0a3e52616196db276786e55..ede60e4b68e35bb82fce7434a5626fd69f97deff 100644 (file)
@@ -881,7 +881,10 @@ value_args_as_decimal (struct value *arg1, struct value *arg2,
     {
       *byte_order_x = gdbarch_byte_order (get_type_arch (type2));
       *len_x = TYPE_LENGTH (type2);
-      decimal_from_integral (arg1, x, *len_x, *byte_order_x);
+      if (TYPE_UNSIGNED (type1))
+       decimal_from_ulongest (value_as_long (arg1), x, *len_x, *byte_order_x);
+      else
+       decimal_from_longest (value_as_long (arg1), x, *len_x, *byte_order_x);
     }
   else
     error (_("Don't know how to convert from %s to %s."), TYPE_NAME (type1),
@@ -900,7 +903,10 @@ value_args_as_decimal (struct value *arg1, struct value *arg2,
     {
       *byte_order_y = gdbarch_byte_order (get_type_arch (type1));
       *len_y = TYPE_LENGTH (type1);
-      decimal_from_integral (arg2, y, *len_y, *byte_order_y);
+      if (TYPE_UNSIGNED (type2))
+       decimal_from_ulongest (value_as_long (arg2), y, *len_y, *byte_order_y);
+      else
+       decimal_from_longest (value_as_long (arg2), y, *len_y, *byte_order_y);
     }
   else
     error (_("Don't know how to convert from %s to %s."), TYPE_NAME (type1),
index defc7d525a4bbc41f160d09f35866647d6633d2a..de4544cd29fd650cb5e12ec0aab91a58262e0b60 100644 (file)
@@ -471,13 +471,18 @@ value_cast (struct type *type, struct value *arg2)
       gdb_byte dec[16];
 
       if (code2 == TYPE_CODE_FLT)
-       decimal_from_floating (arg2, dec, dec_len, byte_order);
+       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);
       else
-       /* The only option left is an integral type.  */
-       decimal_from_integral (arg2, dec, dec_len, byte_order);
+       decimal_from_longest (value_as_long (arg2),
+                             dec, dec_len, byte_order);
 
       return value_from_decfloat (to_type, dec);
     }
index ead4131967445a1c817e0139c828268171e0de60..ca0c4768c9eb78c456e00b6f44ffb84d0eca20be 100644 (file)
@@ -1472,12 +1472,10 @@ print_decimal_floating (const gdb_byte *valaddr, struct type *type,
                        struct ui_file *stream)
 {
   enum bfd_endian byte_order = gdbarch_byte_order (get_type_arch (type));
-  char decstr[MAX_DECIMAL_STRING];
   unsigned len = TYPE_LENGTH (type);
 
-  decimal_to_string (valaddr, len, byte_order, decstr);
-  fputs_filtered (decstr, stream);
-  return;
+  std::string str = decimal_to_string (valaddr, len, byte_order);
+  fputs_filtered (str.c_str (), stream);
 }
 
 void
index 347eba5978eee18bd53853f5498051a66c5c128e..90423ed00286899fd10741bae65ea87526259382 100644 (file)
@@ -2925,9 +2925,7 @@ unpack_long (struct type *type, const gdb_byte *valaddr)
       return (LONGEST) extract_typed_floating (valaddr, type);
 
     case TYPE_CODE_DECFLOAT:
-      /* libdecnumber has a function to convert from decimal to integer, but
-        it doesn't work when the decimal number has a fractional part.  */
-      return (LONGEST) decimal_to_doublest (valaddr, len, byte_order);
+      return decimal_to_longest (valaddr, len, byte_order);
 
     case TYPE_CODE_PTR:
     case TYPE_CODE_REF: