diff options
author | Ulrich Weigand <ulrich.weigand@de.ibm.com> | 2017-11-06 15:57:31 +0100 |
---|---|---|
committer | Ulrich Weigand <ulrich.weigand@de.ibm.com> | 2017-11-06 15:57:31 +0100 |
commit | 50637b26f85dc3e59b616f1b01ca8885cf98f0b4 (patch) | |
tree | 9802b0d858d7571b8a56d752733ee2c58658eecf /gdb/target-float.c | |
parent | f69fdf9bca80ac703890a51e124e408cbccbb743 (diff) | |
download | binutils-gdb-50637b26f85dc3e59b616f1b01ca8885cf98f0b4.tar.gz |
Target FP: Add conversion routines to target-float.{c,h}
This patch adds the following conversion routines:
- target_float_to_longest
- target_float_from_longest
- target_float_from_ulongest
- target_float_convert
which call the equivalent decimal_ routines to handle decimal FP,
and call helper routines that currently still go via DOUBLEST to
handle binary FP.
The target_float_convert routine not only handles BFP<->BFP and
DFP<->DFP conversions, but also BFP<->DFP, which are implemented
by converting to a string and back.
These helpers are used in particular to implement conversion
from and to FP in value_cast, without going through DOUBLEST there.
In order to implement this for the FP<-integer case, the
pack_long / pack_unsigned_long routines are extended to support
floating-point values as output (thereby allowing use of
value_from_[u]longest with a floating-point target type).
This latter change also allows simplification of value_one.
gdb/ChangeLog:
2017-11-06 Ulrich Weigand <uweigand@de.ibm.com>
* target-float.c (floatformat_to_longest): New function.
(floatformat_from_longest, floatformat_from_ulongest): Likewise.
(floatformat_convert): Likewise.
(target_float_to_longest): Likewise.
(target_float_from_longest, target_float_from_ulongest): Likewise.
(target_float_convert): Likewise.
* target-float.h (target_float_to_longest): Add prototype.
(target_float_from_longest, target_float_from_ulongest): Likewise.
(target_float_convert): Likewise.
* value.c (unpack_long): Use target_float_to_longest.
(pack_long): Allow FP types. Use target_float_from_longest.
(pack_unsigned_long): Likewise using target_float_from_ulongest.
* valops.c: Include "target-float.h". Do not include "dfp.h".
(value_cast): Handle conversions to FP using target_float_convert,
value_from_ulongest, and value_from_longest.
(value_one): Use value_from_longest for FP types as well.
Diffstat (limited to 'gdb/target-float.c')
-rw-r--r-- | gdb/target-float.c | 169 |
1 files changed, 169 insertions, 0 deletions
diff --git a/gdb/target-float.c b/gdb/target-float.c index e90cf037868..117892161f9 100644 --- a/gdb/target-float.c +++ b/gdb/target-float.c @@ -25,6 +25,64 @@ #include "target-float.h" +/* Helper routines operating on binary floating-point data. */ + +/* Convert the byte-stream ADDR, interpreted as floating-point format FMT, + to an integer value (rounding towards zero). */ +static LONGEST +floatformat_to_longest (const struct floatformat *fmt, const gdb_byte *addr) +{ + DOUBLEST d; + floatformat_to_doublest (fmt, addr, &d); + return (LONGEST) d; +} + +/* Convert signed integer VAL to a target floating-number of format FMT + and store it as byte-stream ADDR. */ +static void +floatformat_from_longest (const struct floatformat *fmt, gdb_byte *addr, + LONGEST val) +{ + DOUBLEST d = (DOUBLEST) val; + floatformat_from_doublest (fmt, &d, addr); +} + +/* Convert unsigned integer VAL to a target floating-number of format FMT + and store it as byte-stream ADDR. */ +static void +floatformat_from_ulongest (const struct floatformat *fmt, gdb_byte *addr, + ULONGEST val) +{ + DOUBLEST d = (DOUBLEST) val; + floatformat_from_doublest (fmt, &d, addr); +} + +/* Convert a floating-point number of format FROM_FMT from the target + byte-stream FROM to a floating-point number of format TO_FMT, and + store it to the target byte-stream TO. */ +static void +floatformat_convert (const gdb_byte *from, const struct floatformat *from_fmt, + gdb_byte *to, const struct floatformat *to_fmt) +{ + if (from_fmt == to_fmt) + { + /* The floating-point formats match, so we simply copy the data. */ + memcpy (to, from, floatformat_totalsize_bytes (to_fmt)); + } + else + { + /* The floating-point formats don't match. The best we can do + (apart from simulating the target FPU) is converting to the + widest floating-point type supported by the host, and then + again to the desired type. */ + DOUBLEST d; + + floatformat_to_doublest (from_fmt, from, &d); + floatformat_from_doublest (to_fmt, &d, to); + } +} + + /* Typed floating-point routines. These routines operate on floating-point values in target format, represented by a byte buffer interpreted as a "struct type", which may be either a binary or decimal floating-point @@ -97,3 +155,114 @@ target_float_from_string (gdb_byte *addr, const struct type *type, gdb_assert_not_reached ("unexpected type code"); } + +/* Convert the byte-stream ADDR, interpreted as floating-point type TYPE, + to an integer value (rounding towards zero). */ +LONGEST +target_float_to_longest (const gdb_byte *addr, const struct type *type) +{ + if (TYPE_CODE (type) == TYPE_CODE_FLT) + return floatformat_to_longest (floatformat_from_type (type), addr); + + if (TYPE_CODE (type) == TYPE_CODE_DECFLOAT) + return decimal_to_longest (addr, TYPE_LENGTH (type), + gdbarch_byte_order (get_type_arch (type))); + + gdb_assert_not_reached ("unexpected type code"); +} + +/* Convert signed integer VAL to a target floating-number of type TYPE + and store it as byte-stream ADDR. */ +void +target_float_from_longest (gdb_byte *addr, const struct type *type, + LONGEST val) +{ + /* Ensure possible padding bytes in the target buffer are zeroed out. */ + memset (addr, 0, TYPE_LENGTH (type)); + + if (TYPE_CODE (type) == TYPE_CODE_FLT) + { + floatformat_from_longest (floatformat_from_type (type), addr, val); + return; + } + + if (TYPE_CODE (type) == TYPE_CODE_DECFLOAT) + { + decimal_from_longest (val, addr, TYPE_LENGTH (type), + gdbarch_byte_order (get_type_arch (type))); + return; + } + + gdb_assert_not_reached ("unexpected type code"); +} + +/* Convert unsigned integer VAL to a target floating-number of type TYPE + and store it as byte-stream ADDR. */ +void +target_float_from_ulongest (gdb_byte *addr, const struct type *type, + ULONGEST val) +{ + /* Ensure possible padding bytes in the target buffer are zeroed out. */ + memset (addr, 0, TYPE_LENGTH (type)); + + if (TYPE_CODE (type) == TYPE_CODE_FLT) + { + floatformat_from_ulongest (floatformat_from_type (type), addr, val); + return; + } + + if (TYPE_CODE (type) == TYPE_CODE_DECFLOAT) + { + decimal_from_ulongest (val, addr, TYPE_LENGTH (type), + gdbarch_byte_order (get_type_arch (type))); + return; + } + + gdb_assert_not_reached ("unexpected type code"); +} + +/* Convert a floating-point number of type FROM_TYPE from the target + byte-stream FROM to a floating-point number of type TO_TYPE, and + store it to the target byte-stream TO. */ +void +target_float_convert (const gdb_byte *from, const struct type *from_type, + gdb_byte *to, const struct type *to_type) +{ + /* Ensure possible padding bytes in the target buffer are zeroed out. */ + memset (to, 0, TYPE_LENGTH (to_type)); + + /* Use direct conversion routines if we have them. */ + + if (TYPE_CODE (from_type) == TYPE_CODE_FLT + && TYPE_CODE (to_type) == TYPE_CODE_FLT) + { + floatformat_convert (from, floatformat_from_type (from_type), + to, floatformat_from_type (to_type)); + return; + } + + if (TYPE_CODE (from_type) == TYPE_CODE_DECFLOAT + && TYPE_CODE (to_type) == TYPE_CODE_DECFLOAT) + { + decimal_convert (from, TYPE_LENGTH (from_type), + gdbarch_byte_order (get_type_arch (from_type)), + to, TYPE_LENGTH (to_type), + gdbarch_byte_order (get_type_arch (to_type))); + return; + } + + /* We cannot directly convert between binary and decimal floating-point + types, so go via an intermediary string. */ + + if ((TYPE_CODE (from_type) == TYPE_CODE_FLT + && TYPE_CODE (to_type) == TYPE_CODE_DECFLOAT) + || (TYPE_CODE (from_type) == TYPE_CODE_DECFLOAT + && TYPE_CODE (to_type) == TYPE_CODE_FLT)) + { + std::string str = target_float_to_string (from, from_type); + target_float_from_string (to, to_type, str); + return; + } + + gdb_assert_not_reached ("unexpected type code"); +} |