Target FP: Add binop and compare routines to target-float.{c,h}
authorUlrich Weigand <ulrich.weigand@de.ibm.com>
Mon, 6 Nov 2017 14:58:46 +0000 (15:58 +0100)
committerUlrich Weigand <ulrich.weigand@de.ibm.com>
Mon, 6 Nov 2017 14:58:46 +0000 (15:58 +0100)
This patch adds the following target floating-point routines:
 - target_float_binop
 - target_float_compare
which call the equivalent decimal_ routines to handle decimal FP,
and call helper routines that currently still go via DOUBLEST to
handle binary FP (derived from current valarith.c code).

These routines are used to handle both binary and decimal FP types
in scalar_binop, value_equal, and value_less, mostly following the
method currently used for decimal FP.  The existing value_args_as_decimal
helper is renamed to value_args_as_target_float and extended to handle
both binary and decimal types.

The unary operations value_pos and value_neg are also simplified,
the former by using a simple copy for all scalar types, the latter
by using value_binop (... BINOP_SUB) to implement negation as
subtraction from zero.

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

* target-float.c: Include <math.h>.
(floatformat_binop): New function.
(floatformat_compare): Likewise.
(target_float_binop): Likewise.
(target_float_compare): Likewise.
* target-float.h: Include "expression.h".
(target_float_binop): Add prototype.
(target_float_compare): Likewise.

* valarith.c: Do not include "doublest.h" and "dfp.h".
Include "common/byte-vector.h".
(value_args_as_decimal): Remove, replace by ...
(value_args_as_target_float): ... this function.  Handle both
binary and decimal target floating-point formats.
(scalar_binop): Handle both binary and decimal FP using
value_args_as_target_float and target_float_binop.
(value_equal): Handle both binary and decimal FP using
value_args_as_target_float and target_float_compare.
(value_less): Likewise.
(value_pos): Handle all scalar types as simple copy.
(value_neg): Handle all scalar types via BINOP_SUB from 0.
* dfp.c (decimal_binop): Throw error instead of internal_error
when called with an unsupported operation code.

gdb/ChangeLog
gdb/dfp.c
gdb/target-float.c
gdb/target-float.h
gdb/valarith.c

index 6ee299d07c29dba6d36ed7f9c8387168daac9855..6d3c6a1aca66871e17eab6eef6a17d8a1f8aa733 100644 (file)
@@ -1,3 +1,29 @@
+2017-11-06  Ulrich Weigand  <uweigand@de.ibm.com>
+
+       * target-float.c: Include <math.h>.
+       (floatformat_binop): New function.
+       (floatformat_compare): Likewise.
+       (target_float_binop): Likewise.
+       (target_float_compare): Likewise.
+       * target-float.h: Include "expression.h".
+       (target_float_binop): Add prototype.
+       (target_float_compare): Likewise.
+
+       * valarith.c: Do not include "doublest.h" and "dfp.h".
+       Include "common/byte-vector.h".
+       (value_args_as_decimal): Remove, replace by ...
+       (value_args_as_target_float): ... this function.  Handle both
+       binary and decimal target floating-point formats.
+       (scalar_binop): Handle both binary and decimal FP using
+       value_args_as_target_float and target_float_binop.
+       (value_equal): Handle both binary and decimal FP using
+       value_args_as_target_float and target_float_compare.
+       (value_less): Likewise.
+       (value_pos): Handle all scalar types as simple copy.
+       (value_neg): Handle all scalar types via BINOP_SUB from 0.
+       * dfp.c (decimal_binop): Throw error instead of internal_error
+       when called with an unsupported operation code.
+
 2017-11-06  Ulrich Weigand  <uweigand@de.ibm.com>
 
        * target-float.c (target_float_to_string): New function.
index a13e260611a7ad5423f205fd22a4622cce87df8b..d47026855f0a4064f53eb86d43d2351b4acb3ff5 100644 (file)
--- a/gdb/dfp.c
+++ b/gdb/dfp.c
@@ -330,9 +330,8 @@ decimal_binop (enum exp_opcode op,
       case BINOP_EXP:
        decNumberPower (&number3, &number1, &number2, &set);
        break;
-      default:
-       internal_error (__FILE__, __LINE__,
-                       _("Unknown decimal floating point operation."));
+     default:
+       error (_("Operation not valid for decimal floating point number."));
        break;
     }
 
