summaryrefslogtreecommitdiff
path: root/gdb
diff options
context:
space:
mode:
authorThiago Jung Bauermann <bauerman@br.ibm.com>2008-01-07 22:33:57 +0000
committerThiago Jung Bauermann <bauerman@br.ibm.com>2008-01-07 22:33:57 +0000
commit1a608389302243453fd91ece782a57cd90edcecf (patch)
tree01ba1a4371cee056e02c75c1cb6b03eb83f89aad /gdb
parentb64d112298949ee9301ae9df472e933bc7554682 (diff)
downloadgdb-1a608389302243453fd91ece782a57cd90edcecf.tar.gz
* 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.
Diffstat (limited to 'gdb')
-rw-r--r--gdb/ChangeLog44
-rw-r--r--gdb/Makefile.in7
-rw-r--r--gdb/dfp.c299
-rw-r--r--gdb/dfp.h9
-rw-r--r--gdb/eval.c4
-rw-r--r--gdb/valarith.c132
-rw-r--r--gdb/valops.c20
-rw-r--r--gdb/value.c23
-rw-r--r--gdb/value.h5
9 files changed, 510 insertions, 33 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 66d677e337d..9052e28d155 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -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
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index ab3c3fff54a..45c3d298386 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -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) \
diff --git a/gdb/dfp.c b/gdb/dfp.c
index be01c931426..bf82114634b 100644
--- a/gdb/dfp.c
+++ b/gdb/dfp.c
@@ -18,6 +18,10 @@
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);
+}
diff --git a/gdb/dfp.h b/gdb/dfp.h
index 88bd59b3f00..f72337aa105 100644
--- a/gdb/dfp.h
+++ b/gdb/dfp.h
@@ -31,5 +31,14 @@
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
diff --git a/gdb/eval.c b/gdb/eval.c
index 1f84d23d2fb..188cca0e0b0 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -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;
diff --git a/gdb/valarith.c b/gdb/valarith.c
index 145419651b7..05ab8a13890 100644
--- a/gdb/valarith.c
+++ b/gdb/valarith.c
@@ -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)
}
+/* 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;
diff --git a/gdb/valops.c b/gdb/valops.c
index d7b49ea0586..bb4814f00ac 100644
--- a/gdb/valops.c
+++ b/gdb/valops.c
@@ -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
diff --git a/gdb/value.c b/gdb/value.c
index bb27625e08c..5fc12762c66 100644
--- a/gdb/value.c
+++ b/gdb/value.c
@@ -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;
}
diff --git a/gdb/value.h b/gdb/value.h
index d9627c2be93..7e1ccaf2984 100644
--- a/gdb/value.h
+++ b/gdb/value.h
@@ -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);