OSDN Git Service

* Makefile.in (dfp.o): Depend on expression.h, gdbtypes.h and value.h.
authorbauermann <bauermann>
Mon, 7 Jan 2008 22:33:56 +0000 (22:33 +0000)
committerbauermann <bauermann>
Mon, 7 Jan 2008 22:33:56 +0000 (22:33 +0000)
(valarith.o): Depend on dfp.h.
(valops.o): Likewise.
* dfp.c: Include expression.h, gdbtypes.h, value.h and dfp.h.
(set_decnumber_context): New function.
(decimal_check_errors): Likewise.
(decimal_from_number): Likewise.
(decimal_to_number): Likewise.
(decimal_from_string): Use set_decnumber_context and
decimal_check_errors.
(decimal_from_integral): New function.
(decimal_from_floating): Likewise.
(decimal_to_double): Likewise.
(promote_decimal): Likewise.
(decimal_binop): Likewise.
(decimal_is_zero): Likewise.
(decimal_compare): Likewise.
(decimal_convert): Likewise.
* dfp.h (decimal_from_integral): New prototype.
(decimal_from_floating): Likewise.
(decimal_to_double): Likewise.
(decimal_binop): Likewise.
(decimal_is_zero): Likewise.
(decimal_compare): Likewise.
(decimal_convert): Likewise.
* eval.c (evaluate_subexp_standard): Remove expect_type argument from
call to value_from_decfloat.
* valarith.c: Include dfp.h.
(value_args_as_decimal): New function.
(value_binop): Add if block to handle TYPE_CODE_DECFLOAT values.
(value_logical_not): Likewise.
(value_equal): Likewise.
(value_less): Likewise.
(value_pos): Likewise.
(value_neg): Formatting fix.
* valops.c: Include dfp.h.
(value_cast): Add if block to handle TYPE_CODE_DECFLOAT values.
* value.c (unpack_long): Add case to handle TYPE_CODE_DECFLOAT.
(unpack_double): Add if block to handle TYPE_CODE_DECFLOAT.
(value_from_decfloat): Remove expect_type argument.
* value.h (value_from_decfloat): Update prototype.

gdb/ChangeLog
gdb/Makefile.in
gdb/dfp.c
gdb/dfp.h
gdb/eval.c
gdb/valarith.c
gdb/valops.c
gdb/value.c
gdb/value.h

index 66d677e..9052e28 100644 (file)
@@ -1,3 +1,47 @@
+2008-01-07  Thiago Jung Bauermann  <bauerman@br.ibm.com>
+
+       * Makefile.in (dfp.o): Depend on expression.h, gdbtypes.h and value.h.
+       (valarith.o): Depend on dfp.h.
+       (valops.o): Likewise.
+       * dfp.c: Include expression.h, gdbtypes.h, value.h and dfp.h.
+       (set_decnumber_context): New function.
+       (decimal_check_errors): Likewise.
+       (decimal_from_number): Likewise.
+       (decimal_to_number): Likewise.
+       (decimal_from_string): Use set_decnumber_context and
+       decimal_check_errors.
+       (decimal_from_integral): New function.
+       (decimal_from_floating): Likewise.
+       (decimal_to_double): Likewise.
+       (promote_decimal): Likewise.
+       (decimal_binop): Likewise.
+       (decimal_is_zero): Likewise.
+       (decimal_compare): Likewise.
+       (decimal_convert): Likewise.
+       * dfp.h (decimal_from_integral): New prototype.
+       (decimal_from_floating): Likewise.
+       (decimal_to_double): Likewise.
+       (decimal_binop): Likewise.
+       (decimal_is_zero): Likewise.
+       (decimal_compare): Likewise.
+       (decimal_convert): Likewise.
+       * eval.c (evaluate_subexp_standard): Remove expect_type argument from
+       call to value_from_decfloat.
+       * valarith.c: Include dfp.h.
+       (value_args_as_decimal): New function.
+       (value_binop): Add if block to handle TYPE_CODE_DECFLOAT values.
+       (value_logical_not): Likewise.
+       (value_equal): Likewise.
+       (value_less): Likewise.
+       (value_pos): Likewise.
+       (value_neg): Formatting fix.
+       * valops.c: Include dfp.h.
+       (value_cast): Add if block to handle TYPE_CODE_DECFLOAT values.
+       * value.c (unpack_long): Add case to handle TYPE_CODE_DECFLOAT.
+       (unpack_double): Add if block to handle TYPE_CODE_DECFLOAT.
+       (value_from_decfloat): Remove expect_type argument.
+       * value.h (value_from_decfloat): Update prototype.
+
 2008-01-07  Vladimir Prus  <vladimir@codesourcery.com>
 
        Ignore change in name of dynamic linker during