index 117892161f9e00d58a02e093c2fa916b937529ee..ad04f8fb4a195f77572ba2702f6868d3451be11f 100644 (file)
@@ -27,6 +27,8 @@
 
 /* Helper routines operating on binary floating-point data.  */
 
+#include <math.h>
+
 /* Convert the byte-stream ADDR, interpreted as floating-point format FMT,
    to an integer value (rounding towards zero).  */
 static LONGEST
@@ -82,6 +84,82 @@ floatformat_convert (const gdb_byte *from, const struct floatformat *from_fmt,
     }
 }
 
+/* Perform the binary operation indicated by OPCODE, using as operands the
+   target byte streams X and Y, interpreted as floating-point numbers of
+   formats FMT_X and FMT_Y, respectively.  Convert the result to format
+   FMT_RES and store it into the byte-stream RES.  */
+static void
+floatformat_binop (enum exp_opcode op,
+                  const struct floatformat *fmt_x, const gdb_byte *x,
+                  const struct floatformat *fmt_y, const gdb_byte *y,
+                  const struct floatformat *fmt_result, gdb_byte *result)
+{
+  DOUBLEST v1, v2, v = 0;
+
+  floatformat_to_doublest (fmt_x, x, &v1);
+  floatformat_to_doublest (fmt_y, y, &v2);
+
+  switch (op)
+    {
+      case BINOP_ADD:
+       v = v1 + v2;
+       break;
+
+      case BINOP_SUB:
+       v = v1 - v2;
+       break;
+
+      case BINOP_MUL:
+       v = v1 * v2;
+       break;
+
+      case BINOP_DIV:
+       v = v1 / v2;
+       break;
+
+      case BINOP_EXP:
+       errno = 0;
+       v = pow (v1, v2);
+       if (errno)
+         error (_("Cannot perform exponentiation: %s"),
+                safe_strerror (errno));
+       break;
+
+      case BINOP_MIN:
+       v = v1 < v2 ? v1 : v2;
+       break;
+
+      case BINOP_MAX:
+       v = v1 > v2 ? v1 : v2;
+       break;
+
+      default:
+       error (_("Integer-only operation on floating point number."));
+       break;
+    }
+
+  floatformat_from_doublest (fmt_result, &v, result);
+}
+
+/* Compare the two target byte streams X and Y, interpreted as floating-point
+   numbers of formats FMT_X and FMT_Y, respectively.  Return zero if X and Y
+   are equal, -1 if X is less than Y, and 1 otherwise.  */
+static int
+floatformat_compare (const struct floatformat *fmt_x, const gdb_byte *x,
+                    const struct floatformat *fmt_y, const gdb_byte *y)
+{
+  DOUBLEST v1, v2;
+
+  floatformat_to_doublest (fmt_x, x, &v1);
+  floatformat_to_doublest (fmt_y, y, &v2);
+
+  if (v1 == v2)
+    return 0;
+  if (v1 < v2)
+    return -1;
+  return 1;
+}
+
 
 /* Typed floating-point routines.  These routines operate on floating-point
    values in target format, represented by a byte buffer interpreted as a
@@ -266,3 +344,77 @@ target_float_convert (const gdb_byte *from, const struct type *from_type,
 
   gdb_assert_not_reached ("unexpected type code");
 }
+
+/* Perform the binary operation indicated by OPCODE, using as operands the
+   target byte streams X and Y, interpreted as floating-point numbers of
+   types TYPE_X and TYPE_Y, respectively.  Convert the result to type
+   TYPE_RES and store it into the byte-stream RES.
+
+   The three types must either be all binary floating-point types, or else
+   all decimal floating-point types.  Binary and decimal floating-point
+   types cannot be mixed within a single operation.  */
+void
+target_float_binop (enum exp_opcode opcode,
+                   const gdb_byte *x, const struct type *type_x,
+                   const gdb_byte *y, const struct type *type_y,
+                   gdb_byte *res, const struct type *type_res)
+{
+  /* Ensure possible padding bytes in the target buffer are zeroed out.  */
+  memset (res, 0, TYPE_LENGTH (type_res));
+
+  if (TYPE_CODE (type_res) == TYPE_CODE_FLT)
+    {
+      gdb_assert (TYPE_CODE (type_x) == TYPE_CODE_FLT);
+      gdb_assert (TYPE_CODE (type_y) == TYPE_CODE_FLT);
+      return floatformat_binop (opcode,
+                               floatformat_from_type (type_x), x,
+                               floatformat_from_type (type_y), y,
+                               floatformat_from_type (type_res), res);
+    }
+
+  if (TYPE_CODE (type_res) == TYPE_CODE_DECFLOAT)
+    {
+      gdb_assert (TYPE_CODE (type_x) == TYPE_CODE_DECFLOAT);
+      gdb_assert (TYPE_CODE (type_y) == TYPE_CODE_DECFLOAT);
+      return decimal_binop (opcode,
+                           x, TYPE_LENGTH (type_x),
+                           gdbarch_byte_order (get_type_arch (type_x)),
+                           y, TYPE_LENGTH (type_y),
+                           gdbarch_byte_order (get_type_arch (type_y)),
+                           res, TYPE_LENGTH (type_res),
+                           gdbarch_byte_order (get_type_arch (type_res)));
+    }
+
+  gdb_assert_not_reached ("unexpected type code");
+}
+
+/* Compare the two target byte streams X and Y, interpreted as floating-point
+   numbers of types TYPE_X and TYPE_Y, respectively.  Return zero if X and Y
+   are equal, -1 if X is less than Y, and 1 otherwise.
+
+   The two types must either both be binary floating-point types, or else
+   both be decimal floating-point types.  Binary and decimal floating-point
+   types cannot compared directly against each other.  */
+int
+target_float_compare (const gdb_byte *x, const struct type *type_x,
+                     const gdb_byte *y, const struct type *type_y)
+{
+  if (TYPE_CODE (type_x) == TYPE_CODE_FLT)
+    {
+      gdb_assert (TYPE_CODE (type_y) == TYPE_CODE_FLT);
+      return floatformat_compare (floatformat_from_type (type_x), x,
+                                 floatformat_from_type (type_y), y);
+    }
+
+  if (TYPE_CODE (type_x) == TYPE_CODE_DECFLOAT)
+    {
+      gdb_assert (TYPE_CODE (type_y) == TYPE_CODE_DECFLOAT);
+      return decimal_compare (x, TYPE_LENGTH (type_x),
+                             gdbarch_byte_order (get_type_arch (type_x)),
+                             y, TYPE_LENGTH (type_y),
+                             gdbarch_byte_order (get_type_arch (type_y)));
+    }
+
+  gdb_assert_not_reached ("unexpected type code");
+}
+
index 9ea1812035c31269cc3e9a61ad40b88515ce7809..466dd1b5c854d4c8ac93fa649a5fe7a12273c0bf 100644 (file)
@@ -20,6 +20,8 @@
 #ifndef TYPED_FLOAT_H
 #define TYPED_FLOAT_H
 
