| /* Floating point routines for GDB, the GNU debugger. | 
 |  | 
 |    Copyright (C) 2017-2022 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 initialization 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_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_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 type1->code () == type2->code (); | 
 | } | 
 |  | 
 | /* 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 (type1->code ()) | 
 |     { | 
 |       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 ()) | 
 |     { | 
 |       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 ()) | 
 |     { | 
 |       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 perform 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 (type1->code () == type2->code ()); | 
 |  | 
 |   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_CODE_FLT) | 
 |     return floatformat_is_valid (floatformat_from_type (type), addr); | 
 |  | 
 |   if (type->code () == 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_CODE_FLT) | 
 |     return (floatformat_classify (floatformat_from_type (type), addr) | 
 | 	    == float_zero); | 
 |  | 
 |   if (type->code () == 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_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); | 
 | } | 
 |  |