index ab3c3ff..45c3d29 100644 (file)
@@ -2046,7 +2046,8 @@ dsrec.o: dsrec.c $(defs_h) $(serial_h) $(srec_h) $(gdb_assert_h) \
 dummy-frame.o: dummy-frame.c $(defs_h) $(dummy_frame_h) $(regcache_h) \
        $(frame_h) $(inferior_h) $(gdb_assert_h) $(frame_unwind_h) \
        $(command_h) $(gdbcmd_h) $(gdb_string_h)
-dfp.o: dfp.c $(defs_h) $(dfp_h) $(decimal128_h) $(decimal64_h) $(decimal32_h)
+dfp.o: dfp.c $(defs_h) $(expression_h) $(gdbtypes_h) $(value_h) $(dfp_h) \
+       $(decimal128_h) $(decimal64_h) $(decimal32_h)
 dwarf2expr.o: dwarf2expr.c $(defs_h) $(symtab_h) $(gdbtypes_h) $(value_h) \
        $(gdbcore_h) $(elf_dwarf2_h) $(dwarf2expr_h)
 dwarf2-frame.o: dwarf2-frame.c $(defs_h) $(dwarf2expr_h) $(elf_dwarf2_h) \
@@ -2910,12 +2911,12 @@ v850-tdep.o: v850-tdep.c $(defs_h) $(frame_h) $(frame_base_h) $(trad_frame_h) \
        $(regcache_h) $(dis_asm_h) $(osabi_h)
 valarith.o: valarith.c $(defs_h) $(value_h) $(symtab_h) $(gdbtypes_h) \
        $(expression_h) $(target_h) $(language_h) $(gdb_string_h) \
-       $(doublest_h) $(infcall_h)
+       $(doublest_h) $(dfp_h) $(infcall_h)
 valops.o: valops.c $(defs_h) $(symtab_h) $(gdbtypes_h) $(value_h) $(frame_h) \
        $(inferior_h) $(gdbcore_h) $(target_h) $(demangle_h) $(language_h) \
        $(gdbcmd_h) $(regcache_h) $(cp_abi_h) $(block_h) $(infcall_h) \
        $(dictionary_h) $(cp_support_h) $(gdb_string_h) $(gdb_assert_h) \
-       $(cp_support_h) $(observer_h)
+       $(cp_support_h) $(observer_h) $(dfp_h)
 valprint.o: valprint.c $(defs_h) $(gdb_string_h) $(symtab_h) $(gdbtypes_h) \
        $(value_h) $(gdbcore_h) $(gdbcmd_h) $(target_h) $(language_h) \
        $(annotate_h) $(valprint_h) $(floatformat_h) $(doublest_h) \
index be01c93..bf82114 100644 (file)
--- a/gdb/dfp.c
+++ b/gdb/dfp.c
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #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
    decNumber structure is large enough to hold decimal128 digits.  */
@@ -50,6 +54,89 @@ match_endianness (const gdb_byte *from, int len, gdb_byte *to)
   return;
 }
 