+#include "expression.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,
@@ -44,4 +46,11 @@ extern void target_float_convert (const gdb_byte *from,
                                  const struct type *from_type,
                                  gdb_byte *to, const struct type *to_type);
 
+extern void target_float_binop (enum exp_opcode opcode,
+                               const gdb_byte *x, const struct type *type_x,
+                               const gdb_byte *y, const struct type *type_y,
+                               gdb_byte *res, const struct type *type_res);
+extern int target_float_compare (const gdb_byte *x, const struct type *type_x,
+                                const gdb_byte *y, const struct type *type_y);
+
 #endif
index 3e52e9d566d8fe9ffa5a4465c8009100eb3af1e6..89e44f3fb01ff2af5731479f97d8aac6d31f137d 100644 (file)
 #include "expression.h"
 #include "target.h"
 #include "language.h"
-#include "doublest.h"
-#include "dfp.h"
 #include "target-float.h"
-#include <math.h>
 #include "infcall.h"
+#include "common/byte-vector.h"
 
 /* Define whether or not the C operator '/' truncates towards zero for
    differently signed operands (truncation direction is undefined in C).  */
@@ -845,69 +843,62 @@ uinteger_pow (ULONGEST v1, LONGEST v2)
     }
 }
 
-/* Obtain decimal value of arguments for binary operation, converting from
-   other types if one of them is not decimal floating point.  */
+/* Obtain argument values for binary operation, converting from
+   other types if one of them is not floating point.  */
 static void
