|  | /* Floating point routines for GDB, the GNU debugger. | 
|  |  | 
|  | Copyright (C) 2017-2020 Free Software Foundation, Inc. | 
|  |  | 
|  | This file is part of GDB. | 
|  |  | 
|  | This program is free software; you can redistribute it and/or modify | 
|  | it under the terms of the GNU General Public License as published by | 
|  | the Free Software Foundation; either version 3 of the License, or | 
|  | (at your option) any later version. | 
|  |  | 
|  | This program is distributed in the hope that it will be useful, | 
|  | but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|  | GNU General Public License for more details. | 
|  |  | 
|  | You should have received a copy of the GNU General Public License | 
|  | along with this program.  If not, see <http://www.gnu.org/licenses/>.  */ | 
|  |  | 
|  | #include "defs.h" | 
|  | #include "gdbtypes.h" | 
|  | #include "floatformat.h" | 
|  | #include "target-float.h" | 
|  | #include "gdbarch.h" | 
|  |  | 
|  | /* Target floating-point operations. | 
|  |  | 
|  | We provide multiple implementations of those operations, which differ | 
|  | by the host-side intermediate format they perform computations in. | 
|  |  | 
|  | 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 | 
|  | values instead of the C99 macros (FP_NAN et cetera).  */ | 
|  | enum float_kind { | 
|  | float_nan, | 
|  | float_infinite, | 
|  | float_zero, | 
|  | float_normal, | 
|  | float_subnormal | 
|  | }; | 
|  |  | 
|  | /* The odds that CHAR_BIT will be anything but 8 are low enough that I'm not | 
|  | going to bother with trying to muck around with whether it is defined in | 
|  | a system header, what we do if not, etc.  */ | 
|  | #define FLOATFORMAT_CHAR_BIT 8 | 
|  |  | 
|  | /* The number of bytes that the largest floating-point type that we | 
|  | can convert to doublest will need.  */ | 
|  | #define FLOATFORMAT_LARGEST_BYTES 16 | 
|  |  | 
|  | /* Return the floatformat's total size in host bytes.  */ | 
|  | static size_t | 
|  | floatformat_totalsize_bytes (const struct floatformat *fmt) | 
|  | { | 
|  | return ((fmt->totalsize + FLOATFORMAT_CHAR_BIT - 1) | 
|  | / FLOATFORMAT_CHAR_BIT); | 
|  | } | 
|  |  | 
|  | /* Return the precision of the floating point format FMT.  */ | 
|  | static int | 
|  | floatformat_precision (const struct floatformat *fmt) | 
|  | { | 
|  | /* Assume the precision of and IBM long double is twice the precision | 
|  | of the underlying double.  This matches what GCC does.  */ | 
|  | if (fmt->split_half) | 
|  | return 2 * floatformat_precision (fmt->split_half); | 
|  |  | 
|  | /* Otherwise, the precision is the size of mantissa in bits, | 
|  | including the implicit bit if present.  */ | 
|  | int prec = fmt->man_len; | 
|  | if (fmt->intbit == floatformat_intbit_no) | 
|  | prec++; | 
|  |  | 
|  | return prec; | 
|  | } | 
|  |  | 
|  | /* Normalize the byte order of FROM into TO.  If no normalization is | 
|  | needed then FMT->byteorder is returned and TO is not changed; | 
|  | otherwise the format of the normalized form in TO is returned.  */ | 
|  | static enum floatformat_byteorders | 
|  | floatformat_normalize_byteorder (const struct floatformat *fmt, | 
|  | const void *from, void *to) | 
|  | { | 
|  | const unsigned char *swapin; | 
|  | unsigned char *swapout; | 
|  | int words; | 
|  |  | 
|  | if (fmt->byteorder == floatformat_little | 
|  | || fmt->byteorder == floatformat_big) | 
|  | return fmt->byteorder; | 
|  |  | 
|  | words = fmt->totalsize / FLOATFORMAT_CHAR_BIT; | 
|  | words >>= 2; | 
|  |  | 
|  | swapout = (unsigned char *)to; | 
|  | swapin = (const unsigned char *)from; | 
|  |  | 
|  | if (fmt->byteorder == floatformat_vax) | 
|  | { | 
|  | while (words-- > 0) | 
|  | { | 
|  | *swapout++ = swapin[1]; | 
|  | *swapout++ = swapin[0]; | 
|  | *swapout++ = swapin[3]; | 
|  | *swapout++ = swapin[2]; | 
|  | swapin += 4; | 
|  | } | 
|  | /* This may look weird, since VAX is little-endian, but it is | 
|  | easier to translate to big-endian than to little-endian.  */ | 
|  | return floatformat_big; | 
|  | } | 
|  | else | 
|  | { | 
|  | gdb_assert (fmt->byteorder == floatformat_littlebyte_bigword); | 
|  |  | 
|  | while (words-- > 0) | 
|  | { | 
|  | *swapout++ = swapin[3]; | 
|  | *swapout++ = swapin[2]; | 
|  | *swapout++ = swapin[1]; | 
|  | *swapout++ = swapin[0]; | 
|  | swapin += 4; | 
|  | } | 
|  | return floatformat_big; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Extract a field which starts at START and is LEN bytes long.  DATA and | 
|  | TOTAL_LEN are the thing we are extracting it from, in byteorder ORDER.  */ | 
|  | static unsigned long | 
|  | get_field (const bfd_byte *data, enum floatformat_byteorders order, | 
|  | unsigned int total_len, unsigned int start, unsigned int len) | 
|  | { | 
|  | unsigned long result; | 
|  | unsigned int cur_byte; | 
|  | int cur_bitshift; | 
|  |  | 
|  | /* Caller must byte-swap words before calling this routine.  */ | 
|  | gdb_assert (order == floatformat_little || order == floatformat_big); | 
|  |  | 
|  | /* Start at the least significant part of the field.  */ | 
|  | if (order == floatformat_little) | 
|  | { | 
|  | /* We start counting from the other end (i.e, from the high bytes | 
|  | rather than the low bytes).  As such, we need to be concerned | 
|  | with what happens if bit 0 doesn't start on a byte boundary. | 
|  | I.e, we need to properly handle the case where total_len is | 
|  | not evenly divisible by 8.  So we compute ``excess'' which | 
|  | represents the number of bits from the end of our starting | 
|  | byte needed to get to bit 0.  */ | 
|  | int excess = FLOATFORMAT_CHAR_BIT - (total_len % FLOATFORMAT_CHAR_BIT); | 
|  |  | 
|  | cur_byte = (total_len / FLOATFORMAT_CHAR_BIT) | 
|  | - ((start + len + excess) / FLOATFORMAT_CHAR_BIT); | 
|  | cur_bitshift = ((start + len + excess) % FLOATFORMAT_CHAR_BIT) | 
|  | - FLOATFORMAT_CHAR_BIT; | 
|  | } | 
|  | else | 
|  | { | 
|  | cur_byte = (start + len) / FLOATFORMAT_CHAR_BIT; | 
|  | cur_bitshift = | 
|  | ((start + len) % FLOATFORMAT_CHAR_BIT) - FLOATFORMAT_CHAR_BIT; | 
|  | } | 
|  | if (cur_bitshift > -FLOATFORMAT_CHAR_BIT) | 
|  | result = *(data + cur_byte) >> (-cur_bitshift); | 
|  | else | 
|  | result = 0; | 
|  | cur_bitshift += FLOATFORMAT_CHAR_BIT; | 
|  | if (order == floatformat_little) | 
|  | ++cur_byte; | 
|  | else | 
|  | --cur_byte; | 
|  |  | 
|  | /* Move towards the most significant part of the field.  */ | 
|  | while (cur_bitshift < len) | 
|  | { | 
|  | result |= (unsigned long)*(data + cur_byte) << cur_bitshift; | 
|  | cur_bitshift += FLOATFORMAT_CHAR_BIT; | 
|  | switch (order) | 
|  | { | 
|  | case floatformat_little: | 
|  | ++cur_byte; | 
|  | break; | 
|  | case floatformat_big: | 
|  | --cur_byte; | 
|  | break; | 
|  | } | 
|  | } | 
|  | if (len < sizeof(result) * FLOATFORMAT_CHAR_BIT) | 
|  | /* Mask out bits which are not part of the field.  */ | 
|  | result &= ((1UL << len) - 1); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | /* Set a field which starts at START and is LEN bytes long.  DATA and | 
|  | TOTAL_LEN are the thing we are extracting it from, in byteorder ORDER.  */ | 
|  | static void | 
|  | put_field (unsigned char *data, enum floatformat_byteorders order, | 
|  | unsigned int total_len, unsigned int start, unsigned int len, | 
|  | unsigned long stuff_to_put) | 
|  | { | 
|  | unsigned int cur_byte; | 
|  | int cur_bitshift; | 
|  |  | 
|  | /* Caller must byte-swap words before calling this routine.  */ | 
|  | gdb_assert (order == floatformat_little || order == floatformat_big); | 
|  |  | 
|  | /* Start at the least significant part of the field.  */ | 
|  | if (order == floatformat_little) | 
|  | { | 
|  | int excess = FLOATFORMAT_CHAR_BIT - (total_len % FLOATFORMAT_CHAR_BIT); | 
|  |  | 
|  | cur_byte = (total_len / FLOATFORMAT_CHAR_BIT) | 
|  | - ((start + len + excess) / FLOATFORMAT_CHAR_BIT); | 
|  | cur_bitshift = ((start + len + excess) % FLOATFORMAT_CHAR_BIT) | 
|  | - FLOATFORMAT_CHAR_BIT; | 
|  | } | 
|  | else | 
|  | { | 
|  | cur_byte = (start + len) / FLOATFORMAT_CHAR_BIT; | 
|  | cur_bitshift = | 
|  | ((start + len) % FLOATFORMAT_CHAR_BIT) - FLOATFORMAT_CHAR_BIT; | 
|  | } | 
|  | if (cur_bitshift > -FLOATFORMAT_CHAR_BIT) | 
|  | { | 
|  | *(data + cur_byte) &= | 
|  | ~(((1 << ((start + len) % FLOATFORMAT_CHAR_BIT)) - 1) | 
|  | << (-cur_bitshift)); | 
|  | *(data + cur_byte) |= | 
|  | (stuff_to_put & ((1 << FLOATFORMAT_CHAR_BIT) - 1)) << (-cur_bitshift); | 
|  | } | 
|  | cur_bitshift += FLOATFORMAT_CHAR_BIT; | 
|  | if (order == floatformat_little) | 
|  | ++cur_byte; | 
|  | else | 
|  | --cur_byte; | 
|  |  | 
|  | /* Move towards the most significant part of the field.  */ | 
|  | while (cur_bitshift < len) | 
|  | { | 
|  | if (len - cur_bitshift < FLOATFORMAT_CHAR_BIT) | 
|  | { | 
|  | /* This is the last byte.  */ | 
|  | *(data + cur_byte) &= | 
|  | ~((1 << (len - cur_bitshift)) - 1); | 
|  | *(data + cur_byte) |= (stuff_to_put >> cur_bitshift); | 
|  | } | 
|  | else | 
|  | *(data + cur_byte) = ((stuff_to_put >> cur_bitshift) | 
|  | & ((1 << FLOATFORMAT_CHAR_BIT) - 1)); | 
|  | cur_bitshift += FLOATFORMAT_CHAR_BIT; | 
|  | if (order == floatformat_little) | 
|  | ++cur_byte; | 
|  | else | 
|  | --cur_byte; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Check if VAL (which is assumed to be a floating point number whose | 
|  | format is described by FMT) is negative.  */ | 
|  | static int | 
|  | floatformat_is_negative (const struct floatformat *fmt, | 
|  | const bfd_byte *uval) | 
|  | { | 
|  | enum floatformat_byteorders order; | 
|  | unsigned char newfrom[FLOATFORMAT_LARGEST_BYTES]; | 
|  |  | 
|  | gdb_assert (fmt != NULL); | 
|  | gdb_assert (fmt->totalsize | 
|  | <= FLOATFORMAT_LARGEST_BYTES * FLOATFORMAT_CHAR_BIT); | 
|  |  | 
|  | /* An IBM long double (a two element array of double) always takes the | 
|  | sign of the first double.  */ | 
|  | if (fmt->split_half) | 
|  | fmt = fmt->split_half; | 
|  |  | 
|  | order = floatformat_normalize_byteorder (fmt, uval, newfrom); | 
|  |  | 
|  | if (order != fmt->byteorder) | 
|  | uval = newfrom; | 
|  |  | 
|  | return get_field (uval, order, fmt->totalsize, fmt->sign_start, 1); | 
|  | } | 
|  |  | 
|  | /* Check if VAL is "not a number" (NaN) for FMT.  */ | 
|  | static enum float_kind | 
|  | floatformat_classify (const struct floatformat *fmt, | 
|  | const bfd_byte *uval) | 
|  | { | 
|  | long exponent; | 
|  | unsigned long mant; | 
|  | unsigned int mant_bits, mant_off; | 
|  | int mant_bits_left; | 
|  | enum floatformat_byteorders order; | 
|  | unsigned char newfrom[FLOATFORMAT_LARGEST_BYTES]; | 
|  | int mant_zero; | 
|  |  | 
|  | gdb_assert (fmt != NULL); | 
|  | gdb_assert (fmt->totalsize | 
|  | <= FLOATFORMAT_LARGEST_BYTES * FLOATFORMAT_CHAR_BIT); | 
|  |  | 
|  | /* An IBM long double (a two element array of double) can be classified | 
|  | by looking at the first double.  inf and nan are specified as | 
|  | ignoring the second double.  zero and subnormal will always have | 
|  | the second double 0.0 if the long double is correctly rounded.  */ | 
|  | if (fmt->split_half) | 
|  | fmt = fmt->split_half; | 
|  |  | 
|  | order = floatformat_normalize_byteorder (fmt, uval, newfrom); | 
|  |  | 
|  | if (order != fmt->byteorder) | 
|  | uval = newfrom; | 
|  |  | 
|  | exponent = get_field (uval, order, fmt->totalsize, fmt->exp_start, | 
|  | fmt->exp_len); | 
|  |  | 
|  | mant_bits_left = fmt->man_len; | 
|  | mant_off = fmt->man_start; | 
|  |  | 
|  | mant_zero = 1; | 
|  | while (mant_bits_left > 0) | 
|  | { | 
|  | mant_bits = std::min (mant_bits_left, 32); | 
|  |  | 
|  | mant = get_field (uval, order, fmt->totalsize, mant_off, mant_bits); | 
|  |  | 
|  | /* If there is an explicit integer bit, mask it off.  */ | 
|  | if (mant_off == fmt->man_start | 
|  | && fmt->intbit == floatformat_intbit_yes) | 
|  | mant &= ~(1 << (mant_bits - 1)); | 
|  |  | 
|  | if (mant) | 
|  | { | 
|  | mant_zero = 0; | 
|  | break; | 
|  | } | 
|  |  | 
|  | mant_off += mant_bits; | 
|  | mant_bits_left -= mant_bits; | 
|  | } | 
|  |  | 
|  | /* If exp_nan is not set, assume that inf, NaN, and subnormals are not | 
|  | supported.  */ | 
|  | if (! fmt->exp_nan) | 
|  | { | 
|  | if (mant_zero) | 
|  | return float_zero; | 
|  | else | 
|  | return float_normal; | 
|  | } | 
|  |  | 
|  | if (exponent == 0) | 
|  | { | 
|  | if (mant_zero) | 
|  | return float_zero; | 
|  | else | 
|  | return float_subnormal; | 
|  | } | 
|  |  | 
|  | if (exponent == fmt->exp_nan) | 
|  | { | 
|  | if (mant_zero) | 
|  | return float_infinite; | 
|  | else | 
|  | return float_nan; | 
|  | } | 
|  |  | 
|  | return float_normal; | 
|  | } | 
|  |  | 
|  | /* Convert the mantissa of VAL (which is assumed to be a floating | 
|  | point number whose format is described by FMT) into a hexadecimal | 
|  | and store it in a static string.  Return a pointer to that string.  */ | 
|  | static const char * | 
|  | floatformat_mantissa (const struct floatformat *fmt, | 
|  | const bfd_byte *val) | 
|  | { | 
|  | unsigned char *uval = (unsigned char *) val; | 
|  | unsigned long mant; | 
|  | unsigned int mant_bits, mant_off; | 
|  | int mant_bits_left; | 
|  | static char res[50]; | 
|  | char buf[9]; | 
|  | int len; | 
|  | enum floatformat_byteorders order; | 
|  | unsigned char newfrom[FLOATFORMAT_LARGEST_BYTES]; | 
|  |  | 
|  | gdb_assert (fmt != NULL); | 
|  | gdb_assert (fmt->totalsize | 
|  | <= FLOATFORMAT_LARGEST_BYTES * FLOATFORMAT_CHAR_BIT); | 
|  |  | 
|  | /* For IBM long double (a two element array of double), return the | 
|  | mantissa of the first double.  The problem with returning the | 
|  | actual mantissa from both doubles is that there can be an | 
|  | arbitrary number of implied 0's or 1's between the mantissas | 
|  | of the first and second double.  In any case, this function | 
|  | is only used for dumping out nans, and a nan is specified to | 
|  | ignore the value in the second double.  */ | 
|  | if (fmt->split_half) | 
|  | fmt = fmt->split_half; | 
|  |  | 
|  | order = floatformat_normalize_byteorder (fmt, uval, newfrom); | 
|  |  | 
|  | if (order != fmt->byteorder) | 
|  | uval = newfrom; | 
|  |  | 
|  | if (! fmt->exp_nan) | 
|  | return 0; | 
|  |  | 
|  | /* Make sure we have enough room to store the mantissa.  */ | 
|  | gdb_assert (sizeof res > ((fmt->man_len + 7) / 8) * 2); | 
|  |  | 
|  | mant_off = fmt->man_start; | 
|  | mant_bits_left = fmt->man_len; | 
|  | mant_bits = (mant_bits_left % 32) > 0 ? mant_bits_left % 32 : 32; | 
|  |  | 
|  | mant = get_field (uval, order, fmt->totalsize, mant_off, mant_bits); | 
|  |  | 
|  | len = xsnprintf (res, sizeof res, "%lx", mant); | 
|  |  | 
|  | mant_off += mant_bits; | 
|  | mant_bits_left -= mant_bits; | 
|  |  | 
|  | while (mant_bits_left > 0) | 
|  | { | 
|  | mant = get_field (uval, order, fmt->totalsize, mant_off, 32); | 
|  |  | 
|  | xsnprintf (buf, sizeof buf, "%08lx", mant); | 
|  | gdb_assert (len + strlen (buf) <= sizeof res); | 
|  | strcat (res, buf); | 
|  |  | 
|  | mant_off += 32; | 
|  | mant_bits_left -= 32; | 
|  | } | 
|  |  | 
|  | return res; | 
|  | } | 
|  |  | 
|  | /* 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 | 
|  | increase precision as necessary.  Otherwise, we call the conversion | 
|  | routine and let it do the dirty work.  Note that even if the target | 
|  | and host floating-point formats match, the length of the types | 
|  | might still be different, so the conversion routines must make sure | 
|  | to not overrun any buffers.  For example, on x86, long double is | 
|  | the 80-bit extended precision type on both 32-bit and 64-bit ABIs, | 
|  | but by default it is stored as 12 bytes on 32-bit, and 16 bytes on | 
|  | 64-bit, for alignment reasons.  See comment in store_typed_floating | 
|  | for a discussion about zeroing out remaining bytes in the target | 
|  | buffer.  */ | 
|  |  | 
|  | static const struct floatformat *host_float_format = GDB_HOST_FLOAT_FORMAT; | 
|  | 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 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); | 
|  |  | 
|  | if (fmt == host_float_format) | 
|  | { | 
|  | float val = 0; | 
|  |  | 
|  | memcpy (&val, from, floatformat_totalsize_bytes (fmt)); | 
|  | *to = val; | 
|  | return; | 
|  | } | 
|  | else if (fmt == host_double_format) | 
|  | { | 
|  | double val = 0; | 
|  |  | 
|  | memcpy (&val, from, floatformat_totalsize_bytes (fmt)); | 
|  | *to = val; | 
|  | return; | 
|  | } | 
|  | else if (fmt == host_long_double_format) | 
|  | { | 
|  | long double val = 0; | 
|  |  | 
|  | memcpy (&val, from, floatformat_totalsize_bytes (fmt)); | 
|  | *to = val; | 
|  | return; | 
|  | } | 
|  |  | 
|  | unsigned char *ufrom = (unsigned char *) from; | 
|  | long exponent; | 
|  | unsigned long mant; | 
|  | unsigned int mant_bits, mant_off; | 
|  | int mant_bits_left; | 
|  | int special_exponent;		/* It's a NaN, denorm or zero.  */ | 
|  | enum floatformat_byteorders order; | 
|  | unsigned char newfrom[FLOATFORMAT_LARGEST_BYTES]; | 
|  | enum float_kind kind; | 
|  |  | 
|  | gdb_assert (fmt->totalsize | 
|  | <= FLOATFORMAT_LARGEST_BYTES * FLOATFORMAT_CHAR_BIT); | 
|  |  | 
|  | /* For non-numbers, reuse libiberty's logic to find the correct | 
|  | format.  We do not lose any precision in this case by passing | 
|  | through a double.  */ | 
|  | kind = floatformat_classify (fmt, (const bfd_byte *) from); | 
|  | if (kind == float_infinite || kind == float_nan) | 
|  | { | 
|  | double dto; | 
|  |  | 
|  | floatformat_to_double	/* ARI: floatformat_to_double */ | 
|  | (fmt->split_half ? fmt->split_half : fmt, from, &dto); | 
|  | *to = (T) dto; | 
|  | return; | 
|  | } | 
|  |  | 
|  | order = floatformat_normalize_byteorder (fmt, ufrom, newfrom); | 
|  |  | 
|  | if (order != fmt->byteorder) | 
|  | ufrom = newfrom; | 
|  |  | 
|  | if (fmt->split_half) | 
|  | { | 
|  | T dtop, dbot; | 
|  |  | 
|  | from_target (fmt->split_half, ufrom, &dtop); | 
|  | /* Preserve the sign of 0, which is the sign of the top | 
|  | half.  */ | 
|  | if (dtop == 0.0) | 
|  | { | 
|  | *to = dtop; | 
|  | return; | 
|  | } | 
|  | from_target (fmt->split_half, | 
|  | ufrom + fmt->totalsize / FLOATFORMAT_CHAR_BIT / 2, &dbot); | 
|  | *to = dtop + dbot; | 
|  | return; | 
|  | } | 
|  |  | 
|  | exponent = get_field (ufrom, order, fmt->totalsize, fmt->exp_start, | 
|  | fmt->exp_len); | 
|  | /* Note that if exponent indicates a NaN, we can't really do anything useful | 
|  | (not knowing if the host has NaN's, or how to build one).  So it will | 
|  | end up as an infinity or something close; that is OK.  */ | 
|  |  | 
|  | mant_bits_left = fmt->man_len; | 
|  | mant_off = fmt->man_start; | 
|  | T dto = 0.0; | 
|  |  | 
|  | special_exponent = exponent == 0 || exponent == fmt->exp_nan; | 
|  |  | 
|  | /* Don't bias NaNs.  Use minimum exponent for denorms.  For | 
|  | simplicity, we don't check for zero as the exponent doesn't matter. | 
|  | Note the cast to int; exp_bias is unsigned, so it's important to | 
|  | make sure the operation is done in signed arithmetic.  */ | 
|  | if (!special_exponent) | 
|  | exponent -= fmt->exp_bias; | 
|  | else if (exponent == 0) | 
|  | exponent = 1 - fmt->exp_bias; | 
|  |  | 
|  | /* Build the result algebraically.  Might go infinite, underflow, etc; | 
|  | who cares.  */ | 
|  |  | 
|  | /* If this format uses a hidden bit, explicitly add it in now.  Otherwise, | 
|  | increment the exponent by one to account for the integer bit.  */ | 
|  |  | 
|  | if (!special_exponent) | 
|  | { | 
|  | if (fmt->intbit == floatformat_intbit_no) | 
|  | dto = ldexp (1.0, exponent); | 
|  | else | 
|  | exponent++; | 
|  | } | 
|  |  | 
|  | while (mant_bits_left > 0) | 
|  | { | 
|  | mant_bits = std::min (mant_bits_left, 32); | 
|  |  | 
|  | mant = get_field (ufrom, order, fmt->totalsize, mant_off, mant_bits); | 
|  |  | 
|  | dto += ldexp ((T) mant, exponent - mant_bits); | 
|  | exponent -= mant_bits; | 
|  | mant_off += mant_bits; | 
|  | mant_bits_left -= mant_bits; | 
|  | } | 
|  |  | 
|  | /* Negate it if negative.  */ | 
|  | if (get_field (ufrom, order, fmt->totalsize, fmt->sign_start, 1)) | 
|  | dto = -dto; | 
|  | *to = dto; | 
|  | } | 
|  |  | 
|  | 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); | 
|  |  | 
|  | if (fmt == host_float_format) | 
|  | { | 
|  | float val = *from; | 
|  |  | 
|  | memcpy (to, &val, floatformat_totalsize_bytes (fmt)); | 
|  | return; | 
|  | } | 
|  | else if (fmt == host_double_format) | 
|  | { | 
|  | double val = *from; | 
|  |  | 
|  | memcpy (to, &val, floatformat_totalsize_bytes (fmt)); | 
|  | return; | 
|  | } | 
|  | else if (fmt == host_long_double_format) | 
|  | { | 
|  | long double val = *from; | 
|  |  | 
|  | memcpy (to, &val, floatformat_totalsize_bytes (fmt)); | 
|  | return; | 
|  | } | 
|  |  | 
|  | T dfrom; | 
|  | int exponent; | 
|  | T mant; | 
|  | unsigned int mant_bits, mant_off; | 
|  | int mant_bits_left; | 
|  | unsigned char *uto = (unsigned char *) to; | 
|  | enum floatformat_byteorders order = fmt->byteorder; | 
|  | unsigned char newto[FLOATFORMAT_LARGEST_BYTES]; | 
|  |  | 
|  | if (order != floatformat_little) | 
|  | order = floatformat_big; | 
|  |  | 
|  | if (order != fmt->byteorder) | 
|  | uto = newto; | 
|  |  | 
|  | memcpy (&dfrom, from, sizeof (dfrom)); | 
|  | memset (uto, 0, floatformat_totalsize_bytes (fmt)); | 
|  |  | 
|  | if (fmt->split_half) | 
|  | { | 
|  | /* Use static volatile to ensure that any excess precision is | 
|  | removed via storing in memory, and so the top half really is | 
|  | the result of converting to double.  */ | 
|  | static volatile double dtop, dbot; | 
|  | T dtopnv, dbotnv; | 
|  |  | 
|  | dtop = (double) dfrom; | 
|  | /* If the rounded top half is Inf, the bottom must be 0 not NaN | 
|  | or Inf.  */ | 
|  | if (dtop + dtop == dtop && dtop != 0.0) | 
|  | dbot = 0.0; | 
|  | else | 
|  | dbot = (double) (dfrom - (T) dtop); | 
|  | dtopnv = dtop; | 
|  | dbotnv = dbot; | 
|  | to_target (fmt->split_half, &dtopnv, uto); | 
|  | to_target (fmt->split_half, &dbotnv, | 
|  | uto + fmt->totalsize / FLOATFORMAT_CHAR_BIT / 2); | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (dfrom == 0) | 
|  | goto finalize_byteorder;	/* Result is zero */ | 
|  | if (dfrom != dfrom)		/* Result is NaN */ | 
|  | { | 
|  | /* From is NaN */ | 
|  | put_field (uto, order, fmt->totalsize, fmt->exp_start, | 
|  | fmt->exp_len, fmt->exp_nan); | 
|  | /* Be sure it's not infinity, but NaN value is irrel.  */ | 
|  | put_field (uto, order, fmt->totalsize, fmt->man_start, | 
|  | fmt->man_len, 1); | 
|  | goto finalize_byteorder; | 
|  | } | 
|  |  | 
|  | /* If negative, set the sign bit.  */ | 
|  | if (dfrom < 0) | 
|  | { | 
|  | put_field (uto, order, fmt->totalsize, fmt->sign_start, 1, 1); | 
|  | dfrom = -dfrom; | 
|  | } | 
|  |  | 
|  | if (dfrom + dfrom == dfrom && dfrom != 0.0)	/* Result is Infinity.  */ | 
|  | { | 
|  | /* Infinity exponent is same as NaN's.  */ | 
|  | put_field (uto, order, fmt->totalsize, fmt->exp_start, | 
|  | fmt->exp_len, fmt->exp_nan); | 
|  | /* Infinity mantissa is all zeroes.  */ | 
|  | put_field (uto, order, fmt->totalsize, fmt->man_start, | 
|  | fmt->man_len, 0); | 
|  | goto finalize_byteorder; | 
|  | } | 
|  |  | 
|  | mant = frexp (dfrom, &exponent); | 
|  |  | 
|  | if (exponent + fmt->exp_bias <= 0) | 
|  | { | 
|  | /* The value is too small to be expressed in the destination | 
|  | type (not enough bits in the exponent.  Treat as 0.  */ | 
|  | put_field (uto, order, fmt->totalsize, fmt->exp_start, | 
|  | fmt->exp_len, 0); | 
|  | put_field (uto, order, fmt->totalsize, fmt->man_start, | 
|  | fmt->man_len, 0); | 
|  | goto finalize_byteorder; | 
|  | } | 
|  |  | 
|  | if (exponent + fmt->exp_bias >= (1 << fmt->exp_len)) | 
|  | { | 
|  | /* The value is too large to fit into the destination. | 
|  | Treat as infinity.  */ | 
|  | put_field (uto, order, fmt->totalsize, fmt->exp_start, | 
|  | fmt->exp_len, fmt->exp_nan); | 
|  | put_field (uto, order, fmt->totalsize, fmt->man_start, | 
|  | fmt->man_len, 0); | 
|  | goto finalize_byteorder; | 
|  | } | 
|  |  | 
|  | put_field (uto, order, fmt->totalsize, fmt->exp_start, fmt->exp_len, | 
|  | exponent + fmt->exp_bias - 1); | 
|  |  | 
|  | mant_bits_left = fmt->man_len; | 
|  | mant_off = fmt->man_start; | 
|  | while (mant_bits_left > 0) | 
|  | { | 
|  | unsigned long mant_long; | 
|  |  | 
|  | mant_bits = mant_bits_left < 32 ? mant_bits_left : 32; | 
|  |  | 
|  | mant *= 4294967296.0; | 
|  | mant_long = ((unsigned long) mant) & 0xffffffffL; | 
|  | mant -= mant_long; | 
|  |  | 
|  | /* If the integer bit is implicit, then we need to discard it. | 
|  | If we are discarding a zero, we should be (but are not) creating | 
|  | a denormalized number which means adjusting the exponent | 
|  | (I think).  */ | 
|  | if (mant_bits_left == fmt->man_len | 
|  | && fmt->intbit == floatformat_intbit_no) | 
|  | { | 
|  | mant_long <<= 1; | 
|  | mant_long &= 0xffffffffL; | 
|  | /* If we are processing the top 32 mantissa bits of a doublest | 
|  | so as to convert to a float value with implied integer bit, | 
|  | we will only be putting 31 of those 32 bits into the | 
|  | final value due to the discarding of the top bit.  In the | 
|  | case of a small float value where the number of mantissa | 
|  | bits is less than 32, discarding the top bit does not alter | 
|  | the number of bits we will be adding to the result.  */ | 
|  | if (mant_bits == 32) | 
|  | mant_bits -= 1; | 
|  | } | 
|  |  | 
|  | if (mant_bits < 32) | 
|  | { | 
|  | /* The bits we want are in the most significant MANT_BITS bits of | 
|  | mant_long.  Move them to the least significant.  */ | 
|  | mant_long >>= 32 - mant_bits; | 
|  | } | 
|  |  | 
|  | put_field (uto, order, fmt->totalsize, | 
|  | mant_off, mant_bits, mant_long); | 
|  | mant_off += mant_bits; | 
|  | mant_bits_left -= mant_bits; | 
|  | } | 
|  |  | 
|  | finalize_byteorder: | 
|  | /* Do we need to byte-swap the words in the result?  */ | 
|  | if (order != fmt->byteorder) | 
|  | floatformat_normalize_byteorder (fmt, newto, to); | 
|  | } | 
|  |  | 
|  | template<typename T> void | 
|  | host_float_ops<T>::to_target (const struct type *type, | 
|  | const T *from, gdb_byte *to) const | 
|  | { | 
|  | /* Ensure possible padding bytes in the target buffer are zeroed out.  */ | 
|  | memset (to, 0, TYPE_LENGTH (type)); | 
|  |  | 
|  | 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.  */ | 
|  | 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); | 
|  |  | 
|  | T host_float; | 
|  | from_target (type, addr, &host_float); | 
|  |  | 
|  | DIAGNOSTIC_PUSH | 
|  | DIAGNOSTIC_IGNORE_FORMAT_NONLITERAL | 
|  | return string_printf (host_format.c_str (), host_float); | 
|  | DIAGNOSTIC_POP | 
|  | } | 
|  |  | 
|  | /* Parse string IN into a target floating-number of type TYPE and | 
|  | store it as byte-stream ADDR.  Return whether parsing succeeded.  */ | 
|  | 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 | 
|  | { | 
|  | T host_float; | 
|  | int n, num; | 
|  |  | 
|  | std::string scan_format = "%"; | 
|  | if (scanf_length_modifier<T>::value) | 
|  | scan_format += scanf_length_modifier<T>::value; | 
|  | scan_format += "g%n"; | 
|  |  | 
|  | DIAGNOSTIC_PUSH | 
|  | DIAGNOSTIC_IGNORE_FORMAT_NONLITERAL | 
|  | num = sscanf (in.c_str (), scan_format.c_str(), &host_float, &n); | 
|  | DIAGNOSTIC_POP | 
|  |  | 
|  | /* The sscanf man page suggests not making any assumptions on the effect | 
|  | of %n on the result, so we don't. | 
|  | That is why we simply test num == 0.  */ | 
|  | if (num == 0) | 
|  | return false; | 
|  |  | 
|  | /* We only accept the whole string.  */ | 
|  | if (in[n]) | 
|  | return false; | 
|  |  | 
|  | to_target (type, &host_float, addr); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | /* Convert the byte-stream ADDR, interpreted as floating-point type TYPE, | 
|  | to an integer value (rounding towards zero).  */ | 
|  | template<typename T> LONGEST | 
|  | host_float_ops<T>::to_longest (const gdb_byte *addr, | 
|  | const struct type *type) const | 
|  | { | 
|  | T host_float; | 
|  | from_target (type, addr, &host_float); | 
|  | T min_possible_range = static_cast<T>(std::numeric_limits<LONGEST>::min()); | 
|  | T max_possible_range = -min_possible_range; | 
|  | /* host_float can be converted to an integer as long as it's in | 
|  | the range [min_possible_range, max_possible_range). If not, it is either | 
|  | too large, or too small, or is NaN; in this case return the maximum or | 
|  | minimum possible value.  */ | 
|  | if (host_float < max_possible_range && host_float >= min_possible_range) | 
|  | return static_cast<LONGEST> (host_float); | 
|  | if (host_float < min_possible_range) | 
|  | return std::numeric_limits<LONGEST>::min(); | 
|  | /* This line will be executed if host_float is NaN.  */ | 
|  | return std::numeric_limits<LONGEST>::max(); | 
|  | } | 
|  |  | 
|  | /* Convert signed integer VAL to a target floating-number of type TYPE | 
|  | and store it as byte-stream ADDR.  */ | 
|  | template<typename T> void | 
|  | host_float_ops<T>::from_longest (gdb_byte *addr, const struct type *type, | 
|  | LONGEST val) const | 
|  | { | 
|  | T host_float = (T) val; | 
|  | to_target (type, &host_float, addr); | 
|  | } | 
|  |  | 
|  | /* Convert unsigned integer VAL to a target floating-number of type TYPE | 
|  | and store it as byte-stream ADDR.  */ | 
|  | template<typename T> void | 
|  | host_float_ops<T>::from_ulongest (gdb_byte *addr, const struct type *type, | 
|  | ULONGEST val) const | 
|  | { | 
|  | T host_float = (T) val; | 
|  | to_target (type, &host_float, addr); | 
|  | } | 
|  |  | 
|  | /* Convert the byte-stream ADDR, interpreted as floating-point type TYPE, | 
|  | to a floating-point value in the host "double" format.  */ | 
|  | template<typename T> double | 
|  | host_float_ops<T>::to_host_double (const gdb_byte *addr, | 
|  | const struct type *type) const | 
|  | { | 
|  | 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 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 | 
|  | { | 
|  | T host_float = (T) val; | 
|  | to_target (type, &host_float, addr); | 
|  | } | 
|  |  | 
|  | /* 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.  */ | 
|  | 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 | 
|  | { | 
|  | 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 | 
|  | 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 | 
|  | { | 
|  | T v1, v2, v = 0; | 
|  |  | 
|  | from_target (type_x, x, &v1); | 
|  | from_target (type_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; | 
|  | } | 
|  |  | 
|  | to_target (type_res, &v, res); | 
|  | } | 
|  |  | 
|  | /* 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.  */ | 
|  | 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 | 
|  | { | 
|  | T v1, v2; | 
|  |  | 
|  | from_target (type_x, x, &v1); | 
|  | from_target (type_y, y, &v2); | 
|  |  | 
|  | if (v1 == v2) | 
|  | return 0; | 
|  | if (v1 < v2) | 
|  | return -1; | 
|  | return 1; | 
|  | } | 
|  |  | 
|  |  | 
|  | /* Implementation of target_float_ops using the MPFR library | 
|  | mpfr_t as intermediate type.  */ | 
|  |  | 
|  | #ifdef HAVE_LIBMPFR | 
|  |  | 
|  | #define MPFR_USE_INTMAX_T | 
|  |  | 
|  | #include <mpfr.h> | 
|  |  | 
|  | class mpfr_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: | 
|  | /* Local wrapper class to handle mpfr_t initalization and cleanup.  */ | 
|  | class gdb_mpfr | 
|  | { | 
|  | public: | 
|  | mpfr_t val; | 
|  |  | 
|  | gdb_mpfr (const struct type *type) | 
|  | { | 
|  | const struct floatformat *fmt = floatformat_from_type (type); | 
|  | mpfr_init2 (val, floatformat_precision (fmt)); | 
|  | } | 
|  |  | 
|  | gdb_mpfr (const gdb_mpfr &source) | 
|  | { | 
|  | mpfr_init2 (val, mpfr_get_prec (source.val)); | 
|  | } | 
|  |  | 
|  | ~gdb_mpfr () | 
|  | { | 
|  | mpfr_clear (val); | 
|  | } | 
|  | }; | 
|  |  | 
|  | void from_target (const struct floatformat *fmt, | 
|  | const gdb_byte *from, gdb_mpfr &to) const; | 
|  | void from_target (const struct type *type, | 
|  | const gdb_byte *from, gdb_mpfr &to) const; | 
|  |  | 
|  | void to_target (const struct type *type, | 
|  | const gdb_mpfr &from, gdb_byte *to) const; | 
|  | void to_target (const struct floatformat *fmt, | 
|  | const gdb_mpfr &from, gdb_byte *to) const; | 
|  | }; | 
|  |  | 
|  |  | 
|  | /* Convert TO/FROM target floating-point format to mpfr_t.  */ | 
|  |  | 
|  | void | 
|  | mpfr_float_ops::from_target (const struct floatformat *fmt, | 
|  | const gdb_byte *orig_from, gdb_mpfr &to) const | 
|  | { | 
|  | const gdb_byte *from = orig_from; | 
|  | mpfr_exp_t exponent; | 
|  | unsigned long mant; | 
|  | unsigned int mant_bits, mant_off; | 
|  | int mant_bits_left; | 
|  | int special_exponent;		/* It's a NaN, denorm or zero.  */ | 
|  | enum floatformat_byteorders order; | 
|  | unsigned char newfrom[FLOATFORMAT_LARGEST_BYTES]; | 
|  | enum float_kind kind; | 
|  |  | 
|  | gdb_assert (fmt->totalsize | 
|  | <= FLOATFORMAT_LARGEST_BYTES * FLOATFORMAT_CHAR_BIT); | 
|  |  | 
|  | /* Handle non-numbers.  */ | 
|  | kind = floatformat_classify (fmt, from); | 
|  | if (kind == float_infinite) | 
|  | { | 
|  | mpfr_set_inf (to.val, floatformat_is_negative (fmt, from) ? -1 : 1); | 
|  | return; | 
|  | } | 
|  | if (kind == float_nan) | 
|  | { | 
|  | mpfr_set_nan (to.val); | 
|  | return; | 
|  | } | 
|  |  | 
|  | order = floatformat_normalize_byteorder (fmt, from, newfrom); | 
|  |  | 
|  | if (order != fmt->byteorder) | 
|  | from = newfrom; | 
|  |  | 
|  | if (fmt->split_half) | 
|  | { | 
|  | gdb_mpfr top (to), bot (to); | 
|  |  | 
|  | from_target (fmt->split_half, from, top); | 
|  | /* Preserve the sign of 0, which is the sign of the top half.  */ | 
|  | if (mpfr_zero_p (top.val)) | 
|  | { | 
|  | mpfr_set (to.val, top.val, MPFR_RNDN); | 
|  | return; | 
|  | } | 
|  | from_target (fmt->split_half, | 
|  | from + fmt->totalsize / FLOATFORMAT_CHAR_BIT / 2, bot); | 
|  | mpfr_add (to.val, top.val, bot.val, MPFR_RNDN); | 
|  | return; | 
|  | } | 
|  |  | 
|  | exponent = get_field (from, order, fmt->totalsize, fmt->exp_start, | 
|  | fmt->exp_len); | 
|  | /* Note that if exponent indicates a NaN, we can't really do anything useful | 
|  | (not knowing if the host has NaN's, or how to build one).  So it will | 
|  | end up as an infinity or something close; that is OK.  */ | 
|  |  | 
|  | mant_bits_left = fmt->man_len; | 
|  | mant_off = fmt->man_start; | 
|  | mpfr_set_zero (to.val, 0); | 
|  |  | 
|  | special_exponent = exponent == 0 || exponent == fmt->exp_nan; | 
|  |  | 
|  | /* Don't bias NaNs.  Use minimum exponent for denorms.  For | 
|  | simplicity, we don't check for zero as the exponent doesn't matter. | 
|  | Note the cast to int; exp_bias is unsigned, so it's important to | 
|  | make sure the operation is done in signed arithmetic.  */ | 
|  | if (!special_exponent) | 
|  | exponent -= fmt->exp_bias; | 
|  | else if (exponent == 0) | 
|  | exponent = 1 - fmt->exp_bias; | 
|  |  | 
|  | /* Build the result algebraically.  Might go infinite, underflow, etc; | 
|  | who cares.  */ | 
|  |  | 
|  | /* If this format uses a hidden bit, explicitly add it in now.  Otherwise, | 
|  | increment the exponent by one to account for the integer bit.  */ | 
|  |  | 
|  | if (!special_exponent) | 
|  | { | 
|  | if (fmt->intbit == floatformat_intbit_no) | 
|  | mpfr_set_ui_2exp (to.val, 1, exponent, MPFR_RNDN); | 
|  | else | 
|  | exponent++; | 
|  | } | 
|  |  | 
|  | gdb_mpfr tmp (to); | 
|  |  | 
|  | while (mant_bits_left > 0) | 
|  | { | 
|  | mant_bits = std::min (mant_bits_left, 32); | 
|  |  | 
|  | mant = get_field (from, order, fmt->totalsize, mant_off, mant_bits); | 
|  |  | 
|  | mpfr_set_ui (tmp.val, mant, MPFR_RNDN); | 
|  | mpfr_mul_2si (tmp.val, tmp.val, exponent - mant_bits, MPFR_RNDN); | 
|  | mpfr_add (to.val, to.val, tmp.val, MPFR_RNDN); | 
|  | exponent -= mant_bits; | 
|  | mant_off += mant_bits; | 
|  | mant_bits_left -= mant_bits; | 
|  | } | 
|  |  | 
|  | /* Negate it if negative.  */ | 
|  | if (get_field (from, order, fmt->totalsize, fmt->sign_start, 1)) | 
|  | mpfr_neg (to.val, to.val, MPFR_RNDN); | 
|  | } | 
|  |  | 
|  | void | 
|  | mpfr_float_ops::from_target (const struct type *type, | 
|  | const gdb_byte *from, gdb_mpfr &to) const | 
|  | { | 
|  | from_target (floatformat_from_type (type), from, to); | 
|  | } | 
|  |  | 
|  | void | 
|  | mpfr_float_ops::to_target (const struct floatformat *fmt, | 
|  | const gdb_mpfr &from, gdb_byte *orig_to) const | 
|  | { | 
|  | unsigned char *to = orig_to; | 
|  | mpfr_exp_t exponent; | 
|  | unsigned int mant_bits, mant_off; | 
|  | int mant_bits_left; | 
|  | enum floatformat_byteorders order = fmt->byteorder; | 
|  | unsigned char newto[FLOATFORMAT_LARGEST_BYTES]; | 
|  |  | 
|  | if (order != floatformat_little) | 
|  | order = floatformat_big; | 
|  |  | 
|  | if (order != fmt->byteorder) | 
|  | to = newto; | 
|  |  | 
|  | memset (to, 0, floatformat_totalsize_bytes (fmt)); | 
|  |  | 
|  | if (fmt->split_half) | 
|  | { | 
|  | gdb_mpfr top (from), bot (from); | 
|  |  | 
|  | mpfr_set (top.val, from.val, MPFR_RNDN); | 
|  | /* If the rounded top half is Inf, the bottom must be 0 not NaN | 
|  | or Inf.  */ | 
|  | if (mpfr_inf_p (top.val)) | 
|  | mpfr_set_zero (bot.val, 0); | 
|  | else | 
|  | mpfr_sub (bot.val, from.val, top.val, MPFR_RNDN); | 
|  |  | 
|  | to_target (fmt->split_half, top, to); | 
|  | to_target (fmt->split_half, bot, | 
|  | to + fmt->totalsize / FLOATFORMAT_CHAR_BIT / 2); | 
|  | return; | 
|  | } | 
|  |  | 
|  | gdb_mpfr tmp (from); | 
|  |  | 
|  | if (mpfr_zero_p (from.val)) | 
|  | goto finalize_byteorder;	/* Result is zero */ | 
|  |  | 
|  | mpfr_set (tmp.val, from.val, MPFR_RNDN); | 
|  |  | 
|  | if (mpfr_nan_p (tmp.val))	/* Result is NaN */ | 
|  | { | 
|  | /* From is NaN */ | 
|  | put_field (to, order, fmt->totalsize, fmt->exp_start, | 
|  | fmt->exp_len, fmt->exp_nan); | 
|  | /* Be sure it's not infinity, but NaN value is irrel.  */ | 
|  | put_field (to, order, fmt->totalsize, fmt->man_start, | 
|  | fmt->man_len, 1); | 
|  | goto finalize_byteorder; | 
|  | } | 
|  |  | 
|  | /* If negative, set the sign bit.  */ | 
|  | if (mpfr_sgn (tmp.val) < 0) | 
|  | { | 
|  | put_field (to, order, fmt->totalsize, fmt->sign_start, 1, 1); | 
|  | mpfr_neg (tmp.val, tmp.val, MPFR_RNDN); | 
|  | } | 
|  |  | 
|  | if (mpfr_inf_p (tmp.val))		/* Result is Infinity.  */ | 
|  | { | 
|  | /* Infinity exponent is same as NaN's.  */ | 
|  | put_field (to, order, fmt->totalsize, fmt->exp_start, | 
|  | fmt->exp_len, fmt->exp_nan); | 
|  | /* Infinity mantissa is all zeroes.  */ | 
|  | put_field (to, order, fmt->totalsize, fmt->man_start, | 
|  | fmt->man_len, 0); | 
|  | goto finalize_byteorder; | 
|  | } | 
|  |  | 
|  | mpfr_frexp (&exponent, tmp.val, tmp.val, MPFR_RNDN); | 
|  |  | 
|  | if (exponent + fmt->exp_bias <= 0) | 
|  | { | 
|  | /* The value is too small to be expressed in the destination | 
|  | type (not enough bits in the exponent.  Treat as 0.  */ | 
|  | put_field (to, order, fmt->totalsize, fmt->exp_start, | 
|  | fmt->exp_len, 0); | 
|  | put_field (to, order, fmt->totalsize, fmt->man_start, | 
|  | fmt->man_len, 0); | 
|  | goto finalize_byteorder; | 
|  | } | 
|  |  | 
|  | if (exponent + fmt->exp_bias >= (1 << fmt->exp_len)) | 
|  | { | 
|  | /* The value is too large to fit into the destination. | 
|  | Treat as infinity.  */ | 
|  | put_field (to, order, fmt->totalsize, fmt->exp_start, | 
|  | fmt->exp_len, fmt->exp_nan); | 
|  | put_field (to, order, fmt->totalsize, fmt->man_start, | 
|  | fmt->man_len, 0); | 
|  | goto finalize_byteorder; | 
|  | } | 
|  |  | 
|  | put_field (to, order, fmt->totalsize, fmt->exp_start, fmt->exp_len, | 
|  | exponent + fmt->exp_bias - 1); | 
|  |  | 
|  | mant_bits_left = fmt->man_len; | 
|  | mant_off = fmt->man_start; | 
|  | while (mant_bits_left > 0) | 
|  | { | 
|  | unsigned long mant_long; | 
|  |  | 
|  | mant_bits = mant_bits_left < 32 ? mant_bits_left : 32; | 
|  |  | 
|  | mpfr_mul_2ui (tmp.val, tmp.val, 32, MPFR_RNDN); | 
|  | mant_long = mpfr_get_ui (tmp.val, MPFR_RNDZ) & 0xffffffffL; | 
|  | mpfr_sub_ui (tmp.val, tmp.val, mant_long, MPFR_RNDZ); | 
|  |  | 
|  | /* If the integer bit is implicit, then we need to discard it. | 
|  | If we are discarding a zero, we should be (but are not) creating | 
|  | a denormalized number which means adjusting the exponent | 
|  | (I think).  */ | 
|  | if (mant_bits_left == fmt->man_len | 
|  | && fmt->intbit == floatformat_intbit_no) | 
|  | { | 
|  | mant_long <<= 1; | 
|  | mant_long &= 0xffffffffL; | 
|  | /* If we are processing the top 32 mantissa bits of a doublest | 
|  | so as to convert to a float value with implied integer bit, | 
|  | we will only be putting 31 of those 32 bits into the | 
|  | final value due to the discarding of the top bit.  In the | 
|  | case of a small float value where the number of mantissa | 
|  | bits is less than 32, discarding the top bit does not alter | 
|  | the number of bits we will be adding to the result.  */ | 
|  | if (mant_bits == 32) | 
|  | mant_bits -= 1; | 
|  | } | 
|  |  | 
|  | if (mant_bits < 32) | 
|  | { | 
|  | /* The bits we want are in the most significant MANT_BITS bits of | 
|  | mant_long.  Move them to the least significant.  */ | 
|  | mant_long >>= 32 - mant_bits; | 
|  | } | 
|  |  | 
|  | put_field (to, order, fmt->totalsize, | 
|  | mant_off, mant_bits, mant_long); | 
|  | mant_off += mant_bits; | 
|  | mant_bits_left -= mant_bits; | 
|  | } | 
|  |  | 
|  | finalize_byteorder: | 
|  | /* Do we need to byte-swap the words in the result?  */ | 
|  | if (order != fmt->byteorder) | 
|  | floatformat_normalize_byteorder (fmt, newto, orig_to); | 
|  | } | 
|  |  | 
|  | void | 
|  | mpfr_float_ops::to_target (const struct type *type, | 
|  | const gdb_mpfr &from, gdb_byte *to) const | 
|  | { | 
|  | /* Ensure possible padding bytes in the target buffer are zeroed out.  */ | 
|  | memset (to, 0, TYPE_LENGTH (type)); | 
|  |  | 
|  | 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.  */ | 
|  | std::string | 
|  | mpfr_float_ops::to_string (const gdb_byte *addr, | 
|  | const struct type *type, | 
|  | const char *format) const | 
|  | { | 
|  | const struct floatformat *fmt = floatformat_from_type (type); | 
|  |  | 
|  | /* 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, addr)) | 
|  | return "<invalid float value>"; | 
|  |  | 
|  | /* 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); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Determine the format string to use on the host side.  */ | 
|  | std::string host_format = floatformat_printf_format (fmt, format, 'R'); | 
|  |  | 
|  | gdb_mpfr tmp (type); | 
|  | from_target (type, addr, tmp); | 
|  |  | 
|  | int size = mpfr_snprintf (NULL, 0, host_format.c_str (), tmp.val); | 
|  | std::string str (size, '\0'); | 
|  | mpfr_sprintf (&str[0], host_format.c_str (), tmp.val); | 
|  |  | 
|  | return str; | 
|  | } | 
|  |  | 
|  | /* Parse string STRING into a target floating-number of type TYPE and | 
|  | store it as byte-stream ADDR.  Return whether parsing succeeded.  */ | 
|  | bool | 
|  | mpfr_float_ops::from_string (gdb_byte *addr, | 
|  | const struct type *type, | 
|  | const std::string &in) const | 
|  | { | 
|  | gdb_mpfr tmp (type); | 
|  |  | 
|  | char *endptr; | 
|  | mpfr_strtofr (tmp.val, in.c_str (), &endptr, 0, MPFR_RNDN); | 
|  |  | 
|  | /* We only accept the whole string.  */ | 
|  | if (*endptr) | 
|  | return false; | 
|  |  | 
|  | to_target (type, tmp, addr); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | /* Convert the byte-stream ADDR, interpreted as floating-point type TYPE, | 
|  | to an integer value (rounding towards zero).  */ | 
|  | LONGEST | 
|  | mpfr_float_ops::to_longest (const gdb_byte *addr, | 
|  | const struct type *type) const | 
|  | { | 
|  | gdb_mpfr tmp (type); | 
|  | from_target (type, addr, tmp); | 
|  | return mpfr_get_sj (tmp.val, MPFR_RNDZ); | 
|  | } | 
|  |  | 
|  | /* Convert signed integer VAL to a target floating-number of type TYPE | 
|  | and store it as byte-stream ADDR.  */ | 
|  | void | 
|  | mpfr_float_ops::from_longest (gdb_byte *addr, | 
|  | const struct type *type, | 
|  | LONGEST val) const | 
|  | { | 
|  | gdb_mpfr tmp (type); | 
|  | mpfr_set_sj (tmp.val, val, MPFR_RNDN); | 
|  | to_target (type, tmp, addr); | 
|  | } | 
|  |  | 
|  | /* Convert unsigned integer VAL to a target floating-number of type TYPE | 
|  | and store it as byte-stream ADDR.  */ | 
|  | void | 
|  | mpfr_float_ops::from_ulongest (gdb_byte *addr, | 
|  | const struct type *type, | 
|  | ULONGEST val) const | 
|  | { | 
|  | gdb_mpfr tmp (type); | 
|  | mpfr_set_uj (tmp.val, val, MPFR_RNDN); | 
|  | to_target (type, tmp, addr); | 
|  | } | 
|  |  | 
|  | /* Convert the byte-stream ADDR, interpreted as floating-point type TYPE, | 
|  | to a floating-point value in the host "double" format.  */ | 
|  | double | 
|  | mpfr_float_ops::to_host_double (const gdb_byte *addr, | 
|  | const struct type *type) const | 
|  | { | 
|  | gdb_mpfr tmp (type); | 
|  | from_target (type, addr, tmp); | 
|  | return mpfr_get_d (tmp.val, MPFR_RNDN); | 
|  | } | 
|  |  | 
|  | /* Convert floating-point value VAL in the host "double" format to a target | 
|  | floating-number of type TYPE and store it as byte-stream ADDR.  */ | 
|  | void | 
|  | mpfr_float_ops::from_host_double (gdb_byte *addr, | 
|  | const struct type *type, | 
|  | double val) const | 
|  | { | 
|  | gdb_mpfr tmp (type); | 
|  | mpfr_set_d (tmp.val, val, MPFR_RNDN); | 
|  | to_target (type, tmp, addr); | 
|  | } | 
|  |  | 
|  | /* 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 | 
|  | mpfr_float_ops::convert (const gdb_byte *from, | 
|  | const struct type *from_type, | 
|  | gdb_byte *to, | 
|  | const struct type *to_type) const | 
|  | { | 
|  | gdb_mpfr from_tmp (from_type), to_tmp (to_type); | 
|  | from_target (from_type, from, from_tmp); | 
|  | mpfr_set (to_tmp.val, from_tmp.val, MPFR_RNDN); | 
|  | to_target (to_type, to_tmp, to); | 
|  | } | 
|  |  | 
|  | /* 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.  */ | 
|  | void | 
|  | mpfr_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 | 
|  | { | 
|  | gdb_mpfr x_tmp (type_x), y_tmp (type_y), tmp (type_res); | 
|  |  | 
|  | from_target (type_x, x, x_tmp); | 
|  | from_target (type_y, y, y_tmp); | 
|  |  | 
|  | switch (op) | 
|  | { | 
|  | case BINOP_ADD: | 
|  | mpfr_add (tmp.val, x_tmp.val, y_tmp.val, MPFR_RNDN); | 
|  | break; | 
|  |  | 
|  | case BINOP_SUB: | 
|  | mpfr_sub (tmp.val, x_tmp.val, y_tmp.val, MPFR_RNDN); | 
|  | break; | 
|  |  | 
|  | case BINOP_MUL: | 
|  | mpfr_mul (tmp.val, x_tmp.val, y_tmp.val, MPFR_RNDN); | 
|  | break; | 
|  |  | 
|  | case BINOP_DIV: | 
|  | mpfr_div (tmp.val, x_tmp.val, y_tmp.val, MPFR_RNDN); | 
|  | break; | 
|  |  | 
|  | case BINOP_EXP: | 
|  | mpfr_pow (tmp.val, x_tmp.val, y_tmp.val, MPFR_RNDN); | 
|  | break; | 
|  |  | 
|  | case BINOP_MIN: | 
|  | mpfr_min (tmp.val, x_tmp.val, y_tmp.val, MPFR_RNDN); | 
|  | break; | 
|  |  | 
|  | case BINOP_MAX: | 
|  | mpfr_max (tmp.val, x_tmp.val, y_tmp.val, MPFR_RNDN); | 
|  | break; | 
|  |  | 
|  | default: | 
|  | error (_("Integer-only operation on floating point number.")); | 
|  | break; | 
|  | } | 
|  |  | 
|  | to_target (type_res, tmp, res); | 
|  | } | 
|  |  | 
|  | /* 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.  */ | 
|  | int | 
|  | mpfr_float_ops::compare (const gdb_byte *x, const struct type *type_x, | 
|  | const gdb_byte *y, const struct type *type_y) const | 
|  | { | 
|  | gdb_mpfr x_tmp (type_x), y_tmp (type_y); | 
|  |  | 
|  | from_target (type_x, x, x_tmp); | 
|  | from_target (type_y, y, y_tmp); | 
|  |  | 
|  | if (mpfr_equal_p (x_tmp.val, y_tmp.val)) | 
|  | return 0; | 
|  | else if (mpfr_less_p (x_tmp.val, y_tmp.val)) | 
|  | return -1; | 
|  | else | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | #endif | 
|  |  | 
|  |  | 
|  | /* Helper routines operating on decimal floating-point data.  */ | 
|  |  | 
|  | /* Decimal floating point is one of the extension to IEEE 754, which is | 
|  | described in http://grouper.ieee.org/groups/754/revision.html and | 
|  | http://www2.hursley.ibm.com/decimal/.  It completes binary floating | 
|  | point by representing floating point more exactly.  */ | 
|  |  | 
|  | /* The order of the following headers is important for making sure | 
|  | decNumber structure is large enough to hold decimal128 digits.  */ | 
|  |  | 
|  | #include "dpd/decimal128.h" | 
|  | #include "dpd/decimal64.h" | 
|  | #include "dpd/decimal32.h" | 
|  |  | 
|  | /* When using decimal128, this is the maximum string length + 1 | 
|  | (value comes from libdecnumber's DECIMAL128_String constant).  */ | 
|  | #define MAX_DECIMAL_STRING  43 | 
|  |  | 
|  | /* In GDB, we are using an array of gdb_byte to represent decimal values. | 
|  | 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, 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 | 
|  | #define OPPOSITE_BYTE_ORDER BFD_ENDIAN_LITTLE | 
|  | #else | 
|  | #define OPPOSITE_BYTE_ORDER BFD_ENDIAN_BIG | 
|  | #endif | 
|  |  | 
|  | if (type_byte_order (type) == OPPOSITE_BYTE_ORDER) | 
|  | for (i = 0; i < len; i++) | 
|  | to[i] = from[len - i - 1]; | 
|  | else | 
|  | for (i = 0; i < len; i++) | 
|  | to[i] = from[i]; | 
|  |  | 
|  | return; | 
|  | } | 
|  |  | 
|  | /* Helper function to get the appropriate libdecnumber context for each size | 
|  | of decimal float.  */ | 
|  | static void | 
|  | set_decnumber_context (decContext *ctx, const struct type *type) | 
|  | { | 
|  | gdb_assert (TYPE_CODE (type) == TYPE_CODE_DECFLOAT); | 
|  |  | 
|  | switch (TYPE_LENGTH (type)) | 
|  | { | 
|  | case 4: | 
|  | decContextDefault (ctx, DEC_INIT_DECIMAL32); | 
|  | break; | 
|  | case 8: | 
|  | decContextDefault (ctx, DEC_INIT_DECIMAL64); | 
|  | break; | 
|  | case 16: | 
|  | decContextDefault (ctx, DEC_INIT_DECIMAL128); | 
|  | break; | 
|  | } | 
|  |  | 
|  | ctx->traps = 0; | 
|  | } | 
|  |  | 
|  | /* Check for errors signaled in the decimal context structure.  */ | 
|  | static void | 
|  | decimal_check_errors (decContext *ctx) | 
|  | { | 
|  | /* An error here could be a division by zero, an overflow, an underflow or | 
|  | an invalid operation (from the DEC_Errors constant in decContext.h). | 
|  | Since GDB doesn't complain about division by zero, overflow or underflow | 
|  | errors for binary floating, we won't complain about them for decimal | 
|  | floating either.  */ | 
|  | if (ctx->status & DEC_IEEE_854_Invalid_operation) | 
|  | { | 
|  | /* Leave only the error bits in the status flags.  */ | 
|  | ctx->status &= DEC_IEEE_854_Invalid_operation; | 
|  | error (_("Cannot perform operation: %s"), | 
|  | decContextStatusToString (ctx)); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Helper function to convert from libdecnumber's appropriate representation | 
|  | for computation to each size of decimal float.  */ | 
|  | static void | 
|  | decimal_from_number (const decNumber *from, | 
|  | gdb_byte *to, const struct type *type) | 
|  | { | 
|  | gdb_byte dec[16]; | 
|  |  | 
|  | decContext set; | 
|  |  | 
|  | set_decnumber_context (&set, type); | 
|  |  | 
|  | switch (TYPE_LENGTH (type)) | 
|  | { | 
|  | case 4: | 
|  | decimal32FromNumber ((decimal32 *) dec, from, &set); | 
|  | break; | 
|  | case 8: | 
|  | decimal64FromNumber ((decimal64 *) dec, from, &set); | 
|  | break; | 
|  | case 16: | 
|  | decimal128FromNumber ((decimal128 *) dec, from, &set); | 
|  | break; | 
|  | default: | 
|  | error (_("Unknown decimal floating point type.")); | 
|  | break; | 
|  | } | 
|  |  | 
|  | 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 *addr, const struct type *type, | 
|  | decNumber *to) | 
|  | { | 
|  | gdb_byte dec[16]; | 
|  | match_endianness (addr, type, dec); | 
|  |  | 
|  | switch (TYPE_LENGTH (type)) | 
|  | { | 
|  | case 4: | 
|  | decimal32ToNumber ((decimal32 *) dec, to); | 
|  | break; | 
|  | case 8: | 
|  | decimal64ToNumber ((decimal64 *) dec, to); | 
|  | break; | 
|  | case 16: | 
|  | decimal128ToNumber ((decimal128 *) dec, to); | 
|  | break; | 
|  | default: | 
|  | error (_("Unknown decimal floating point type.")); | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* 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.  */ | 
|  | 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 (addr, type, dec); | 
|  |  | 
|  | if (format != nullptr) | 
|  | { | 
|  | /* We don't handle format strings (yet).  If the host printf supports | 
|  | decimal floating point types, just use this.  Otherwise, fall back | 
|  | to printing the number while ignoring the format string.  */ | 
|  | #if defined (PRINTF_HAS_DECFLOAT) | 
|  | /* FIXME: This makes unwarranted assumptions about the host ABI!  */ | 
|  | return string_printf (format, dec); | 
|  | #endif | 
|  | } | 
|  |  | 
|  | std::string result; | 
|  | result.resize (MAX_DECIMAL_STRING); | 
|  |  | 
|  | switch (TYPE_LENGTH (type)) | 
|  | { | 
|  | case 4: | 
|  | decimal32ToString ((decimal32 *) dec, &result[0]); | 
|  | break; | 
|  | case 8: | 
|  | decimal64ToString ((decimal64 *) dec, &result[0]); | 
|  | break; | 
|  | case 16: | 
|  | decimal128ToString ((decimal128 *) dec, &result[0]); | 
|  | break; | 
|  | default: | 
|  | error (_("Unknown decimal floating point type.")); | 
|  | break; | 
|  | } | 
|  |  | 
|  | return result; | 
|  | } | 
|  |  | 
|  | /* 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.  */ | 
|  | 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, type); | 
|  |  | 
|  | switch (TYPE_LENGTH (type)) | 
|  | { | 
|  | case 4: | 
|  | decimal32FromString ((decimal32 *) dec, string.c_str (), &set); | 
|  | break; | 
|  | case 8: | 
|  | decimal64FromString ((decimal64 *) dec, string.c_str (), &set); | 
|  | break; | 
|  | case 16: | 
|  | decimal128FromString ((decimal128 *) dec, string.c_str (), &set); | 
|  | break; | 
|  | default: | 
|  | error (_("Unknown decimal floating point type.")); | 
|  | break; | 
|  | } | 
|  |  | 
|  | match_endianness (dec, type, addr); | 
|  |  | 
|  | /* Check for errors in the DFP operation.  */ | 
|  | decimal_check_errors (&set); | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | /* Converts a LONGEST to a decimal float of specified LEN bytes.  */ | 
|  | void | 
|  | decimal_float_ops::from_longest (gdb_byte *addr, const struct type *type, | 
|  | LONGEST from) const | 
|  | { | 
|  | decNumber number; | 
|  |  | 
|  | if ((int32_t) from != from) | 
|  | /* libdecnumber can convert only 32-bit integers.  */ | 
|  | error (_("Conversion of large integer to a " | 
|  | "decimal floating type is not supported.")); | 
|  |  | 
|  | decNumberFromInt32 (&number, (int32_t) from); | 
|  |  | 
|  | decimal_from_number (&number, addr, type); | 
|  | } | 
|  |  | 
|  | /* Converts a ULONGEST to a decimal float of specified LEN bytes.  */ | 
|  | void | 
|  | decimal_float_ops::from_ulongest (gdb_byte *addr, const struct type *type, | 
|  | ULONGEST from) const | 
|  | { | 
|  | decNumber number; | 
|  |  | 
|  | if ((uint32_t) from != from) | 
|  | /* libdecnumber can convert only 32-bit integers.  */ | 
|  | error (_("Conversion of large integer to a " | 
|  | "decimal floating type is not supported.")); | 
|  |  | 
|  | decNumberFromUInt32 (&number, (uint32_t) from); | 
|  |  | 
|  | decimal_from_number (&number, addr, type); | 
|  | } | 
|  |  | 
|  | /* Converts a decimal float of LEN bytes to a LONGEST.  */ | 
|  | 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 = 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.  */ | 
|  | 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, type_x, &number1); | 
|  | decimal_to_number (y, type_y, &number2); | 
|  |  | 
|  | set_decnumber_context (&set, type_res); | 
|  |  | 
|  | switch (op) | 
|  | { | 
|  | case BINOP_ADD: | 
|  | decNumberAdd (&number3, &number1, &number2, &set); | 
|  | break; | 
|  | case BINOP_SUB: | 
|  | decNumberSubtract (&number3, &number1, &number2, &set); | 
|  | break; | 
|  | case BINOP_MUL: | 
|  | decNumberMultiply (&number3, &number1, &number2, &set); | 
|  | break; | 
|  | case BINOP_DIV: | 
|  | decNumberDivide (&number3, &number1, &number2, &set); | 
|  | break; | 
|  | case BINOP_EXP: | 
|  | decNumberPower (&number3, &number1, &number2, &set); | 
|  | break; | 
|  | default: | 
|  | error (_("Operation not valid for decimal floating point number.")); | 
|  | break; | 
|  | } | 
|  |  | 
|  | /* Check for errors in the DFP operation.  */ | 
|  | decimal_check_errors (&set); | 
|  |  | 
|  | 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.  */ | 
|  | 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; | 
|  | const struct type *type_result; | 
|  |  | 
|  | decimal_to_number (x, type_x, &number1); | 
|  | decimal_to_number (y, type_y, &number2); | 
|  |  | 
|  | /* Perform the comparison in the larger of the two sizes.  */ | 
|  | 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); | 
|  |  | 
|  | /* Check for errors in the DFP operation.  */ | 
|  | decimal_check_errors (&set); | 
|  |  | 
|  | if (decNumberIsNaN (&result)) | 
|  | error (_("Comparison with an invalid number (NaN).")); | 
|  | else if (decNumberIsZero (&result)) | 
|  | return 0; | 
|  | else if (decNumberIsNegative (&result)) | 
|  | return -1; | 
|  | else | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | /* Convert a decimal value from a decimal type with LEN_FROM bytes to a | 
|  | decimal type with LEN_TO bytes.  */ | 
|  | void | 
|  | decimal_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, from_type, &number); | 
|  | decimal_from_number (&number, to, to_type); | 
|  | } | 
|  |  | 
|  |  | 
|  | /* 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 | 
|  | 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) | 
|  | && (type_byte_order (type1) | 
|  | == type_byte_order (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 mpfr_t as intermediate format to provide precise target-floating | 
|  | point emulation.  However, if the MPFR library is not available, | 
|  | use the largest host floating-point type as intermediate format.  */ | 
|  | case target_float_ops_kind::binary: | 
|  | { | 
|  | #ifdef HAVE_LIBMPFR | 
|  | static mpfr_float_ops binary_float_ops; | 
|  | #else | 
|  | static host_float_ops<long double> binary_float_ops; | 
|  | #endif | 
|  | 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 | 
|  | target_float_is_valid (const gdb_byte *addr, const struct type *type) | 
|  | { | 
|  | if (TYPE_CODE (type) == TYPE_CODE_FLT) | 
|  | return floatformat_is_valid (floatformat_from_type (type), addr); | 
|  |  | 
|  | if (TYPE_CODE (type) == TYPE_CODE_DECFLOAT) | 
|  | return true; | 
|  |  | 
|  | gdb_assert_not_reached ("unexpected type code"); | 
|  | } | 
|  |  | 
|  | /* Return whether the byte-stream ADDR, interpreted as floating-point | 
|  | type TYPE, is numerically equal to zero (of either sign).  */ | 
|  | bool | 
|  | target_float_is_zero (const gdb_byte *addr, const struct type *type) | 
|  | { | 
|  | if (TYPE_CODE (type) == TYPE_CODE_FLT) | 
|  | return (floatformat_classify (floatformat_from_type (type), addr) | 
|  | == float_zero); | 
|  |  | 
|  | if (TYPE_CODE (type) == TYPE_CODE_DECFLOAT) | 
|  | return decimal_is_zero (addr, type); | 
|  |  | 
|  | gdb_assert_not_reached ("unexpected type code"); | 
|  | } | 
|  |  | 
|  | /* Convert the byte-stream ADDR, interpreted as floating-point type TYPE, | 
|  | to a string, optionally using the print format FORMAT.  */ | 
|  | std::string | 
|  | target_float_to_string (const gdb_byte *addr, const struct type *type, | 
|  | const char *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); | 
|  |  | 
|  | /* Detect invalid representations.  */ | 
|  | if (!floatformat_is_valid (fmt, addr)) | 
|  | return "<invalid float value>"; | 
|  |  | 
|  | /* 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 | 
|  | store it as byte-stream ADDR.  Return whether parsing succeeded.  */ | 
|  | bool | 
|  | target_float_from_string (gdb_byte *addr, const struct type *type, | 
|  | const std::string &string) | 
|  | { | 
|  | 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, | 
|  | to an integer value (rounding towards zero).  */ | 
|  | LONGEST | 
|  | target_float_to_longest (const gdb_byte *addr, const struct type *type) | 
|  | { | 
|  | 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 | 
|  | and store it as byte-stream ADDR.  */ | 
|  | void | 
|  | target_float_from_longest (gdb_byte *addr, const struct type *type, | 
|  | LONGEST val) | 
|  | { | 
|  | 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 | 
|  | and store it as byte-stream ADDR.  */ | 
|  | void | 
|  | target_float_from_ulongest (gdb_byte *addr, const struct type *type, | 
|  | ULONGEST val) | 
|  | { | 
|  | 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, | 
|  | to a floating-point value in the host "double" format.  */ | 
|  | double | 
|  | target_float_to_host_double (const gdb_byte *addr, | 
|  | const struct type *type) | 
|  | { | 
|  | 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 | 
|  | floating-number of type TYPE and store it as byte-stream ADDR.  */ | 
|  | void | 
|  | target_float_from_host_double (gdb_byte *addr, const struct type *type, | 
|  | double val) | 
|  | { | 
|  | 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 | 
|  | 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) | 
|  | { | 
|  | /* We cannot directly convert between binary and decimal floating-point | 
|  | types, so go via an intermediary string.  */ | 
|  | 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; | 
|  | } | 
|  |  | 
|  | /* 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 | 
|  | 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) | 
|  | { | 
|  | gdb_assert (target_float_same_category_p (type_x, type_res)); | 
|  | gdb_assert (target_float_same_category_p (type_y, type_res)); | 
|  |  | 
|  | 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 | 
|  | 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) | 
|  | { | 
|  | gdb_assert (target_float_same_category_p (type_x, type_y)); | 
|  |  | 
|  | const target_float_ops *ops = get_target_float_ops (type_x, type_y); | 
|  | return ops->compare (x, type_x, y, type_y); | 
|  | } | 
|  |  |