+/* Helper function to get the appropriate libdecnumber context for each size
+   of decimal float.  */
+static void
+set_decnumber_context (decContext *ctx, int len)
+{
+  switch (len)
+    {
+      case 4:
+       decContextDefault (ctx, DEC_INIT_DECIMAL32);
+       break;
+      case 8:
+       decContextDefault (ctx, DEC_INIT_DECIMAL64);
+       break;
+      case 16:
+       decContextDefault (ctx, DEC_INIT_DECIMAL128);
+       break;
+    }
+
+  ctx->traps = 0;
+}
+
+/* Check for errors signaled in the decimal context structure.  */
+static void
+decimal_check_errors (decContext *ctx)
+{
+  /* An error here could be a division by zero, an overflow, an underflow or
+     an invalid operation (from the DEC_Errors constant in decContext.h).
+     Since GDB doesn't complain about division by zero, overflow or underflow
+     errors for binary floating, we won't complain about them for decimal
+     floating either.  */
+  if (ctx->status & DEC_IEEE_854_Invalid_operation)
+    {
+      /* Leave only the error bits in the status flags.  */
+      ctx->status &= DEC_IEEE_854_Invalid_operation;
+      error (_("Cannot perform operation: %s"), decContextStatusToString (ctx));
+    }
+}
+
+/* Helper function to convert from libdecnumber's appropriate representation
+   for computation to each size of decimal float.  */
+static void
+decimal_from_number (const decNumber *from, gdb_byte *to, int len)
+{
+  decContext set;
+
+  set_decnumber_context (&set, len);
+
+  switch (len)
+    {
+      case 4:
+       decimal32FromNumber ((decimal32 *) to, from, &set);
+       break;
+      case 8:
+       decimal64FromNumber ((decimal64 *) to, from, &set);
+       break;
+      case 16:
+       decimal128FromNumber ((decimal128 *) to, from, &set);
+       break;
+    }
+}
+
+/* Helper function to convert each size of decimal float to libdecnumber's
+   appropriate representation for computation.  */
+static void
+decimal_to_number (const gdb_byte *from, int len, decNumber *to)
+{
+  switch (len)
+    {
+      case 4:
+       decimal32ToNumber ((decimal32 *) from, to);
+       break;
+      case 8:
+       decimal64ToNumber ((decimal64 *) from, to);
+       break;
+      case 16:
+       decimal128ToNumber ((decimal128 *) from, to);
+       break;
+      default:
+       error (_("Unknown decimal floating point type.\n"));
+       break;
+    }
+}
+
 /* 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.  */
@@ -59,6 +146,7 @@ decimal_to_string (const gdb_byte *decbytes, int len, char *s)
   gdb_byte dec[16];
 
   match_endianness (decbytes, len, dec);