-value_args_as_decimal (struct value *arg1, struct value *arg2,
-                      gdb_byte *x, int *len_x, enum bfd_endian *byte_order_x,
-                      gdb_byte *y, int *len_y, enum bfd_endian *byte_order_y)
+value_args_as_target_float (struct value *arg1, struct value *arg2,
+                           gdb_byte *x, struct type **eff_type_x,
+                           gdb_byte *y, struct type **eff_type_y)
 {
   struct type *type1, *type2;
 
   type1 = check_typedef (value_type (arg1));
   type2 = check_typedef (value_type (arg2));
 
-  /* At least one of the arguments must be of decimal float type.  */
-  gdb_assert (TYPE_CODE (type1) == TYPE_CODE_DECFLOAT
-             || TYPE_CODE (type2) == TYPE_CODE_DECFLOAT);
+  /* At least one of the arguments must be of floating-point type.  */
+  gdb_assert (is_floating_type (type1) || is_floating_type (type2));
 
-  if (TYPE_CODE (type1) == TYPE_CODE_FLT
-      || TYPE_CODE (type2) == TYPE_CODE_FLT)
+  if (is_floating_type (type1) && is_floating_type (type2)
+      && TYPE_CODE (type1) != TYPE_CODE (type2))
     /* The DFP extension to the C language does not allow mixing of
      * decimal float types with other float types in expressions
      * (see WDTR 24732, page 12).  */
     error (_("Mixing decimal floating types with "
             "other floating types is not allowed."));
 
-  /* Obtain decimal value of arg1, converting from other types
-     if necessary.  */
+  /* Obtain value of arg1, converting from other types if necessary.  */
 
-  if (TYPE_CODE (type1) == TYPE_CODE_DECFLOAT)
+  if (is_floating_type (type1))
     {
-      *byte_order_x = gdbarch_byte_order (get_type_arch (type1));
-      *len_x = TYPE_LENGTH (type1);
-      memcpy (x, value_contents (arg1), *len_x);
+      *eff_type_x = type1;
+      memcpy (x, value_contents (arg1), TYPE_LENGTH (type1));
     }
   else if (is_integral_type (type1))
     {
-      *byte_order_x = gdbarch_byte_order (get_type_arch (type2));
-      *len_x = TYPE_LENGTH (type2);
+      *eff_type_x = type2;
       if (TYPE_UNSIGNED (type1))
-       decimal_from_ulongest (value_as_long (arg1), x, *len_x, *byte_order_x);
+       target_float_from_ulongest (x, *eff_type_x, value_as_long (arg1));
       else
-       decimal_from_longest (value_as_long (arg1), x, *len_x, *byte_order_x);
+       target_float_from_longest (x, *eff_type_x, value_as_long (arg1));
     }
   else
     error (_("Don't know how to convert from %s to %s."), TYPE_NAME (type1),
             TYPE_NAME (type2));
 
-  /* Obtain decimal value of arg2, converting from other types
-     if necessary.  */
+  /* Obtain value of arg2, converting from other types if necessary.  */
 
-  if (TYPE_CODE (type2) == TYPE_CODE_DECFLOAT)
+  if (is_floating_type (type2))
     {
-      *byte_order_y = gdbarch_byte_order (get_type_arch (type2));
-      *len_y = TYPE_LENGTH (type2);
-      memcpy (y, value_contents (arg2), *len_y);
+      *eff_type_y = type2;
+      memcpy (y, value_contents (arg2), TYPE_LENGTH (type2));
     }
   else if (is_integral_type (type2))
     {
-      *byte_order_y = gdbarch_byte_order (get_type_arch (type1));
-      *len_y = TYPE_LENGTH (type1);
+      *eff_type_y = type1;
       if (TYPE_UNSIGNED (type2))
-       decimal_from_ulongest (value_as_long (arg2), y, *len_y, *byte_order_y);
+       target_float_from_ulongest (y, *eff_type_y, value_as_long (arg2));
       else
-       decimal_from_longest (value_as_long (arg2), y, *len_y, *byte_order_y);
+       target_float_from_longest (y, *eff_type_y, value_as_long (arg2));
     }
   else
     error (_("Don't know how to convert from %s to %s."), TYPE_NAME (type1),
@@ -932,111 +923,17 @@ scalar_binop (struct value *arg1, struct value *arg2, enum exp_opcode op)
   type1 = check_typedef (value_type (arg1));
   type2 = check_typedef (value_type (arg2));
 
-  if ((TYPE_CODE (type1) != TYPE_CODE_FLT
-       && TYPE_CODE (type1) != TYPE_CODE_DECFLOAT
-       && !is_integral_type (type1))
-      || (TYPE_CODE (type2) != TYPE_CODE_FLT
-         && TYPE_CODE (type2) != TYPE_CODE_DECFLOAT
-         && !is_integral_type (type2)))
+  if ((!is_floating_value (arg1) && !is_integral_type (type1))
+      || (!is_floating_value (arg2) && !is_integral_type (type2)))
     error (_("Argument to arithmetic operation not a number or boolean."));
 
-  if (TYPE_CODE (type1) == TYPE_CODE_DECFLOAT
-      || TYPE_CODE (type2) == TYPE_CODE_DECFLOAT)
+  if (is_floating_type (type1) || is_floating_type (type2))
     {
-      int len_v1, len_v2, len_v;
-      enum bfd_endian byte_order_v1, byte_order_v2, byte_order_v;
-      gdb_byte v1[16], v2[16];
-      gdb_byte v[16];
-
-      /* If only one type is decimal float, use its type.
+      /* If only one type is floating-point, use its type.
         Otherwise use the bigger type.  */
-      if (TYPE_CODE (type1) != TYPE_CODE_DECFLOAT)
+      if (!is_floating_type (type1))
        result_type = type2;
-      else if (TYPE_CODE (type2) != TYPE_CODE_DECFLOAT)
-       result_type = type1;
-      else if (TYPE_LENGTH (type2) > TYPE_LENGTH (type1))
-       result_type = type2;
-      else
-       result_type = type1;
-
-      len_v = TYPE_LENGTH (result_type);
-      byte_order_v = gdbarch_byte_order (get_type_arch (result_type));
-
-      value_args_as_decimal (arg1, arg2, v1, &len_v1, &byte_order_v1,
-                                        v2, &len_v2, &byte_order_v2);
-
-      switch (op)
-       {
-       case BINOP_ADD:
-       case BINOP_SUB:
-       case BINOP_MUL:
-       case BINOP_DIV:
-       case BINOP_EXP:
-         decimal_binop (op, v1, len_v1, byte_order_v1,
-                            v2, len_v2, byte_order_v2,
-                            v, len_v, byte_order_v);
-         break;
-
-       default:
-         error (_("Operation not valid for decimal floating point number."));
-       }
-
-      val = value_from_decfloat (result_type, v);
-    }
-  else if (TYPE_CODE (type1) == TYPE_CODE_FLT
-          || TYPE_CODE (type2) == TYPE_CODE_FLT)
-    {
-      /* FIXME-if-picky-about-floating-accuracy: Should be doing this
-         in target format.  real.c in GCC probably has the necessary
-         code.  */
-      DOUBLEST v1, v2, v = 0;
-
-      v1 = value_as_double (arg1);
-      v2 = value_as_double (arg2);
-
-      switch (op)
-       {
-       case BINOP_ADD:
-         v = v1 + v2;
-         break;
-
-       case BINOP_SUB:
-         v = v1 - v2;
-         break;
-
-       case BINOP_MUL:
-         v = v1 * v2;
-         break;
-
-       case BINOP_DIV:
-         v = v1 / v2;
-         break;
-
-       case BINOP_EXP:
-         errno = 0;
-         v = pow (v1, v2);
-         if (errno)
-           error (_("Cannot perform exponentiation: %s"),
-                  safe_strerror (errno));
-         break;
-
-       case BINOP_MIN:
-         v = v1 < v2 ? v1 : v2;
-         break;
-             
-       case BINOP_MAX:
-         v = v1 > v2 ? v1 : v2;
-         break;
-
-       default:
-         error (_("Integer-only operation on floating point number."));
-       }
-
-      /* If only one type is float, use its type.
-        Otherwise use the bigger type.  */
-      if (TYPE_CODE (type1) != TYPE_CODE_FLT)
-       result_type = type2;
-      else if (TYPE_CODE (type2) != TYPE_CODE_FLT)
+      else if (!is_floating_type (type2))
        result_type = type1;
       else if (TYPE_LENGTH (type2) > TYPE_LENGTH (type1))
        result_type = type2;
@@ -1044,7 +941,18 @@ scalar_binop (struct value *arg1, struct value *arg2, enum exp_opcode op)
        result_type = type1;
 
       val = allocate_value (result_type);
-      store_typed_floating (value_contents_raw (val), value_type (val), v);
+
+      struct type *eff_type_v1, *eff_type_v2;
+      gdb::byte_vector v1, v2;
+      v1.resize (TYPE_LENGTH (result_type));
+      v2.resize (TYPE_LENGTH (result_type));
+
+      value_args_as_target_float (arg1, arg2,
+                                 v1.data (), &eff_type_v1,
+                                 v2.data (), &eff_type_v2);
+      target_float_binop (op, v1.data (), eff_type_v1,
+                             v2.data (), eff_type_v2,
+                             value_contents_raw (val), result_type);
     }
   else if (TYPE_CODE (type1) == TYPE_CODE_BOOL
           || TYPE_CODE (type2) == TYPE_CODE_BOOL)
@@ -1587,27 +1495,20 @@ value_equal (struct value *arg1, struct value *arg2)
   if (is_int1 && is_int2)
     return longest_to_int (value_as_long (value_binop (arg1, arg2,
                                                       BINOP_EQUAL)));
-  else if ((code1 == TYPE_CODE_FLT || is_int1)
-          && (code2 == TYPE_CODE_FLT || is_int2))
+  else if ((is_floating_value (arg1) || is_int1)
+          && (is_floating_value (arg2) || is_int2))
     {
-      /* NOTE: kettenis/20050816: Avoid compiler bug on systems where
-        `long double' values are returned in static storage (m68k).  */
-      DOUBLEST d = value_as_double (arg1);
+      struct type *eff_type_v1, *eff_type_v2;
+      gdb::byte_vector v1, v2;
+      v1.resize (std::max (TYPE_LENGTH (type1), TYPE_LENGTH (type2)));
+      v2.resize (std::max (TYPE_LENGTH (type1), TYPE_LENGTH (type2)));
 
-      return d == value_as_double (arg2);
-    }
-  else if ((code1 == TYPE_CODE_DECFLOAT || is_int1)
-          && (code2 == TYPE_CODE_DECFLOAT || is_int2))
-    {
-      gdb_byte v1[16], v2[16];
-      int len_v1, len_v2;
-      enum bfd_endian byte_order_v1, byte_order_v2;
-
-      value_args_as_decimal (arg1, arg2, v1, &len_v1, &byte_order_v1,
-                                        v2, &len_v2, &byte_order_v2);
+      value_args_as_target_float (arg1, arg2,
+                                 v1.data (), &eff_type_v1,
+                                 v2.data (), &eff_type_v2);
 
-      return decimal_compare (v1, len_v1, byte_order_v1,
-                             v2, len_v2, byte_order_v2) == 0;
+      return target_float_compare (v1.data (), eff_type_v1,
+                                  v2.data (), eff_type_v2) == 0;
     }
 
   /* FIXME: Need to promote to either CORE_ADDR or LONGEST, whichever
@@ -1683,27 +1584,20 @@ value_less (struct value *arg1, struct value *arg2)
   if (is_int1 && is_int2)
     return longest_to_int (value_as_long (value_binop (arg1, arg2,
                                                       BINOP_LESS)));
-  else if ((code1 == TYPE_CODE_FLT || is_int1)
-          && (code2 == TYPE_CODE_FLT || is_int2))
+  else if ((is_floating_value (arg1) || is_int1)
+          && (is_floating_value (arg2) || is_int2))
     {
-      /* NOTE: kettenis/20050816: Avoid compiler bug on systems where
-        `long double' values are returned in static storage (m68k).  */
-      DOUBLEST d = value_as_double (arg1);
+      struct type *eff_type_v1, *eff_type_v2;
+      gdb::byte_vector v1, v2;
+      v1.resize (std::max (TYPE_LENGTH (type1), TYPE_LENGTH (type2)));
+      v2.resize (std::max (TYPE_LENGTH (type1), TYPE_LENGTH (type2)));
 
-      return d < value_as_double (arg2);
-    }
-  else if ((code1 == TYPE_CODE_DECFLOAT || is_int1)
-          && (code2 == TYPE_CODE_DECFLOAT || is_int2))
-    {
-      gdb_byte v1[16], v2[16];
-      int len_v1, len_v2;
-      enum bfd_endian byte_order_v1, byte_order_v2;
+      value_args_as_target_float (arg1, arg2,
+                                 v1.data (), &eff_type_v1,
+                                 v2.data (), &eff_type_v2);
 
-      value_args_as_decimal (arg1, arg2, v1, &len_v1, &byte_order_v1,
-                                        v2, &len_v2, &byte_order_v2);
-
-      return decimal_compare (v1, len_v1, byte_order_v1,
-                             v2, len_v2, byte_order_v2) == -1;
+      return target_float_compare (v1.data (), eff_type_v1,
+                                  v2.data (), eff_type_v2) == -1;
     }
   else if (code1 == TYPE_CODE_PTR && code2 == TYPE_CODE_PTR)
     return value_as_address (arg1) < value_as_address (arg2);
@@ -1733,22 +1627,9 @@ value_pos (struct value *arg1)
   arg1 = coerce_ref (arg1);
   type = check_typedef (value_type (arg1));
 
-  if (TYPE_CODE (type) == TYPE_CODE_FLT)
-    return value_from_double (type, value_as_double (arg1));
-  else if (TYPE_CODE (type) == TYPE_CODE_DECFLOAT)
-    return value_from_decfloat (type, value_contents (arg1));
-  else if (is_integral_type (type))
-    {
-      return value_from_longest (type, value_as_long (arg1));
-    }
-  else if (TYPE_CODE (type) == TYPE_CODE_ARRAY && TYPE_VECTOR (type))
-    {
-      struct value *val = allocate_value (type);
-
-      memcpy (value_contents_raw (val), value_contents (arg1),
-              TYPE_LENGTH (type));
-      return val;
-    }
+  if (is_integral_type (type) || is_floating_value (arg1)
+      || (TYPE_CODE (type) == TYPE_CODE_ARRAY && TYPE_VECTOR (type)))
+    return value_from_contents (type, value_contents (arg1));
   else
     {
       error (_("Argument to positive operation not a number."));
@@ -1764,28 +1645,8 @@ value_neg (struct value *arg1)
   arg1 = coerce_ref (arg1);
   type = check_typedef (value_type (arg1));
 
-  if (TYPE_CODE (type) == TYPE_CODE_DECFLOAT)
-    {
-      struct value *val = allocate_value (type);
-      int len = TYPE_LENGTH (type);
-      gdb_byte decbytes[16];  /* a decfloat is at most 128 bits long.  */
-
-      memcpy (decbytes, value_contents (arg1), len);
-
-      if (gdbarch_byte_order (get_type_arch (type)) == BFD_ENDIAN_LITTLE)
-       decbytes[len-1] = decbytes[len - 1] | 0x80;
-      else
-       decbytes[0] = decbytes[0] | 0x80;
-
-      memcpy (value_contents_raw (val), decbytes, len);
-      return val;
-    }
-  else if (TYPE_CODE (type) == TYPE_CODE_FLT)
-    return value_from_double (type, -value_as_double (arg1));
-  else if (is_integral_type (type))
-    {
-      return value_from_longest (type, -value_as_long (arg1));
-    }
+  if (is_integral_type (type) || is_floating_type (type))
+    return value_binop (value_from_longest (type, 0), arg1, BINOP_SUB);
   else if (TYPE_CODE (type) == TYPE_CODE_ARRAY && TYPE_VECTOR (type))
     {
       struct value *tmp, *val = allocate_value (type);