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.
This commit is contained in:
parent
f69fdf9bca
commit
50637b26f8
4 changed files with 205 additions and 36 deletions
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -32,4 +32,16 @@ extern bool target_float_from_string (gdb_byte *addr,
|
|||
const struct type *type,
|
||||
const std::string &string);
|
||||
|
||||
extern LONGEST target_float_to_longest (const gdb_byte *addr,
|
||||
const struct type *type);
|
||||
extern void target_float_from_longest (gdb_byte *addr,
|
||||
const struct type *type,
|
||||
LONGEST val);
|
||||
extern void target_float_from_ulongest (gdb_byte *addr,
|
||||
const struct type *type,
|
||||
ULONGEST val);
|
||||
extern void target_float_convert (const gdb_byte *from,
|
||||
const struct type *from_type,
|
||||
gdb_byte *to, const struct type *to_type);
|
||||
|
||||
#endif
|
||||
|
|
46
gdb/valops.c
46
gdb/valops.c
|
@ -34,7 +34,7 @@
|
|||
#include "infcall.h"
|
||||
#include "dictionary.h"
|
||||
#include "cp-support.h"
|
||||
#include "dfp.h"
|
||||
#include "target-float.h"
|
||||
#include "tracepoint.h"
|
||||
#include "observer.h"
|
||||
#include "objfiles.h"
|
||||
|
@ -462,29 +462,21 @@ value_cast (struct type *type, struct value *arg2)
|
|||
return v;
|
||||
}
|
||||
|
||||
if (code1 == TYPE_CODE_FLT && scalar)
|
||||
return value_from_double (to_type, value_as_double (arg2));
|
||||
else if (code1 == TYPE_CODE_DECFLOAT && scalar)
|
||||
if (is_floating_type (type) && scalar)
|
||||
{
|
||||
enum bfd_endian byte_order = gdbarch_byte_order (get_type_arch (type));
|
||||
int dec_len = TYPE_LENGTH (type);
|
||||
gdb_byte dec[16];
|
||||
if (is_floating_value (arg2))
|
||||
{
|
||||
struct value *v = allocate_value (to_type);
|
||||
target_float_convert (value_contents (arg2), type2,
|
||||
value_contents_raw (v), type);
|
||||
return v;
|
||||
}
|
||||
|
||||
if (code2 == TYPE_CODE_FLT)
|
||||
decimal_from_doublest (value_as_double (arg2),
|
||||
dec, dec_len, byte_order);
|
||||
else if (code2 == TYPE_CODE_DECFLOAT)
|
||||
decimal_convert (value_contents (arg2), TYPE_LENGTH (type2),
|
||||
byte_order, dec, dec_len, byte_order);
|
||||
/* The only option left is an integral type. */
|
||||
else if (TYPE_UNSIGNED (type2))
|
||||
decimal_from_ulongest (value_as_long (arg2),
|
||||
dec, dec_len, byte_order);
|
||||
if (TYPE_UNSIGNED (type2))
|
||||
return value_from_ulongest (to_type, value_as_long (arg2));
|
||||
else
|
||||
decimal_from_longest (value_as_long (arg2),
|
||||
dec, dec_len, byte_order);
|
||||
|
||||
return value_from_decfloat (to_type, dec);
|
||||
return value_from_longest (to_type, value_as_long (arg2));
|
||||
}
|
||||
else if ((code1 == TYPE_CODE_INT || code1 == TYPE_CODE_ENUM
|
||||
|| code1 == TYPE_CODE_RANGE)
|
||||
|
@ -868,19 +860,7 @@ value_one (struct type *type)
|
|||
struct type *type1 = check_typedef (type);
|
||||
struct value *val;
|
||||
|
||||
if (TYPE_CODE (type1) == TYPE_CODE_DECFLOAT)
|
||||
{
|
||||
enum bfd_endian byte_order = gdbarch_byte_order (get_type_arch (type));
|
||||
gdb_byte v[16];
|
||||
|
||||
decimal_from_string (v, TYPE_LENGTH (type), byte_order, "1");
|
||||
val = value_from_decfloat (type, v);
|
||||
}
|
||||
else if (TYPE_CODE (type1) == TYPE_CODE_FLT)
|
||||
{
|
||||
val = value_from_double (type, (DOUBLEST) 1);
|
||||
}
|
||||
else if (is_integral_type (type1))
|
||||
if (is_integral_type (type1) || is_floating_type (type1))
|
||||
{
|
||||
val = value_from_longest (type, (LONGEST) 1);
|
||||
}
|
||||
|
|
14
gdb/value.c
14
gdb/value.c
|
@ -2922,10 +2922,8 @@ unpack_long (struct type *type, const gdb_byte *valaddr)
|
|||
return extract_signed_integer (valaddr, len, byte_order);
|
||||
|
||||
case TYPE_CODE_FLT:
|
||||
return (LONGEST) extract_typed_floating (valaddr, type);
|
||||
|
||||
case TYPE_CODE_DECFLOAT:
|
||||
return decimal_to_longest (valaddr, len, byte_order);
|
||||
return target_float_to_longest (valaddr, type);
|
||||
|
||||
case TYPE_CODE_PTR:
|
||||
case TYPE_CODE_REF:
|
||||
|
@ -3539,6 +3537,11 @@ pack_long (gdb_byte *buf, struct type *type, LONGEST num)
|
|||
store_typed_address (buf, type, (CORE_ADDR) num);
|
||||
break;
|
||||
|
||||
case TYPE_CODE_FLT:
|
||||
case TYPE_CODE_DECFLOAT:
|
||||
target_float_from_longest (buf, type, num);
|
||||
break;
|
||||
|
||||
default:
|
||||
error (_("Unexpected type (%d) encountered for integer constant."),
|
||||
TYPE_CODE (type));
|
||||
|
@ -3576,6 +3579,11 @@ pack_unsigned_long (gdb_byte *buf, struct type *type, ULONGEST num)
|
|||
store_typed_address (buf, type, (CORE_ADDR) num);
|
||||
break;
|
||||
|
||||
case TYPE_CODE_FLT:
|
||||
case TYPE_CODE_DECFLOAT:
|
||||
target_float_from_ulongest (buf, type, num);
|
||||
break;
|
||||
|
||||
default:
|
||||
error (_("Unexpected type (%d) encountered "
|
||||
"for unsigned integer constant."),
|
||||
|
|
Loading…
Add table
Reference in a new issue