+
   switch (len)
     {
       case 4:
@@ -85,21 +173,17 @@ decimal_from_string (gdb_byte *decbytes, int len, const char *string)
   decContext set;
   gdb_byte dec[16];
 
+  set_decnumber_context (&set, len);
+
   switch (len)
     {
       case 4:
-       decContextDefault (&set, DEC_INIT_DECIMAL32);
-       set.traps = 0;
        decimal32FromString ((decimal32 *) dec, string, &set);
        break;
       case 8:
-       decContextDefault (&set, DEC_INIT_DECIMAL64);
-       set.traps = 0;
        decimal64FromString ((decimal64 *) dec, string, &set);
        break;
       case 16:
-       decContextDefault (&set, DEC_INIT_DECIMAL128);
-       set.traps = 0;
        decimal128FromString ((decimal128 *) dec, string, &set);
        break;
       default:
@@ -109,5 +193,208 @@ decimal_from_string (gdb_byte *decbytes, int len, const char *string)
 
   match_endianness (dec, len, decbytes);
 
+  /* Check for errors in the DFP operation.  */
+  decimal_check_errors (&set);
+
   return 1;
 }
+
+/* Converts a value of an integral type to a decimal float of
+   specified LEN bytes.  */
+void
+decimal_from_integral (struct value *from, gdb_byte *to, int len)
+{
+  LONGEST l;
+  gdb_byte dec[16];
+  decNumber number;
+  struct type *type;
+
+  type = check_typedef (value_type (from));
+
+  if (TYPE_LENGTH (type) > 4)
+    /* 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);
+
+  decimal_from_number (&number, dec, len);
+  match_endianness (dec, len, to);
+}
+
+/* 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, gdb_byte *to, int len)
+{
+  char *buffer;
+  int ret;
+
+  ret = asprintf (&buffer, "%.30Lg", value_as_double (from));
+  if (ret < 0)
+    error (_("Error in memory allocation for conversion to decimal float."));
+
+  decimal_from_string (to, len, buffer);
+
+  free (buffer);
+}
+
+/* Converts a decimal float of LEN bytes to a double value.  */
+DOUBLEST
+decimal_to_double (const gdb_byte *from, int len)
+{
+  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, buffer);
+  return strtod (buffer, NULL);
+}
+
+/* Check if operands have the same size and convert them to the
+   biggest of the two if necessary.  */
+static int
+promote_decimal (gdb_byte *x, int len_x, gdb_byte *y, int len_y)
+{
+  int len_result;
+  decNumber number;
+
+  if (len_x < len_y)
+    {
+      decimal_to_number (x, len_x, &number);
+      decimal_from_number (&number, x, len_y);
+      len_result = len_y;
+    }
+  else if (len_x > len_y)
+    {
+      decimal_to_number (y, len_y, &number);
+      decimal_from_number (&number, y, len_x);
+      len_result = len_x;
+    }
+  else
+    len_result = len_x;
+
+  return len_result;
+}
+
+/* Perform operation OP with operands X and Y and store value in RESULT.
+   If LEN_X and LEN_Y are not equal, RESULT will have the size of the biggest
+   of the two, and LEN_RESULT will be set accordingly.  */
+void
+decimal_binop (enum exp_opcode op, const gdb_byte *x, int len_x,
+              const gdb_byte *y, int len_y, gdb_byte *result, int *len_result)
+{
+  decContext set;
+  decNumber number1, number2, number3;
+  gdb_byte dec1[16], dec2[16], dec3[16];
+
+  match_endianness (x, len_x, dec1);
+  match_endianness (y, len_y, dec2);
+
+  *len_result = promote_decimal (dec1, len_x, dec2, len_y);
+
+  /* Both operands are of size *len_result from now on.  */
+
+  decimal_to_number (dec1, *len_result, &number1);
+  decimal_to_number (dec2, *len_result, &number2);
+
+  set_decnumber_context (&set, *len_result);
+
+  switch (op)
+    {
+      case BINOP_ADD:
+       decNumberAdd (&number3, &number1, &number2, &set);
+       break;
+      case BINOP_SUB:
+       decNumberSubtract (&number3, &number1, &number2, &set);
+       break;
+      case BINOP_MUL:
+       decNumberMultiply (&number3, &number1, &number2, &set);
+       break;
+      case BINOP_DIV:
+       decNumberDivide (&number3, &number1, &number2, &set);
+       break;
+      case BINOP_EXP:
+       decNumberPower (&number3, &number1, &number2, &set);
+       break;
+      default:
+       internal_error (__FILE__, __LINE__,
+                       _("Unknown decimal floating point operation."));
+       break;
+    }
+
+  /* Check for errors in the DFP operation.  */
+  decimal_check_errors (&set);
+
+  decimal_from_number (&number3, dec3, *len_result);
+
+  match_endianness (dec3, *len_result, result);
+}
+
+/* Returns true if X (which is LEN bytes wide) is the number zero.  */
+int
+decimal_is_zero (const gdb_byte *x, int len)
+{
+  decNumber number;
+  gdb_byte dec[16];
+
+  match_endianness (x, len, dec);
+  decimal_to_number (dec, len, &number);
+
+  return decNumberIsZero (&number);
+}
+
+/* Compares two numbers numerically.  If X is less than Y then the return value
+   will be -1.  If they are equal, then the return value will be 0.  If X is
+   greater than the Y then the return value will be 1.  */
+int
+decimal_compare (const gdb_byte *x, int len_x, const gdb_byte *y, int len_y)
+{
+  decNumber number1, number2, result;
+  decContext set;
+  gdb_byte dec1[16], dec2[16];
+  int len_result;
+
+  match_endianness (x, len_x, dec1);
+  match_endianness (y, len_y, dec2);
+
+  len_result = promote_decimal (dec1, len_x, dec2, len_y);
+
+  decimal_to_number (dec1, len_result, &number1);
+  decimal_to_number (dec2, len_result, &number2);
+
+  set_decnumber_context (&set, len_result);
+
+  decNumberCompare (&result, &number1, &number2, &set);
+
+  /* Check for errors in the DFP operation.  */
+  decimal_check_errors (&set);
+
+  if (decNumberIsNaN (&result))
+    error (_("Comparison with an invalid number (NaN)."));
+  else if (decNumberIsZero (&result))
+    return 0;
+  else if (decNumberIsNegative (&result))
+    return -1;
+  else
+    return 1;
+}
+
+/* Convert a decimal value from a decimal type with LEN_FROM bytes to a
+   decimal type with LEN_TO bytes.  */
+void
+decimal_convert (const gdb_byte *from, int len_from, gdb_byte *to,
+                int len_to)
+{
+  decNumber number;
+
+  decimal_to_number (from, len_from, &number);
+  decimal_from_number (&number, to, len_to);
+}
index 88bd59b..f72337a 100644 (file)
--- a/gdb/dfp.h
+++ b/gdb/dfp.h
 
 extern void decimal_to_string (const gdb_byte *, int, char *);
 extern int decimal_from_string (gdb_byte *, int, const char *);
+extern void decimal_from_integral (struct value *from, gdb_byte *to, int len);
+extern void decimal_from_floating (struct value *from, gdb_byte *to, int len);
+extern DOUBLEST decimal_to_double (const gdb_byte *from, int len);
+extern void decimal_binop (enum exp_opcode, const gdb_byte *, int,
+                          const gdb_byte *, int, gdb_byte *, int *);
+extern int decimal_is_zero (const gdb_byte *x, int len);
+extern int decimal_compare (const gdb_byte *x, int len_x, const gdb_byte *y, int len_y);
+extern void decimal_convert (const gdb_byte *from, int len_from, gdb_byte *to,
+                            int len_to);
 
 #endif
index 1f84d23..188cca0 100644 (file)
@@ -458,8 +458,8 @@ evaluate_subexp_standard (struct type *expect_type,
 
     case OP_DECFLOAT:
       (*pos) += 3;
-      return value_from_decfloat (expect_type, exp->elts[pc + 1].type,
-                               exp->elts[pc + 2].decfloatconst);
+      return value_from_decfloat (exp->elts[pc + 1].type,
+                                 exp->elts[pc + 2].decfloatconst);
 
     case OP_VAR_VALUE:
       (*pos) += 3;
index 1454196..05ab8a1 100644 (file)
@@ -28,6 +28,7 @@
 #include "language.h"
 #include "gdb_string.h"
 #include "doublest.h"
+#include "dfp.h"
 #include <math.h>
 #include "infcall.h"
 
@@ -741,6 +742,62 @@ value_concat (struct value *arg1, struct value *arg2)
 }
 \f
 
+/* Obtain decimal value of arguments for binary operation, converting from
+   other types if one of them is not decimal floating point.  */
+static void
+value_args_as_decimal (struct value *arg1, struct value *arg2,
+                      gdb_byte *x, int *len_x, gdb_byte *y, int *len_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);
+
+  if (TYPE_CODE (type1) == TYPE_CODE_FLT
+      || TYPE_CODE (type2) == TYPE_CODE_FLT)
+    /* 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.  */
+
+  if (TYPE_CODE (type1) == TYPE_CODE_DECFLOAT)
+    {
+      *len_x = TYPE_LENGTH (type1);
+      memcpy (x, value_contents (arg1), *len_x);
+    }
+  else if (is_integral_type (type1))
+    {
+      *len_x = TYPE_LENGTH (type2);
+      decimal_from_integral (arg1, x, *len_x);
+    }
+  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.  */
+
+  if (TYPE_CODE (type2) == TYPE_CODE_DECFLOAT)
+    {
+      *len_y = TYPE_LENGTH (type2);
+      memcpy (y, value_contents (arg2), *len_y);
+    }
+  else if (is_integral_type (type2))
+    {
+      *len_y = TYPE_LENGTH (type1);
+      decimal_from_integral (arg2, y, *len_y);
+    }
+  else
+    error (_("Don't know how to convert from %s to %s."), TYPE_NAME (type1),
+            TYPE_NAME (type2));
+}
 
 /* Perform a binary operation on two operands which have reasonable
    representations as integers or floats.  This includes booleans,
@@ -759,14 +816,55 @@ value_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 && !is_integral_type (type1))
+  if ((TYPE_CODE (type1) != TYPE_CODE_FLT
+       && TYPE_CODE (type1) != TYPE_CODE_DECFLOAT && !is_integral_type (type1))
       ||
-      (TYPE_CODE (type2) != TYPE_CODE_FLT && !is_integral_type (type2)))
+      (TYPE_CODE (type2) != TYPE_CODE_FLT
+       && TYPE_CODE (type2) != TYPE_CODE_DECFLOAT && !is_integral_type (type2)))
     error (_("Argument to arithmetic operation not a number or boolean."));
 
-  if (TYPE_CODE (type1) == TYPE_CODE_FLT
+  if (TYPE_CODE (type1) == TYPE_CODE_DECFLOAT
       ||
-      TYPE_CODE (type2) == TYPE_CODE_FLT)
+      TYPE_CODE (type2) == TYPE_CODE_DECFLOAT)
+    {
+      struct type *v_type;
+      int len_v1, len_v2, len_v;
+      gdb_byte v1[16], v2[16];
+      gdb_byte v[16];
+
+      value_args_as_decimal (arg1, arg2, v1, &len_v1, v2, &len_v2);
+
+      switch (op)
+       {
+       case BINOP_ADD:
+       case BINOP_SUB:
+       case BINOP_MUL:
+       case BINOP_DIV:
+       case BINOP_EXP:
+         decimal_binop (op, v1, len_v1, v2, len_v2, v, &len_v);
+         break;
+
+       default:
+         error (_("Operation not valid for decimal floating point number."));
+       }
+
+      if (TYPE_CODE (type1) != TYPE_CODE_DECFLOAT)
+       /* If arg1 is not a decimal float, the type of the result is the type
+          of the decimal float argument, arg2.  */
+       v_type = type2;
+      else if (TYPE_CODE (type2) != TYPE_CODE_DECFLOAT)
+       /* Same logic, for the case where arg2 is not a decimal float.  */
+       v_type = type1;
+      else
+       /* len_v is equal either to len_v1 or to len_v2.  the type of the
+          result is the type of the argument with the same length as v.  */
+       v_type = (len_v == len_v1)? type1 : type2;
+
+      val = value_from_decfloat (v_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
@@ -1177,6 +1275,8 @@ value_logical_not (struct value *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));
 
   len = TYPE_LENGTH (type1);
   p = value_contents (arg1);
