aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/ChangeLog107
-rw-r--r--gdb/target-float.c1052
-rw-r--r--gdb/testsuite/ChangeLog4
-rw-r--r--gdb/testsuite/gdb.arch/vsx-regs.exp12
4 files changed, 747 insertions, 428 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 63ae72e..b330c7b 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,110 @@
+2017-11-22 Ulrich Weigand <uweigand@de.ibm.com>
+
+ * target-float.c: Do not include <math.h>.
+ Include <cmath> and <limits>.
+ (DOUBLEST): Do not define.
+ (class target_float_ops): New type.
+ (class host_float_ops): New templated type.
+ (class decimal_float_ops): New type.
+
+ (floatformat_to_doublest): Rename to ...
+ (host_float_ops<T>::from_target): ... this. Use template type T
+ instead of DOUBLEST. Use C++ math routines. Update recursive calls.
+ (host_float_ops<T>::from_target): New overload using a type argument.
+ (floatformat_from_doublest): Rename to ...
+ (host_float_ops<T>::to_target): ... this. Use template type T
+ instead of DOUBLEST. Use C++ math routines. Update recursive calls.
+ (host_float_ops<T>::to_target): New overload using a type argument.
+ (floatformat_printf_format): New function.
+ (struct printf_length_modifier): New templated type.
+ (floatformat_to_string): Rename to ...
+ (host_float_ops<T>::to_string): ... this. Use type instead of
+ floatformat argument. Use floatformat_printf_format and
+ printf_length_modifier. Remove special handling of invalid numbers,
+ infinities and NaN (moved to target_float_to_string).
+ (struct scanf_length_modifier): New templated type.
+ (floatformat_from_string): Rename to ...
+ (host_float_ops<T>::from_string): ... this. Use type instead of
+ floatformat argument. Use scanf_length_modifier.
+ (floatformat_to_longest): Rename to ...
+ (host_float_ops<T>::to_longest): ... this. Use type instead of
+ floatformat argument. Handle out-of-range values deterministically.
+ (floatformat_from_longest): Rename to ...
+ (host_float_ops<T>::from_longest): ... this. Use type instead of
+ floatformat argument.
+ (floatformat_from_ulongest): Rename to ...
+ (host_float_ops<T>::from_ulongest): ... this. Use type instead of
+ floatformat argument.
+ (floatformat_to_host_double): Rename to ...
+ (host_float_ops<T>::to_host_double): ... this. Use type instead of
+ floatformat argument.
+ (floatformat_from_host_double): Rename to ...
+ (host_float_ops<T>::from_host_double): ... this. Use type instead of
+ floatformat argument.
+ (floatformat_convert): Rename to ...
+ (host_float_ops<T>::convert): ... this. Use type instead of
+ floatformat arguments. Remove handling of no-op conversions.
+ (floatformat_binop): Rename to ...
+ (host_float_ops<T>::binop): ... this. Use type instead of
+ floatformat arguments.
+ (floatformat_compare): Rename to ...
+ (host_float_ops<T>::compare): ... this. Use type instead of
+ floatformat arguments.
+
+ (match_endianness): Use type instead of length/byte_order arguments.
+ (set_decnumber_context): Likewise.
+ (decimal_from_number): Likewise. Update calls.
+ (decimal_to_number): Likewise.
+ (decimal_is_zero): Likewise. Update calls. Move to earlier in file.
+ (decimal_float_ops::to_host_double): New dummy function.
+ (decimal_float_ops::from_host_double): Likewise.
+ (decimal_to_string): Rename to ...
+ (decimal_float_ops::to_string): ... this. Use type instead of
+ length/byte_order arguments. Update calls.
+ (decimal_from_string): Rename to ...
+ (decimal_float_ops::from_string): ... this. Use type instead of
+ length/byte_order arguments. Update calls.
+ (decimal_from_longest): Rename to ...
+ (decimal_float_ops::from_longest): ... this. Use type instead of
+ length/byte_order arguments. Update calls.
+ (decimal_from_ulongest): Rename to ...
+ (decimal_float_ops::from_ulongest): ... this. Use type instead of
+ length/byte_order arguments. Update calls.
+ (decimal_to_longest): Rename to ...
+ (decimal_float_ops::to_longest): ... this. Use type instead of
+ length/byte_order arguments. Update calls.
+ (decimal_binop): Rename to ...
+ (decimal_float_ops::binop): ... this. Use type instead of
+ length/byte_order arguments. Update calls.
+ (decimal_compare): Rename to ...
+ (decimal_float_ops::compare): ... this. Use type instead of
+ length/byte_order arguments. Update calls.
+ (decimal_convert): Rename to ...
+ (decimal_float_ops::convert): ... this. Use type instead of
+ length/byte_order arguments. Update calls.
+
+ (target_float_same_category_p): New function.
+ (target_float_same_format_p): Likewise.
+ (target_float_format_length): Likewise.
+ (enum target_float_ops_kind): New type.
+ (get_target_float_ops_kind): New function.
+ (get_target_float_ops): Three new overloaded functions.
+
+ (target_float_is_zero): Update call.
+ (target_float_to_string): Add special handling of invalid numbers,
+ infinities and NaN (moved from floatformat_to_string). Use
+ target_float_ops callback.
+ (target_float_from_string): Use target_float_ops callback.
+ (target_float_to_longest): Likewise.
+ (target_float_from_longest): Likewise.
+ (target_float_from_ulongest): Likewise.
+ (target_float_to_host_double): Likewise.
+ (target_float_from_host_double): Likewise.
+ (target_float_convert): Add special case for no-op conversions.
+ Use target_float_ops callback.
+ (target_float_binop): Use target_float_ops callback.
+ (target_float_compare): Likewise.
+
2017-11-22 Yao Qi <yao.qi@linaro.org>
* python/py-gdb-readline.c (gdbpy_readline_wrapper): Use strcpy.
diff --git a/gdb/target-float.c b/gdb/target-float.c
index 8bc027e..8f1b9f6 100644
--- a/gdb/target-float.c
+++ b/gdb/target-float.c
@@ -23,21 +23,48 @@
#include "target-float.h"
-/* Helper routines operating on binary floating-point data. */
+/* Target floating-point operations.
-#include <math.h>
+ We provide multiple implementations of those operations, which differ
+ by the host-side intermediate format they perform computations in.
-#if (defined HAVE_LONG_DOUBLE && defined PRINTF_HAS_LONG_DOUBLE \
- && defined SCANF_HAS_LONG_DOUBLE)
-typedef long double DOUBLEST;
-#else
-typedef double DOUBLEST;
-/* If we can't scan or print long double, we don't want to use it
- anywhere. */
-# undef HAVE_LONG_DOUBLE
-# undef PRINTF_HAS_LONG_DOUBLE
-# undef SCANF_HAS_LONG_DOUBLE
-#endif
+ Those multiple implementations all derive from the following abstract
+ base class, which specifies the set of operations to be implemented. */
+
+class target_float_ops
+{
+public:
+ virtual std::string to_string (const gdb_byte *addr, const struct type *type,
+ const char *format) const = 0;
+ virtual bool from_string (gdb_byte *addr, const struct type *type,
+ const std::string &string) const = 0;
+
+ virtual LONGEST to_longest (const gdb_byte *addr,
+ const struct type *type) const = 0;
+ virtual void from_longest (gdb_byte *addr, const struct type *type,
+ LONGEST val) const = 0;
+ virtual void from_ulongest (gdb_byte *addr, const struct type *type,
+ ULONGEST val) const = 0;
+ virtual double to_host_double (const gdb_byte *addr,
+ const struct type *type) const = 0;
+ virtual void from_host_double (gdb_byte *addr, const struct type *type,
+ double val) const = 0;
+ virtual void convert (const gdb_byte *from, const struct type *from_type,
+ gdb_byte *to, const struct type *to_type) const = 0;
+
+ virtual void 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) const = 0;
+ virtual int compare (const gdb_byte *x, const struct type *type_x,
+ const gdb_byte *y, const struct type *type_y) const = 0;
+};
+
+
+/* Helper routines operating on binary floating-point data. */
+
+#include <cmath>
+#include <limits>
/* Different kinds of floatformat numbers recognized by
floatformat_classify. To avoid portability issues, we use local
@@ -447,7 +474,106 @@ floatformat_mantissa (const struct floatformat *fmt,
return res;
}
-/* Convert TO/FROM target to the hosts DOUBLEST floating-point format.
+/* Convert printf format string FORMAT to the otherwise equivalent string
+ which may be used to print a host floating-point number using the length
+ modifier LENGTH (which may be 0 if none is needed). If FORMAT is null,
+ return a format appropriate to print the full precision of a target
+ floating-point number of format FMT. */
+static std::string
+floatformat_printf_format (const struct floatformat *fmt,
+ const char *format, char length)
+{
+ std::string host_format;
+ char conversion;
+
+ if (format == nullptr)
+ {
+ /* If no format was specified, print the number using a format string
+ where the precision is set to the DECIMAL_DIG value for the given
+ floating-point format. This value is computed as
+
+ ceil(1 + p * log10(b)),
+
+ where p is the precision of the floating-point format in bits, and
+ b is the base (which is always 2 for the formats we support). */
+ const double log10_2 = .30102999566398119521;
+ double d_decimal_dig = 1 + floatformat_precision (fmt) * log10_2;
+ int decimal_dig = d_decimal_dig;
+ if (decimal_dig < d_decimal_dig)
+ decimal_dig++;
+
+ host_format = string_printf ("%%.%d", decimal_dig);
+ conversion = 'g';
+ }
+ else
+ {
+ /* Use the specified format, stripping out the conversion character
+ and length modifier, if present. */
+ size_t len = strlen (format);
+ gdb_assert (len > 1);
+ conversion = format[--len];
+ gdb_assert (conversion == 'e' || conversion == 'f' || conversion == 'g'
+ || conversion == 'E' || conversion == 'G');
+ if (format[len - 1] == 'L')
+ len--;
+
+ host_format = std::string (format, len);
+ }
+
+ /* Add the length modifier and conversion character appropriate for
+ handling the appropriate host floating-point type. */
+ if (length)
+ host_format += length;
+ host_format += conversion;
+
+ return host_format;
+}
+
+/* Implementation of target_float_ops using the host floating-point type T
+ as intermediate type. */
+
+template<typename T> class host_float_ops : public target_float_ops
+{
+public:
+ std::string to_string (const gdb_byte *addr, const struct type *type,
+ const char *format) const override;
+ bool from_string (gdb_byte *addr, const struct type *type,
+ const std::string &string) const override;
+
+ LONGEST to_longest (const gdb_byte *addr,
+ const struct type *type) const override;
+ void from_longest (gdb_byte *addr, const struct type *type,
+ LONGEST val) const override;
+ void from_ulongest (gdb_byte *addr, const struct type *type,
+ ULONGEST val) const override;
+ double to_host_double (const gdb_byte *addr,
+ const struct type *type) const override;
+ void from_host_double (gdb_byte *addr, const struct type *type,
+ double val) const override;
+ void convert (const gdb_byte *from, const struct type *from_type,
+ gdb_byte *to, const struct type *to_type) const override;
+
+ void 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) const override;
+ int compare (const gdb_byte *x, const struct type *type_x,
+ const gdb_byte *y, const struct type *type_y) const override;
+
+private:
+ void from_target (const struct floatformat *fmt,
+ const gdb_byte *from, T *to) const;
+ void from_target (const struct type *type,
+ const gdb_byte *from, T *to) const;
+
+ void to_target (const struct type *type,
+ const T *from, gdb_byte *to) const;
+ void to_target (const struct floatformat *fmt,
+ const T *from, gdb_byte *to) const;
+};
+
+
+/* Convert TO/FROM target to the host floating-point format T.
If the host and target formats agree, we just copy the raw data
into the appropriate type of variable and return, letting the host
@@ -467,11 +593,11 @@ static const struct floatformat *host_double_format = GDB_HOST_DOUBLE_FORMAT;
static const struct floatformat *host_long_double_format
= GDB_HOST_LONG_DOUBLE_FORMAT;
-/* Convert from FMT to a DOUBLEST. FROM is the address of the extended float.
- Store the DOUBLEST in *TO. */
-static void
-floatformat_to_doublest (const struct floatformat *fmt,
- const void *from, DOUBLEST *to)
+/* Convert target floating-point value at FROM in format FMT to host
+ floating-point format of type T. */
+template<typename T> void
+host_float_ops<T>::from_target (const struct floatformat *fmt,
+ const gdb_byte *from, T *to) const
{
gdb_assert (fmt != NULL);
@@ -501,7 +627,7 @@ floatformat_to_doublest (const struct floatformat *fmt,
}
unsigned char *ufrom = (unsigned char *) from;
- DOUBLEST dto;
+ T dto;
long exponent;
unsigned long mant;
unsigned int mant_bits, mant_off;
@@ -524,7 +650,7 @@ floatformat_to_doublest (const struct floatformat *fmt,
floatformat_to_double (fmt->split_half ? fmt->split_half : fmt,
from, &dto);
- *to = (DOUBLEST) dto;
+ *to = (T) dto;
return;
}
@@ -535,9 +661,9 @@ floatformat_to_doublest (const struct floatformat *fmt,
if (fmt->split_half)
{
- DOUBLEST dtop, dbot;
+ T dtop, dbot;
- floatformat_to_doublest (fmt->split_half, ufrom, &dtop);
+ from_target (fmt->split_half, ufrom, &dtop);
/* Preserve the sign of 0, which is the sign of the top
half. */
if (dtop == 0.0)
@@ -545,9 +671,8 @@ floatformat_to_doublest (const struct floatformat *fmt,
*to = dtop;
return;
}
- floatformat_to_doublest (fmt->split_half,
- ufrom + fmt->totalsize / FLOATFORMAT_CHAR_BIT / 2,
- &dbot);
+ from_target (fmt->split_half,
+ ufrom + fmt->totalsize / FLOATFORMAT_CHAR_BIT / 2, &dbot);
*to = dtop + dbot;
return;
}
@@ -593,7 +718,7 @@ floatformat_to_doublest (const struct floatformat *fmt,
mant = get_field (ufrom, order, fmt->totalsize, mant_off, mant_bits);
- dto += ldexp ((double) mant, exponent - mant_bits);
+ dto += ldexp ((T) mant, exponent - mant_bits);
exponent -= mant_bits;
mant_off += mant_bits;
mant_bits_left -= mant_bits;
@@ -605,11 +730,18 @@ floatformat_to_doublest (const struct floatformat *fmt,
*to = dto;
}
-/* Convert the DOUBLEST *FROM to an extended float in format FMT and
- store where TO points. */
-static void
-floatformat_from_doublest (const struct floatformat *fmt,
- const DOUBLEST *from, void *to)
+template<typename T> void
+host_float_ops<T>::from_target (const struct type *type,
+ const gdb_byte *from, T *to) const
+{
+ from_target (floatformat_from_type (type), from, to);
+}
+
+/* Convert host floating-point value of type T to target floating-point
+ value in format FMT and store at TO. */
+template<typename T> void
+host_float_ops<T>::to_target (const struct floatformat *fmt,
+ const T *from, gdb_byte *to) const
{
gdb_assert (fmt != NULL);
@@ -635,9 +767,9 @@ floatformat_from_doublest (const struct floatformat *fmt,
return;
}
- DOUBLEST dfrom;
+ T dfrom;
int exponent;
- DOUBLEST mant;
+ T mant;
unsigned int mant_bits, mant_off;
int mant_bits_left;
unsigned char *uto = (unsigned char *) to;
@@ -659,7 +791,7 @@ floatformat_from_doublest (const struct floatformat *fmt,
removed via storing in memory, and so the top half really is
the result of converting to double. */
static volatile double dtop, dbot;
- DOUBLEST dtopnv, dbotnv;
+ T dtopnv, dbotnv;
dtop = (double) dfrom;
/* If the rounded top half is Inf, the bottom must be 0 not NaN
@@ -667,13 +799,12 @@ floatformat_from_doublest (const struct floatformat *fmt,
if (dtop + dtop == dtop && dtop != 0.0)
dbot = 0.0;
else
- dbot = (double) (dfrom - (DOUBLEST) dtop);
+ dbot = (double) (dfrom - (T) dtop);
dtopnv = dtop;
dbotnv = dbot;
- floatformat_from_doublest (fmt->split_half, &dtopnv, uto);
- floatformat_from_doublest (fmt->split_half, &dbotnv,
- (uto
- + fmt->totalsize / FLOATFORMAT_CHAR_BIT / 2));
+ to_target (fmt->split_half, &dtopnv, uto);
+ to_target (fmt->split_half, &dbotnv,
+ uto + fmt->totalsize / FLOATFORMAT_CHAR_BIT / 2);
return;
}
@@ -708,11 +839,7 @@ floatformat_from_doublest (const struct floatformat *fmt,
goto finalize_byteorder;
}
-#ifdef HAVE_LONG_DOUBLE
- mant = frexpl (dfrom, &exponent);
-#else
mant = frexp (dfrom, &exponent);
-#endif
if (exponent + fmt->exp_bias <= 0)
{
@@ -790,99 +917,67 @@ floatformat_from_doublest (const struct floatformat *fmt,
floatformat_normalize_byteorder (fmt, newto, to);
}
-/* Convert the byte-stream ADDR, interpreted as floating-point format FMT,
- to a string, optionally using the print format FORMAT. */
-static std::string
-floatformat_to_string (const struct floatformat *fmt,
- const gdb_byte *in, const char *format)
+template<typename T> void
+host_float_ops<T>::to_target (const struct type *type,
+ const T *from, gdb_byte *to) const
{
- /* Unless we need to adhere to a specific format, provide special
- output for certain cases. */
- if (format == nullptr)
- {
- /* Detect invalid representations. */
- if (!floatformat_is_valid (fmt, in))
- return "<invalid float value>";
+ /* Ensure possible padding bytes in the target buffer are zeroed out. */
+ memset (to, 0, TYPE_LENGTH (type));
- /* Handle NaN and Inf. */
- enum float_kind kind = floatformat_classify (fmt, in);
- if (kind == float_nan)
- {
- const char *sign = floatformat_is_negative (fmt, in)? "-" : "";
- const char *mantissa = floatformat_mantissa (fmt, in);
- return string_printf ("%snan(0x%s)", sign, mantissa);
- }
- else if (kind == float_infinite)
- {
- const char *sign = floatformat_is_negative (fmt, in)? "-" : "";
- return string_printf ("%sinf", sign);
- }
- }
+ to_target (floatformat_from_type (type), from, to);
+}
+/* Convert the byte-stream ADDR, interpreted as floating-point type TYPE,
+ to a string, optionally using the print format FORMAT. */
+template<typename T> struct printf_length_modifier
+{
+ static constexpr char value = 0;
+};
+template<> struct printf_length_modifier<long double>
+{
+ static constexpr char value = 'L';
+};
+template<typename T> std::string
+host_float_ops<T>::to_string (const gdb_byte *addr, const struct type *type,
+ const char *format) const
+{
/* Determine the format string to use on the host side. */
- std::string host_format;
- char conversion;
-
- if (format == nullptr)
- {
- /* If no format was specified, print the number using a format string
- where the precision is set to the DECIMAL_DIG value for the given
- floating-point format. This value is computed as
+ constexpr char length = printf_length_modifier<T>::value;
+ const struct floatformat *fmt = floatformat_from_type (type);
+ std::string host_format = floatformat_printf_format (fmt, format, length);
- ceil(1 + p * log10(b)),
-
- where p is the precision of the floating-point format in bits, and
- b is the base (which is always 2 for the formats we support). */
- const double log10_2 = .30102999566398119521;
- double d_decimal_dig = 1 + floatformat_precision (fmt) * log10_2;
- int decimal_dig = d_decimal_dig;
- if (decimal_dig < d_decimal_dig)
- decimal_dig++;
-
- host_format = string_printf ("%%.%d", decimal_dig);
- conversion = 'g';
- }
- else
- {
- /* Use the specified format, stripping out the conversion character
- and length modifier, if present. */
- size_t len = strlen (format);
- gdb_assert (len > 1);
- conversion = format[--len];
- gdb_assert (conversion == 'e' || conversion == 'f' || conversion == 'g'
- || conversion == 'E' || conversion == 'G');
- if (format[len - 1] == 'L')
- len--;
-
- host_format = std::string (format, len);
- }
-
- /* Add the length modifier and conversion character appropriate for
- handling the host DOUBLEST type. */
-#ifdef HAVE_LONG_DOUBLE
- host_format += 'L';
-#endif
- host_format += conversion;
-
- DOUBLEST doub;
- floatformat_to_doublest (fmt, in, &doub);
- return string_printf (host_format.c_str (), doub);
+ T host_float;
+ from_target (type, addr, &host_float);
+ return string_printf (host_format.c_str (), host_float);
}
-/* Parse string STRING into a target floating-number of format FMT and
+/* Parse string IN into a target floating-number of type TYPE and
store it as byte-stream ADDR. Return whether parsing succeeded. */
-static bool
-floatformat_from_string (const struct floatformat *fmt, gdb_byte *out,
- const std::string &in)
+template<typename T> struct scanf_length_modifier
+{
+ static constexpr char value = 0;
+};
+template<> struct scanf_length_modifier<double>
+{
+ static constexpr char value = 'l';
+};
+template<> struct scanf_length_modifier<long double>
+{
+ static constexpr char value = 'L';
+};
+template<typename T> bool
+host_float_ops<T>::from_string (gdb_byte *addr, const struct type *type,
+ const std::string &in) const
{
- DOUBLEST doub;
+ T host_float;
int n, num;
-#ifdef HAVE_LONG_DOUBLE
- const char *scan_format = "%Lg%n";
-#else
- const char *scan_format = "%lg%n";
-#endif
- num = sscanf (in.c_str (), scan_format, &doub, &n);
+
+ std::string scan_format = "%";
+ if (scanf_length_modifier<T>::value)
+ scan_format += scanf_length_modifier<T>::value;
+ scan_format += "g%n";
+
+ num = sscanf (in.c_str (), scan_format.c_str(), &host_float, &n);
/* The sscanf man page suggests not making any assumptions on the effect
of %n on the result, so we don't.
@@ -894,100 +989,96 @@ floatformat_from_string (const struct floatformat *fmt, gdb_byte *out,
if (in[n])
return false;
- floatformat_from_doublest (fmt, &doub, out);
+ to_target (type, &host_float, addr);
return true;
}
-/* Convert the byte-stream ADDR, interpreted as floating-point format FMT,
+/* Convert the byte-stream ADDR, interpreted as floating-point type TYPE,
to an integer value (rounding towards zero). */
-static LONGEST
-floatformat_to_longest (const struct floatformat *fmt, const gdb_byte *addr)
+template<typename T> LONGEST
+host_float_ops<T>::to_longest (const gdb_byte *addr,
+ const struct type *type) const
{
- DOUBLEST d;
- floatformat_to_doublest (fmt, addr, &d);
- return (LONGEST) d;
+ T host_float;
+ from_target (type, addr, &host_float);
+ /* Converting an out-of-range value is undefined behavior in C, but we
+ prefer to return a defined value here. */
+ if (host_float > std::numeric_limits<LONGEST>::max())
+ return std::numeric_limits<LONGEST>::max();
+ if (host_float < std::numeric_limits<LONGEST>::min())
+ return std::numeric_limits<LONGEST>::min();
+ return (LONGEST) host_float;
}
-/* Convert signed integer VAL to a target floating-number of format FMT
+/* Convert signed integer VAL to a target floating-number of type TYPE
and store it as byte-stream ADDR. */
-static void
-floatformat_from_longest (const struct floatformat *fmt, gdb_byte *addr,
- LONGEST val)
+template<typename T> void
+host_float_ops<T>::from_longest (gdb_byte *addr, const struct type *type,
+ LONGEST val) const
{
- DOUBLEST d = (DOUBLEST) val;
- floatformat_from_doublest (fmt, &d, addr);
+ T host_float = (T) val;
+ to_target (type, &host_float, addr);
}
-/* Convert unsigned integer VAL to a target floating-number of format FMT
+/* Convert unsigned integer VAL to a target floating-number of type TYPE
and store it as byte-stream ADDR. */
-static void
-floatformat_from_ulongest (const struct floatformat *fmt, gdb_byte *addr,
- ULONGEST val)
+template<typename T> void
+host_float_ops<T>::from_ulongest (gdb_byte *addr, const struct type *type,
+ ULONGEST val) const
{
- DOUBLEST d = (DOUBLEST) val;
- floatformat_from_doublest (fmt, &d, addr);
+ T host_float = (T) val;
+ to_target (type, &host_float, addr);
}
-/* Convert the byte-stream ADDR, interpreted as floating-point format FMT,
+/* Convert the byte-stream ADDR, interpreted as floating-point type TYPE,
to a floating-point value in the host "double" format. */
-static double
-floatformat_to_host_double (const struct floatformat *fmt,
- const gdb_byte *addr)
+template<typename T> double
+host_float_ops<T>::to_host_double (const gdb_byte *addr,
+ const struct type *type) const
{
- DOUBLEST d;
- floatformat_to_doublest (fmt, addr, &d);
- return (double) d;
+ T host_float;
+ from_target (type, addr, &host_float);
+ return (double) host_float;
}
/* Convert floating-point value VAL in the host "double" format to a target
- floating-number of format FMT and store it as byte-stream ADDR. */
-static void
-floatformat_from_host_double (const struct floatformat *fmt, gdb_byte *addr,
- double val)
+ floating-number of type TYPE and store it as byte-stream ADDR. */
+template<typename T> void
+host_float_ops<T>::from_host_double (gdb_byte *addr, const struct type *type,
+ double val) const
{
- DOUBLEST d = (DOUBLEST) val;
- floatformat_from_doublest (fmt, &d, addr);
+ T host_float = (T) val;
+ to_target (type, &host_float, 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
+/* 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. */
-static void
-floatformat_convert (const gdb_byte *from, const struct floatformat *from_fmt,
- gdb_byte *to, const struct floatformat *to_fmt)
+template<typename T> void
+host_float_ops<T>::convert (const gdb_byte *from,
+ const struct type *from_type,
+ gdb_byte *to,
+ const struct type *to_type) const
{
- 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);
- }
+ T host_float;
+ from_target (from_type, from, &host_float);
+ to_target (to_type, &host_float, to);
}
/* 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)
+ types TYPE_X and TYPE_Y, respectively. Convert the result to format
+ TYPE_RES and store it into the byte-stream RES. */
+template<typename T> void
+host_float_ops<T>::binop (enum exp_opcode op,
+ 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) const
{
- DOUBLEST v1, v2, v = 0;
+ T v1, v2, v = 0;
- floatformat_to_doublest (fmt_x, x, &v1);
- floatformat_to_doublest (fmt_y, y, &v2);
+ from_target (type_x, x, &v1);
+ from_target (type_y, y, &v2);
switch (op)
{
@@ -1028,20 +1119,20 @@ floatformat_binop (enum exp_opcode op,
break;
}
- floatformat_from_doublest (fmt_result, &v, result);
+ to_target (type_res, &v, res);
}
/* 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
+ 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. */
-static int
-floatformat_compare (const struct floatformat *fmt_x, const gdb_byte *x,
- const struct floatformat *fmt_y, const gdb_byte *y)
+template<typename T> int
+host_float_ops<T>::compare (const gdb_byte *x, const struct type *type_x,
+ const gdb_byte *y, const struct type *type_y) const
{
- DOUBLEST v1, v2;
+ T v1, v2;
- floatformat_to_doublest (fmt_x, x, &v1);
- floatformat_to_doublest (fmt_y, y, &v2);
+ from_target (type_x, x, &v1);
+ from_target (type_y, y, &v2);
if (v1 == v2)
return 0;
@@ -1073,9 +1164,11 @@ floatformat_compare (const struct floatformat *fmt_x, const gdb_byte *x,
They are stored in host byte order. This routine does the conversion if
the target byte order is different. */
static void
-match_endianness (const gdb_byte *from, int len, enum bfd_endian byte_order,
- gdb_byte *to)
+match_endianness (const gdb_byte *from, const struct type *type, gdb_byte *to)
{
+ gdb_assert (TYPE_CODE (type) == TYPE_CODE_DECFLOAT);
+
+ int len = TYPE_LENGTH (type);
int i;
#if WORDS_BIGENDIAN
@@ -1084,7 +1177,7 @@ match_endianness (const gdb_byte *from, int len, enum bfd_endian byte_order,
#define OPPOSITE_BYTE_ORDER BFD_ENDIAN_BIG
#endif
- if (byte_order == OPPOSITE_BYTE_ORDER)
+ if (gdbarch_byte_order (get_type_arch (type)) == OPPOSITE_BYTE_ORDER)
for (i = 0; i < len; i++)
to[i] = from[len - i - 1];
else
@@ -1097,9 +1190,11 @@ match_endianness (const gdb_byte *from, int len, enum bfd_endian byte_order,
/* Helper function to get the appropriate libdecnumber context for each size
of decimal float. */
static void
-set_decnumber_context (decContext *ctx, int len)
+set_decnumber_context (decContext *ctx, const struct type *type)
{
- switch (len)
+ gdb_assert (TYPE_CODE (type) == TYPE_CODE_DECFLOAT);
+
+ switch (TYPE_LENGTH (type))
{
case 4:
decContextDefault (ctx, DEC_INIT_DECIMAL32);
@@ -1137,15 +1232,15 @@ decimal_check_errors (decContext *ctx)
for computation to each size of decimal float. */
static void
decimal_from_number (const decNumber *from,
- gdb_byte *to, int len, enum bfd_endian byte_order)
+ gdb_byte *to, const struct type *type)
{
gdb_byte dec[16];
decContext set;
- set_decnumber_context (&set, len);
+ set_decnumber_context (&set, type);
- switch (len)
+ switch (TYPE_LENGTH (type))
{
case 4:
decimal32FromNumber ((decimal32 *) dec, from, &set);
@@ -1161,19 +1256,19 @@ decimal_from_number (const decNumber *from,
break;
}
- match_endianness (dec, len, byte_order, to);
+ match_endianness (dec, type, to);
}
/* 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, enum bfd_endian byte_order,
+decimal_to_number (const gdb_byte *addr, const struct type *type,
decNumber *to)
{
gdb_byte dec[16];
- match_endianness (from, len, byte_order, dec);
+ match_endianness (addr, type, dec);
- switch (len)
+ switch (TYPE_LENGTH (type))
{
case 4:
decimal32ToNumber ((decimal32 *) dec, to);
@@ -1190,16 +1285,70 @@ decimal_to_number (const gdb_byte *from, int len, enum bfd_endian byte_order,
}
}
+/* Returns true if ADDR (which is of type TYPE) is the number zero. */
+static bool
+decimal_is_zero (const gdb_byte *addr, const struct type *type)
+{
+ decNumber number;
+
+ decimal_to_number (addr, type, &number);
+
+ return decNumberIsZero (&number);
+}
+
+
+/* Implementation of target_float_ops using the libdecnumber decNumber type
+ as intermediate format. */
+
+class decimal_float_ops : public target_float_ops
+{
+public:
+ std::string to_string (const gdb_byte *addr, const struct type *type,
+ const char *format) const override;
+ bool from_string (gdb_byte *addr, const struct type *type,
+ const std::string &string) const override;
+
+ LONGEST to_longest (const gdb_byte *addr,
+ const struct type *type) const override;
+ void from_longest (gdb_byte *addr, const struct type *type,
+ LONGEST val) const override;
+ void from_ulongest (gdb_byte *addr, const struct type *type,
+ ULONGEST val) const override;
+ double to_host_double (const gdb_byte *addr,
+ const struct type *type) const override
+ {
+ /* We don't support conversions between target decimal floating-point
+ types and the host double type. */
+ gdb_assert_not_reached ("invalid operation on decimal float");
+ }
+ void from_host_double (gdb_byte *addr, const struct type *type,
+ double val) const override
+ {
+ /* We don't support conversions between target decimal floating-point
+ types and the host double type. */
+ gdb_assert_not_reached ("invalid operation on decimal float");
+ }
+ void convert (const gdb_byte *from, const struct type *from_type,
+ gdb_byte *to, const struct type *to_type) const override;
+
+ void 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) const override;
+ int compare (const gdb_byte *x, const struct type *type_x,
+ const gdb_byte *y, const struct type *type_y) const override;
+};
+
/* 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. */
-static std::string
-decimal_to_string (const gdb_byte *decbytes, int len,
- enum bfd_endian byte_order, const char *format = nullptr)
+std::string
+decimal_float_ops::to_string (const gdb_byte *addr, const struct type *type,
+ const char *format = nullptr) const
{
gdb_byte dec[16];
- match_endianness (decbytes, len, byte_order, dec);
+ match_endianness (addr, type, dec);
if (format != nullptr)
{
@@ -1215,7 +1364,7 @@ decimal_to_string (const gdb_byte *decbytes, int len,
std::string result;
result.resize (MAX_DECIMAL_STRING);
- switch (len)
+ switch (TYPE_LENGTH (type))
{
case 4:
decimal32ToString ((decimal32 *) dec, &result[0]);
@@ -1237,16 +1386,16 @@ decimal_to_string (const gdb_byte *decbytes, int len,
/* Convert the string form of a decimal value to its decimal representation.
LEN is the length of the decimal type, 4 bytes for decimal32, 8 bytes for
decimal64 and 16 bytes for decimal128. */
-static bool
-decimal_from_string (gdb_byte *decbytes, int len, enum bfd_endian byte_order,
- const std::string &string)
+bool
+decimal_float_ops::from_string (gdb_byte *addr, const struct type *type,
+ const std::string &string) const
{
decContext set;
gdb_byte dec[16];
- set_decnumber_context (&set, len);
+ set_decnumber_context (&set, type);
- switch (len)
+ switch (TYPE_LENGTH (type))
{
case 4:
decimal32FromString ((decimal32 *) dec, string.c_str (), &set);
@@ -1262,7 +1411,7 @@ decimal_from_string (gdb_byte *decbytes, int len, enum bfd_endian byte_order,
break;
}
- match_endianness (dec, len, byte_order, decbytes);
+ match_endianness (dec, type, addr);
/* Check for errors in the DFP operation. */
decimal_check_errors (&set);
@@ -1271,9 +1420,9 @@ decimal_from_string (gdb_byte *decbytes, int len, enum bfd_endian byte_order,
}
/* Converts a LONGEST to a decimal float of specified LEN bytes. */
-static void
-decimal_from_longest (LONGEST from,
- gdb_byte *to, int len, enum bfd_endian byte_order)
+void
+decimal_float_ops::from_longest (gdb_byte *addr, const struct type *type,
+ LONGEST from) const
{
decNumber number;
@@ -1284,13 +1433,13 @@ decimal_from_longest (LONGEST from,
decNumberFromInt32 (&number, (int32_t) from);
- decimal_from_number (&number, to, len, byte_order);
+ decimal_from_number (&number, addr, type);
}
/* Converts a ULONGEST to a decimal float of specified LEN bytes. */
-static void
-decimal_from_ulongest (ULONGEST from,
- gdb_byte *to, int len, enum bfd_endian byte_order)
+void
+decimal_float_ops::from_ulongest (gdb_byte *addr, const struct type *type,
+ ULONGEST from) const
{
decNumber number;
@@ -1301,36 +1450,36 @@ decimal_from_ulongest (ULONGEST from,
decNumberFromUInt32 (&number, (uint32_t) from);
- decimal_from_number (&number, to, len, byte_order);
+ decimal_from_number (&number, addr, type);
}
/* Converts a decimal float of LEN bytes to a LONGEST. */
-static LONGEST
-decimal_to_longest (const gdb_byte *from, int len, enum bfd_endian byte_order)
+LONGEST
+decimal_float_ops::to_longest (const gdb_byte *addr,
+ const struct type *type) const
{
/* libdecnumber has a function to convert from decimal to integer, but
it doesn't work when the decimal number has a fractional part. */
- std::string str = decimal_to_string (from, len, byte_order);
+ std::string str = to_string (addr, type);
return strtoll (str.c_str (), NULL, 10);
}
/* Perform operation OP with operands X and Y with sizes LEN_X and LEN_Y
and byte orders BYTE_ORDER_X and BYTE_ORDER_Y, and store value in
RESULT with size LEN_RESULT and byte order BYTE_ORDER_RESULT. */
-static void
-decimal_binop (enum exp_opcode op,
- const gdb_byte *x, int len_x, enum bfd_endian byte_order_x,
- const gdb_byte *y, int len_y, enum bfd_endian byte_order_y,
- gdb_byte *result, int len_result,
- enum bfd_endian byte_order_result)
+void
+decimal_float_ops::binop (enum exp_opcode op,
+ 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) const
{
decContext set;
decNumber number1, number2, number3;
- decimal_to_number (x, len_x, byte_order_x, &number1);
- decimal_to_number (y, len_y, byte_order_y, &number2);
+ decimal_to_number (x, type_x, &number1);
+ decimal_to_number (y, type_y, &number2);
- set_decnumber_context (&set, len_result);
+ set_decnumber_context (&set, type_res);
switch (op)
{
@@ -1357,37 +1506,26 @@ decimal_binop (enum exp_opcode op,
/* Check for errors in the DFP operation. */
decimal_check_errors (&set);
- decimal_from_number (&number3, result, len_result, byte_order_result);
-}
-
-/* Returns true if X (which is LEN bytes wide) is the number zero. */
-static int
-decimal_is_zero (const gdb_byte *x, int len, enum bfd_endian byte_order)
-{
- decNumber number;
-
- decimal_to_number (x, len, byte_order, &number);
-
- return decNumberIsZero (&number);
+ decimal_from_number (&number3, res, type_res);
}
/* 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. */
-static int
-decimal_compare (const gdb_byte *x, int len_x, enum bfd_endian byte_order_x,
- const gdb_byte *y, int len_y, enum bfd_endian byte_order_y)
+int
+decimal_float_ops::compare (const gdb_byte *x, const struct type *type_x,
+ const gdb_byte *y, const struct type *type_y) const
{
decNumber number1, number2, result;
decContext set;
- int len_result;
+ const struct type *type_result;
- decimal_to_number (x, len_x, byte_order_x, &number1);
- decimal_to_number (y, len_y, byte_order_y, &number2);
+ decimal_to_number (x, type_x, &number1);
+ decimal_to_number (y, type_y, &number2);
/* Perform the comparison in the larger of the two sizes. */
- len_result = len_x > len_y ? len_x : len_y;
- set_decnumber_context (&set, len_result);
+ type_result = TYPE_LENGTH (type_x) > TYPE_LENGTH (type_y) ? type_x : type_y;
+ set_decnumber_context (&set, type_result);
decNumberCompare (&result, &number1, &number2, &set);
@@ -1406,15 +1544,14 @@ decimal_compare (const gdb_byte *x, int len_x, enum bfd_endian byte_order_x,
/* Convert a decimal value from a decimal type with LEN_FROM bytes to a
decimal type with LEN_TO bytes. */
-static void
-decimal_convert (const gdb_byte *from, int len_from,
- enum bfd_endian byte_order_from, gdb_byte *to, int len_to,
- enum bfd_endian byte_order_to)
+void
+decimal_float_ops::convert (const gdb_byte *from, const struct type *from_type,
+ gdb_byte *to, const struct type *to_type) const
{
decNumber number;
- decimal_to_number (from, len_from, byte_order_from, &number);
- decimal_from_number (&number, to, len_to, byte_order_to);
+ decimal_to_number (from, from_type, &number);
+ decimal_from_number (&number, to, to_type);
}
@@ -1423,6 +1560,174 @@ decimal_convert (const gdb_byte *from, int len_from,
"struct type", which may be either a binary or decimal floating-point
type (TYPE_CODE_FLT or TYPE_CODE_DECFLOAT). */
+/* Return whether TYPE1 and TYPE2 are of the same category (binary or
+ decimal floating-point). */
+static bool
+target_float_same_category_p (const struct type *type1,
+ const struct type *type2)
+{
+ return TYPE_CODE (type1) == TYPE_CODE (type2);
+}
+
+/* Return whether TYPE1 and TYPE2 use the same floating-point format. */
+static bool
+target_float_same_format_p (const struct type *type1,
+ const struct type *type2)
+{
+ if (!target_float_same_category_p (type1, type2))
+ return false;
+
+ switch (TYPE_CODE (type1))
+ {
+ case TYPE_CODE_FLT:
+ return floatformat_from_type (type1) == floatformat_from_type (type2);
+
+ case TYPE_CODE_DECFLOAT:
+ return (TYPE_LENGTH (type1) == TYPE_LENGTH (type2)
+ && (gdbarch_byte_order (get_type_arch (type1))
+ == gdbarch_byte_order (get_type_arch (type2))));
+
+ default:
+ gdb_assert_not_reached ("unexpected type code");
+ }
+}
+
+/* Return the size (without padding) of the target floating-point
+ format used by TYPE. */
+static int
+target_float_format_length (const struct type *type)
+{
+ switch (TYPE_CODE (type))
+ {
+ case TYPE_CODE_FLT:
+ return floatformat_totalsize_bytes (floatformat_from_type (type));
+
+ case TYPE_CODE_DECFLOAT:
+ return TYPE_LENGTH (type);
+
+ default:
+ gdb_assert_not_reached ("unexpected type code");
+ }
+}
+
+/* Identifiers of available host-side intermediate formats. These must
+ be sorted so the that the more "general" kinds come later. */
+enum target_float_ops_kind
+{
+ /* Target binary floating-point formats that match a host format. */
+ host_float = 0,
+ host_double,
+ host_long_double,
+ /* Any other target binary floating-point format. */
+ binary,
+ /* Any target decimal floating-point format. */
+ decimal
+};
+
+/* Given a target type TYPE, choose the best host-side intermediate format
+ to perform operations on TYPE in. */
+static enum target_float_ops_kind
+get_target_float_ops_kind (const struct type *type)
+{
+ switch (TYPE_CODE (type))
+ {
+ case TYPE_CODE_FLT:
+ {
+ const struct floatformat *fmt = floatformat_from_type (type);
+
+ /* Binary floating-point formats matching a host format. */
+ if (fmt == host_float_format)
+ return target_float_ops_kind::host_float;
+ if (fmt == host_double_format)
+ return target_float_ops_kind::host_double;
+ if (fmt == host_long_double_format)
+ return target_float_ops_kind::host_long_double;
+
+ /* Any other binary floating-point format. */
+ return target_float_ops_kind::binary;
+ }
+
+ case TYPE_CODE_DECFLOAT:
+ {
+ /* Any decimal floating-point format. */
+ return target_float_ops_kind::decimal;
+ }
+
+ default:
+ gdb_assert_not_reached ("unexpected type code");
+ }
+}
+
+/* Return target_float_ops to peform operations for KIND. */
+static const target_float_ops *
+get_target_float_ops (enum target_float_ops_kind kind)
+{
+ switch (kind)
+ {
+ /* If the type format matches one of the host floating-point
+ types, use that type as intermediate format. */
+ case target_float_ops_kind::host_float:
+ {
+ static host_float_ops<float> host_float_ops_float;
+ return &host_float_ops_float;
+ }
+
+ case target_float_ops_kind::host_double:
+ {
+ static host_float_ops<double> host_float_ops_double;
+ return &host_float_ops_double;
+ }
+
+ case target_float_ops_kind::host_long_double:
+ {
+ static host_float_ops<long double> host_float_ops_long_double;
+ return &host_float_ops_long_double;
+ }
+
+ /* For binary floating-point formats that do not match any host format,
+ use the largest host floating-point type as intermediate format. */
+ case target_float_ops_kind::binary:
+ {
+ static host_float_ops<long double> binary_float_ops;
+ return &binary_float_ops;
+ }
+
+ /* For decimal floating-point types, always use the libdecnumber
+ decNumber type as intermediate format. */
+ case target_float_ops_kind::decimal:
+ {
+ static decimal_float_ops decimal_float_ops;
+ return &decimal_float_ops;
+ }
+
+ default:
+ gdb_assert_not_reached ("unexpected target_float_ops_kind");
+ }
+}
+
+/* Given a target type TYPE, determine the best host-side intermediate format
+ to perform operations on TYPE in. */
+static const target_float_ops *
+get_target_float_ops (const struct type *type)
+{
+ enum target_float_ops_kind kind = get_target_float_ops_kind (type);
+ return get_target_float_ops (kind);
+}
+
+/* The same for operations involving two target types TYPE1 and TYPE2. */
+static const target_float_ops *
+get_target_float_ops (const struct type *type1, const struct type *type2)
+{
+ gdb_assert (TYPE_CODE (type1) == TYPE_CODE (type2));
+
+ enum target_float_ops_kind kind1 = get_target_float_ops_kind (type1);
+ enum target_float_ops_kind kind2 = get_target_float_ops_kind (type2);
+
+ /* Given the way the kinds are sorted, we simply choose the larger one;
+ this will be able to hold values of either type. */
+ return get_target_float_ops (std::max (kind1, kind2));
+}
+
/* Return whether the byte-stream ADDR holds a valid value of
floating-point type TYPE. */
bool
@@ -1447,8 +1752,7 @@ target_float_is_zero (const gdb_byte *addr, const struct type *type)
== float_zero);
if (TYPE_CODE (type) == TYPE_CODE_DECFLOAT)
- return decimal_is_zero (addr, TYPE_LENGTH (type),
- gdbarch_byte_order (get_type_arch (type)));
+ return decimal_is_zero (addr, type);
gdb_assert_not_reached ("unexpected type code");
}
@@ -1459,15 +1763,33 @@ std::string
target_float_to_string (const gdb_byte *addr, const struct type *type,
const char *format)
{
- if (TYPE_CODE (type) == TYPE_CODE_FLT)
- return floatformat_to_string (floatformat_from_type (type), addr, format);
+ /* Unless we need to adhere to a specific format, provide special
+ output for special cases of binary floating-point numbers. */
+ if (format == nullptr && TYPE_CODE (type) == TYPE_CODE_FLT)
+ {
+ const struct floatformat *fmt = floatformat_from_type (type);
- if (TYPE_CODE (type) == TYPE_CODE_DECFLOAT)
- return decimal_to_string (addr, TYPE_LENGTH (type),
- gdbarch_byte_order (get_type_arch (type)),
- format);
+ /* Detect invalid representations. */
+ if (!floatformat_is_valid (fmt, addr))
+ return "<invalid float value>";
- gdb_assert_not_reached ("unexpected type code");
+ /* Handle NaN and Inf. */
+ enum float_kind kind = floatformat_classify (fmt, addr);
+ if (kind == float_nan)
+ {
+ const char *sign = floatformat_is_negative (fmt, addr)? "-" : "";
+ const char *mantissa = floatformat_mantissa (fmt, addr);
+ return string_printf ("%snan(0x%s)", sign, mantissa);
+ }
+ else if (kind == float_infinite)
+ {
+ const char *sign = floatformat_is_negative (fmt, addr)? "-" : "";
+ return string_printf ("%sinf", sign);
+ }
+ }
+
+ const target_float_ops *ops = get_target_float_ops (type);
+ return ops->to_string (addr, type, format);
}
/* Parse string STRING into a target floating-number of type TYPE and
@@ -1476,19 +1798,8 @@ bool
target_float_from_string (gdb_byte *addr, const struct type *type,
const std::string &string)
{
- /* Ensure possible padding bytes in the target buffer are zeroed out. */
- memset (addr, 0, TYPE_LENGTH (type));
-
- if (TYPE_CODE (type) == TYPE_CODE_FLT)
- return floatformat_from_string (floatformat_from_type (type), addr,
- string);
-
- if (TYPE_CODE (type) == TYPE_CODE_DECFLOAT)
- return decimal_from_string (addr, TYPE_LENGTH (type),
- gdbarch_byte_order (get_type_arch (type)),
- string);
-
- gdb_assert_not_reached ("unexpected type code");
+ const target_float_ops *ops = get_target_float_ops (type);
+ return ops->from_string (addr, type, string);
}
/* Convert the byte-stream ADDR, interpreted as floating-point type TYPE,
@@ -1496,14 +1807,8 @@ target_float_from_string (gdb_byte *addr, const struct type *type,
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");
+ const target_float_ops *ops = get_target_float_ops (type);
+ return ops->to_longest (addr, type);
}
/* Convert signed integer VAL to a target floating-number of type TYPE
@@ -1512,23 +1817,8 @@ 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");
+ const target_float_ops *ops = get_target_float_ops (type);
+ ops->from_longest (addr, type, val);
}
/* Convert unsigned integer VAL to a target floating-number of type TYPE
@@ -1537,23 +1827,8 @@ 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");
+ const target_float_ops *ops = get_target_float_ops (type);
+ ops->from_ulongest (addr, type, val);
}
/* Convert the byte-stream ADDR, interpreted as floating-point type TYPE,
@@ -1562,13 +1837,8 @@ double
target_float_to_host_double (const gdb_byte *addr,
const struct type *type)
{
- if (TYPE_CODE (type) == TYPE_CODE_FLT)
- return floatformat_to_host_double (floatformat_from_type (type), addr);
-
- /* We don't support conversions between target decimal floating-point
- types and the host double type here. */
-
- gdb_assert_not_reached ("unexpected type code");
+ const target_float_ops *ops = get_target_float_ops (type);
+ return ops->to_host_double (addr, type);
}
/* Convert floating-point value VAL in the host "double" format to a target
@@ -1577,19 +1847,8 @@ void
target_float_from_host_double (gdb_byte *addr, const struct type *type,
double 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_host_double (floatformat_from_type (type), addr, val);
- return;
- }
-
- /* We don't support conversions between target decimal floating-point
- types and the host double type here. */
-
- gdb_assert_not_reached ("unexpected type code");
+ const target_float_ops *ops = get_target_float_ops (type);
+ ops->from_host_double (addr, type, val);
}
/* Convert a floating-point number of type FROM_TYPE from the target
@@ -1599,43 +1858,27 @@ 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))
+ if (!target_float_same_category_p (from_type, to_type))
{
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");
+ /* Convert between two different formats in the same category. */
+ if (!target_float_same_format_p (from_type, to_type))
+ {
+ const target_float_ops *ops = get_target_float_ops (from_type, to_type);
+ ops->convert (from, from_type, to, to_type);
+ return;
+ }
+
+ /* The floating-point formats match, so we simply copy the data, ensuring
+ possible padding bytes in the target buffer are zeroed out. */
+ memset (to, 0, TYPE_LENGTH (to_type));
+ memcpy (to, from, target_float_format_length (to_type));
}
/* Perform the binary operation indicated by OPCODE, using as operands the
@@ -1652,33 +1895,11 @@ target_float_binop (enum exp_opcode opcode,
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 (target_float_same_category_p (type_x, type_res));
+ gdb_assert (target_float_same_category_p (type_y, type_res));
- gdb_assert_not_reached ("unexpected type code");
+ const target_float_ops *ops = get_target_float_ops (type_x, type_y);
+ ops->binop (opcode, x, type_x, y, type_y, res, type_res);
}
/* Compare the two target byte streams X and Y, interpreted as floating-point
@@ -1692,22 +1913,9 @@ 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);
- }
+ gdb_assert (target_float_same_category_p (type_x, type_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");
+ const target_float_ops *ops = get_target_float_ops (type_x, type_y);
+ return ops->compare (x, type_x, y, type_y);
}
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index 7434105..b916e93 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,3 +1,7 @@
+2017-11-22 Ulrich Weigand <uweigand@de.ibm.com>
+
+ * gdb.arch/vsx-regs.exp: Update register content checks.
+
2017-11-21 Ulrich Weigand <uweigand@de.ibm.com>
* gdb.arch/ppc-longdouble.exp: New file.
diff --git a/gdb/testsuite/gdb.arch/vsx-regs.exp b/gdb/testsuite/gdb.arch/vsx-regs.exp
index e6b8d72..e45aae5 100644
--- a/gdb/testsuite/gdb.arch/vsx-regs.exp
+++ b/gdb/testsuite/gdb.arch/vsx-regs.exp
@@ -61,11 +61,11 @@ set endianness [get_endianness]
# Data sets used throughout the test
if {$endianness == "big"} {
- set vector_register1 ".uint128 = 0x3ff4cccccccccccc0000000000000000, v2_double = .0x1, 0x0., v4_float = .0x1, 0xf99999a0, 0x0, 0x0., v4_int32 = .0x3ff4cccc, 0xcccccccc, 0x0, 0x0., v8_int16 = .0x3ff4, 0xcccc, 0xcccc, 0xcccc, 0x0, 0x0, 0x0, 0x0., v16_int8 = .0x3f, 0xf4, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0.."
+ set vector_register1 ".uint128 = 0x3ff4cccccccccccd0000000000000000, v2_double = .0x1, 0x0., v4_float = .0x1, 0xf9999998, 0x0, 0x0., v4_int32 = .0x3ff4cccc, 0xcccccccd, 0x0, 0x0., v8_int16 = .0x3ff4, 0xcccc, 0xcccc, 0xcccd, 0x0, 0x0, 0x0, 0x0., v16_int8 = .0x3f, 0xf4, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0.."
- set vector_register1_vr ".uint128 = 0x3ff4cccccccccccc0000000100000001, v4_float = .0x1, 0xf99999a0, 0x0, 0x0., v4_int32 = .0x3ff4cccc, 0xcccccccc, 0x1, 0x1., v8_int16 = .0x3ff4, 0xcccc, 0xcccc, 0xcccc, 0x0, 0x1, 0x0, 0x1., v16_int8 = .0x3f, 0xf4, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1.."
+ set vector_register1_vr ".uint128 = 0x3ff4cccccccccccd0000000100000001, v4_float = .0x1, 0xf9999998, 0x0, 0x0., v4_int32 = .0x3ff4cccc, 0xcccccccd, 0x1, 0x1., v8_int16 = .0x3ff4, 0xcccc, 0xcccc, 0xcccd, 0x0, 0x1, 0x0, 0x1., v16_int8 = .0x3f, 0xf4, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcd, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1.."
- set vector_register2 "uint128 = 0xdeadbeefdeadbeefdeadbeefdeadbeef, v2_double = .0x1, 0x1., v4_float = .0x0, 0x0, 0x0, 0x0., v4_int32 = .0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef., v8_int16 = .0xdead, 0xbeef, 0xdead, 0xbeef, 0xdead, 0xbeef, 0xdead, 0xbeef., v16_int8 = .0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef.."
+ set vector_register2 "uint128 = 0xdeadbeefdeadbeefdeadbeefdeadbeef, v2_double = .0x8000000000000000, 0x8000000000000000., v4_float = .0x0, 0x0, 0x0, 0x0., v4_int32 = .0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef., v8_int16 = .0xdead, 0xbeef, 0xdead, 0xbeef, 0xdead, 0xbeef, 0xdead, 0xbeef., v16_int8 = .0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef.."
set vector_register2_vr "uint128 = 0xdeadbeefdeadbeefdeadbeefdeadbeef, v4_float = .0x0, 0x0, 0x0, 0x0., v4_int32 = .0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef., v8_int16 = .0xdead, 0xbeef, 0xdead, 0xbeef, 0xdead, 0xbeef, 0xdead, 0xbeef., v16_int8 = .0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef.."
@@ -73,11 +73,11 @@ if {$endianness == "big"} {
set vector_register3_vr ".uint128 = 0x1000000010000000100000001, v4_float = .0x0, 0x0, 0x0, 0x0., v4_int32 = .0x1, 0x1, 0x1, 0x1., v8_int16 = .0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1., v16_int8 = .0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1.."
} else {
- set vector_register1 ".uint128 = 0x3ff4cccccccccccc0000000000000000, v2_double = .0x0, 0x1., v4_float = .0x0, 0x0, 0xf99999a0, 0x1., v4_int32 = .0x0, 0x0, 0xcccccccc, 0x3ff4cccc., v8_int16 = .0x0, 0x0, 0x0, 0x0, 0xcccc, 0xcccc, 0xcccc, 0x3ff4., v16_int8 = .0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xf4, 0x3f.."
+ set vector_register1 ".uint128 = 0x3ff4cccccccccccd0000000000000000, v2_double = .0x0, 0x1., v4_float = .0x0, 0x0, 0xf9999998, 0x1., v4_int32 = .0x0, 0x0, 0xcccccccd, 0x3ff4cccc., v8_int16 = .0x0, 0x0, 0x0, 0x0, 0xcccd, 0xcccc, 0xcccc, 0x3ff4., v16_int8 = .0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xcd, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xf4, 0x3f.."
- set vector_register1_vr ".uint128 = 0x3ff4cccccccccccc0000000100000001, v4_float = .0x0, 0x0, 0xf99999a0, 0x1., v4_int32 = .0x1, 0x1, 0xcccccccc, 0x3ff4cccc., v8_int16 = .0x1, 0x0, 0x1, 0x0, 0xcccc, 0xcccc, 0xcccc, 0x3ff4., v16_int8 = .0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xf4, 0x3f.."
+ set vector_register1_vr ".uint128 = 0x3ff4cccccccccccd0000000100000001, v4_float = .0x0, 0x0, 0xf9999998, 0x1., v4_int32 = .0x1, 0x1, 0xcccccccd, 0x3ff4cccc., v8_int16 = .0x1, 0x0, 0x1, 0x0, 0xcccd, 0xcccc, 0xcccc, 0x3ff4., v16_int8 = .0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0xcd, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xf4, 0x3f.."
- set vector_register2 "uint128 = 0xdeadbeefdeadbeefdeadbeefdeadbeef, v2_double = .0x1, 0x1., v4_float = .0x0, 0x0, 0x0, 0x0., v4_int32 = .0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef., v8_int16 = .0xbeef, 0xdead, 0xbeef, 0xdead, 0xbeef, 0xdead, 0xbeef, 0xdead., v16_int8 = .0xef, 0xbe, 0xad, 0xde, 0xef, 0xbe, 0xad, 0xde, 0xef, 0xbe, 0xad, 0xde, 0xef, 0xbe, 0xad, 0xde.."
+ set vector_register2 "uint128 = 0xdeadbeefdeadbeefdeadbeefdeadbeef, v2_double = .0x8000000000000000, 0x8000000000000000., v4_float = .0x0, 0x0, 0x0, 0x0., v4_int32 = .0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef., v8_int16 = .0xbeef, 0xdead, 0xbeef, 0xdead, 0xbeef, 0xdead, 0xbeef, 0xdead., v16_int8 = .0xef, 0xbe, 0xad, 0xde, 0xef, 0xbe, 0xad, 0xde, 0xef, 0xbe, 0xad, 0xde, 0xef, 0xbe, 0xad, 0xde.."
set vector_register2_vr "uint128 = 0xdeadbeefdeadbeefdeadbeefdeadbeef, v4_float = .0x0, 0x0, 0x0, 0x0., v4_int32 = .0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef., v8_int16 = .0xbeef, 0xdead, 0xbeef, 0xdead, 0xbeef, 0xdead, 0xbeef, 0xdead., v16_int8 = .0xef, 0xbe, 0xad, 0xde, 0xef, 0xbe, 0xad, 0xde, 0xef, 0xbe, 0xad, 0xde, 0xef, 0xbe, 0xad, 0xde.."