diff options
-rw-r--r-- | gdb/ChangeLog | 26 | ||||
-rw-r--r-- | gdb/dfp.c | 5 | ||||
-rw-r--r-- | gdb/target-float.c | 152 | ||||
-rw-r--r-- | gdb/target-float.h | 9 | ||||
-rw-r--r-- | gdb/valarith.c | 277 |
5 files changed, 258 insertions, 211 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 6ee299d..6d3c6a1 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,5 +1,31 @@ 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. (target_float_from_string): New function. * target-float.h (target_float_to_string): Add prototype. @@ -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; } diff --git a/gdb/target-float.c b/gdb/target-float.c index 1178921..ad04f8f 100644 --- a/gdb/target-float.c +++ b/gdb/target-float.c @@ -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"); +} + diff --git a/gdb/target-float.h b/gdb/target-float.h index 9ea1812..466dd1b 100644 --- a/gdb/target-float.h +++ b/gdb/target-float.h @@ -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 diff --git a/gdb/valarith.c b/gdb/valarith.c index 3e52e9d..89e44f3 100644 --- a/gdb/valarith.c +++ b/gdb/valarith.c @@ -24,11 +24,9 @@ #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); |