@@ -1255,6 +1355,16 @@ value_equal (struct value *arg1, struct value *arg2)
       DOUBLEST d = value_as_double (arg1);
       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;
+
+      value_args_as_decimal (arg1, arg2, v1, &len_v1, v2, &len_v2);
+
+      return decimal_compare (v1, len_v1, v2, len_v2) == 0;
+    }
 
   /* FIXME: Need to promote to either CORE_ADDR or LONGEST, whichever
      is bigger.  */
@@ -1319,6 +1429,16 @@ value_less (struct value *arg1, struct value *arg2)
       DOUBLEST d = value_as_double (arg1);
       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;
+
+      value_args_as_decimal (arg1, arg2, v1, &len_v1, v2, &len_v2);
+
+      return decimal_compare (v1, len_v1, v2, len_v2) == -1;
+    }
   else if (code1 == TYPE_CODE_PTR && code2 == TYPE_CODE_PTR)
     return value_as_address (arg1) < value_as_address (arg2);
 
@@ -1350,6 +1470,8 @@ value_pos (struct value *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))
     {
       /* Perform integral promotion for ANSI C/C++.  FIXME: What about
@@ -1382,7 +1504,7 @@ value_neg (struct value *arg1)
       int len = TYPE_LENGTH (type);
       gdb_byte decbytes[16];  /* a decfloat is at most 128 bits long */
 
-      memcpy(decbytes, value_contents(arg1), len);
+      memcpy (decbytes, value_contents (arg1), len);
 
       if (gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_LITTLE)
        decbytes[len-1] = decbytes[len - 1] | 0x80;
index d7b49ea..bb4814f 100644 (file)
@@ -36,6 +36,7 @@
 #include "infcall.h"
 #include "dictionary.h"
 #include "cp-support.h"
+#include "dfp.h"
 
 #include <errno.h>
 #include "gdb_string.h"
@@ -338,7 +339,8 @@ value_cast (struct type *type, struct value *arg2)
     code2 = TYPE_CODE_INT;
 
   scalar = (code2 == TYPE_CODE_INT || code2 == TYPE_CODE_FLT
-           || code2 == TYPE_CODE_ENUM || code2 == TYPE_CODE_RANGE);
+           || code2 == TYPE_CODE_DECFLOAT || code2 == TYPE_CODE_ENUM
+           || code2 == TYPE_CODE_RANGE);
 
   if (code1 == TYPE_CODE_STRUCT
       && code2 == TYPE_CODE_STRUCT
@@ -357,6 +359,22 @@ value_cast (struct type *type, struct value *arg2)
     }
   if (code1 == TYPE_CODE_FLT && scalar)
     return value_from_double (type, value_as_double (arg2));
+  else if (code1 == TYPE_CODE_DECFLOAT && scalar)
+    {
+      int dec_len = TYPE_LENGTH (type);
+      gdb_byte dec[16];
+
+      if (code2 == TYPE_CODE_FLT)
+       decimal_from_floating (arg2, dec, dec_len);
+      else if (code2 == TYPE_CODE_DECFLOAT)
+       decimal_convert (value_contents (arg2), TYPE_LENGTH (type2),
+                        dec, dec_len);
+      else
+       /* The only option left is an integral type.  */
+       decimal_from_integral (arg2, dec, dec_len);
+
+      return value_from_decfloat (type, dec);
+    }
   else if ((code1 == TYPE_CODE_INT || code1 == TYPE_CODE_ENUM
            || code1 == TYPE_CODE_RANGE)
           && (scalar || code2 == TYPE_CODE_PTR
index bb27625..5fc1276 100644 (file)
@@ -982,6 +982,7 @@ value_as_double (struct value *val)
     error (_("Invalid floating value found in program."));
   return foo;
 }
+
 /* Extract a value as a C pointer. Does not deallocate the value.  
    Note that val's type may not actually be a pointer; value_as_long
    handles all the cases.  */
@@ -1127,6 +1128,11 @@ unpack_long (struct type *type, const gdb_byte *valaddr)
     case TYPE_CODE_FLT:
       return 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 decimal_to_double (valaddr, len);
+
     case TYPE_CODE_PTR:
     case TYPE_CODE_REF:
       /* Assume a CORE_ADDR can fit in a LONGEST (for now).  Not sure
@@ -1184,6 +1190,8 @@ unpack_double (struct type *type, const gdb_byte *valaddr, int *invp)
 
       return extract_typed_floating (valaddr, type);
     }
+  else if (code == TYPE_CODE_DECFLOAT)
+    return decimal_to_double (valaddr, len);
   else if (nosign)
     {
       /* Unsigned -- be sure we compensate for signed LONGEST.  */
@@ -1643,23 +1651,12 @@ value_from_double (struct type *type, DOUBLEST num)
 }
 
 struct value *
-value_from_decfloat (struct type *expect_type, struct type *type,
-                     gdb_byte decbytes[16])
+value_from_decfloat (struct type *type, const gdb_byte *dec)
 {
   struct value *val = allocate_value (type);
-  int len = TYPE_LENGTH (type);
 
-  if (expect_type)
-    {
-      int expect_len = TYPE_LENGTH (expect_type);
-      char decstr[MAX_DECIMAL_STRING];
-      int real_len;
-
-      decimal_to_string (decbytes, len, decstr);
-      decimal_from_string (decbytes, expect_len, decstr);
-    }
+  memcpy (value_contents_raw (val), dec, TYPE_LENGTH (type));
 
-  memcpy (value_contents_raw (val), decbytes, len);
   return val;
 }
 
index d9627c2..7e1ccaf 100644 (file)
@@ -280,9 +280,8 @@ extern void pack_long (gdb_byte *buf, struct type *type, LONGEST num);
 extern struct value *value_from_longest (struct type *type, LONGEST num);
 extern struct value *value_from_pointer (struct type *type, CORE_ADDR addr);
 extern struct value *value_from_double (struct type *type, DOUBLEST num);
-extern struct value *value_from_decfloat (struct type *expect_type,
-                                         struct type *type,
-                                         gdb_byte decbytes[16]);
+extern struct value *value_from_decfloat (struct type *type,
+                                         const gdb_byte *decbytes);
 extern struct value *value_from_string (char *string);
 
 extern struct value *value_at (struct type *type, CORE_ADDR addr);