198944Sobrien/* Floating point routines for GDB, the GNU debugger.
298944Sobrien
3130803Smarcel   Copyright 1986, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995,
4130803Smarcel   1996, 1997, 1998, 1999, 2000, 2001, 2003 Free Software Foundation,
5130803Smarcel   Inc.
6130803Smarcel
798944Sobrien   This file is part of GDB.
898944Sobrien
998944Sobrien   This program is free software; you can redistribute it and/or modify
1098944Sobrien   it under the terms of the GNU General Public License as published by
1198944Sobrien   the Free Software Foundation; either version 2 of the License, or
1298944Sobrien   (at your option) any later version.
1398944Sobrien
1498944Sobrien   This program is distributed in the hope that it will be useful,
1598944Sobrien   but WITHOUT ANY WARRANTY; without even the implied warranty of
1698944Sobrien   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1798944Sobrien   GNU General Public License for more details.
1898944Sobrien
1998944Sobrien   You should have received a copy of the GNU General Public License
2098944Sobrien   along with this program; if not, write to the Free Software
2198944Sobrien   Foundation, Inc., 59 Temple Place - Suite 330,
2298944Sobrien   Boston, MA 02111-1307, USA.  */
2398944Sobrien
2498944Sobrien/* Support for converting target fp numbers into host DOUBLEST format.  */
2598944Sobrien
2698944Sobrien/* XXX - This code should really be in libiberty/floatformat.c,
2798944Sobrien   however configuration issues with libiberty made this very
2898944Sobrien   difficult to do in the available time.  */
2998944Sobrien
3098944Sobrien#include "defs.h"
3198944Sobrien#include "doublest.h"
3298944Sobrien#include "floatformat.h"
3398944Sobrien#include "gdb_assert.h"
3498944Sobrien#include "gdb_string.h"
3598944Sobrien#include "gdbtypes.h"
3698944Sobrien#include <math.h>		/* ldexp */
3798944Sobrien
3898944Sobrien/* The odds that CHAR_BIT will be anything but 8 are low enough that I'm not
3998944Sobrien   going to bother with trying to muck around with whether it is defined in
4098944Sobrien   a system header, what we do if not, etc.  */
4198944Sobrien#define FLOATFORMAT_CHAR_BIT 8
4298944Sobrien
4398944Sobrienstatic unsigned long get_field (unsigned char *,
4498944Sobrien				enum floatformat_byteorders,
4598944Sobrien				unsigned int, unsigned int, unsigned int);
4698944Sobrien
4798944Sobrien/* Extract a field which starts at START and is LEN bytes long.  DATA and
4898944Sobrien   TOTAL_LEN are the thing we are extracting it from, in byteorder ORDER.  */
4998944Sobrienstatic unsigned long
5098944Sobrienget_field (unsigned char *data, enum floatformat_byteorders order,
5198944Sobrien	   unsigned int total_len, unsigned int start, unsigned int len)
5298944Sobrien{
5398944Sobrien  unsigned long result;
5498944Sobrien  unsigned int cur_byte;
5598944Sobrien  int cur_bitshift;
5698944Sobrien
5798944Sobrien  /* Start at the least significant part of the field.  */
5898944Sobrien  if (order == floatformat_little || order == floatformat_littlebyte_bigword)
5998944Sobrien    {
6098944Sobrien      /* We start counting from the other end (i.e, from the high bytes
6198944Sobrien	 rather than the low bytes).  As such, we need to be concerned
6298944Sobrien	 with what happens if bit 0 doesn't start on a byte boundary.
6398944Sobrien	 I.e, we need to properly handle the case where total_len is
6498944Sobrien	 not evenly divisible by 8.  So we compute ``excess'' which
6598944Sobrien	 represents the number of bits from the end of our starting
6698944Sobrien	 byte needed to get to bit 0. */
6798944Sobrien      int excess = FLOATFORMAT_CHAR_BIT - (total_len % FLOATFORMAT_CHAR_BIT);
6898944Sobrien      cur_byte = (total_len / FLOATFORMAT_CHAR_BIT)
6998944Sobrien                 - ((start + len + excess) / FLOATFORMAT_CHAR_BIT);
7098944Sobrien      cur_bitshift = ((start + len + excess) % FLOATFORMAT_CHAR_BIT)
7198944Sobrien                     - FLOATFORMAT_CHAR_BIT;
7298944Sobrien    }
7398944Sobrien  else
7498944Sobrien    {
7598944Sobrien      cur_byte = (start + len) / FLOATFORMAT_CHAR_BIT;
7698944Sobrien      cur_bitshift =
7798944Sobrien	((start + len) % FLOATFORMAT_CHAR_BIT) - FLOATFORMAT_CHAR_BIT;
7898944Sobrien    }
7998944Sobrien  if (cur_bitshift > -FLOATFORMAT_CHAR_BIT)
8098944Sobrien    result = *(data + cur_byte) >> (-cur_bitshift);
8198944Sobrien  else
8298944Sobrien    result = 0;
8398944Sobrien  cur_bitshift += FLOATFORMAT_CHAR_BIT;
8498944Sobrien  if (order == floatformat_little || order == floatformat_littlebyte_bigword)
8598944Sobrien    ++cur_byte;
8698944Sobrien  else
8798944Sobrien    --cur_byte;
8898944Sobrien
8998944Sobrien  /* Move towards the most significant part of the field.  */
9098944Sobrien  while (cur_bitshift < len)
9198944Sobrien    {
9298944Sobrien      result |= (unsigned long)*(data + cur_byte) << cur_bitshift;
9398944Sobrien      cur_bitshift += FLOATFORMAT_CHAR_BIT;
9498944Sobrien      if (order == floatformat_little || order == floatformat_littlebyte_bigword)
9598944Sobrien	++cur_byte;
9698944Sobrien      else
9798944Sobrien	--cur_byte;
9898944Sobrien    }
9998944Sobrien  if (len < sizeof(result) * FLOATFORMAT_CHAR_BIT)
10098944Sobrien    /* Mask out bits which are not part of the field */
10198944Sobrien    result &= ((1UL << len) - 1);
10298944Sobrien  return result;
10398944Sobrien}
10498944Sobrien
10598944Sobrien/* Convert from FMT to a DOUBLEST.
10698944Sobrien   FROM is the address of the extended float.
10798944Sobrien   Store the DOUBLEST in *TO.  */
10898944Sobrien
10998944Sobrienstatic void
11098944Sobrienconvert_floatformat_to_doublest (const struct floatformat *fmt,
11198944Sobrien				 const void *from,
11298944Sobrien				 DOUBLEST *to)
11398944Sobrien{
11498944Sobrien  unsigned char *ufrom = (unsigned char *) from;
11598944Sobrien  DOUBLEST dto;
11698944Sobrien  long exponent;
11798944Sobrien  unsigned long mant;
11898944Sobrien  unsigned int mant_bits, mant_off;
11998944Sobrien  int mant_bits_left;
12098944Sobrien  int special_exponent;		/* It's a NaN, denorm or zero */
12198944Sobrien
12298944Sobrien  /* If the mantissa bits are not contiguous from one end of the
12398944Sobrien     mantissa to the other, we need to make a private copy of the
12498944Sobrien     source bytes that is in the right order since the unpacking
12598944Sobrien     algorithm assumes that the bits are contiguous.
12698944Sobrien
12798944Sobrien     Swap the bytes individually rather than accessing them through
12898944Sobrien     "long *" since we have no guarantee that they start on a long
12998944Sobrien     alignment, and also sizeof(long) for the host could be different
13098944Sobrien     than sizeof(long) for the target.  FIXME: Assumes sizeof(long)
13198944Sobrien     for the target is 4. */
13298944Sobrien
13398944Sobrien  if (fmt->byteorder == floatformat_littlebyte_bigword)
13498944Sobrien    {
13598944Sobrien      static unsigned char *newfrom;
13698944Sobrien      unsigned char *swapin, *swapout;
13798944Sobrien      int longswaps;
13898944Sobrien
13998944Sobrien      longswaps = fmt->totalsize / FLOATFORMAT_CHAR_BIT;
14098944Sobrien      longswaps >>= 3;
14198944Sobrien
14298944Sobrien      if (newfrom == NULL)
14398944Sobrien	{
14498944Sobrien	  newfrom = (unsigned char *) xmalloc (fmt->totalsize);
14598944Sobrien	}
14698944Sobrien      swapout = newfrom;
14798944Sobrien      swapin = ufrom;
14898944Sobrien      ufrom = newfrom;
14998944Sobrien      while (longswaps-- > 0)
15098944Sobrien	{
15198944Sobrien	  /* This is ugly, but efficient */
15298944Sobrien	  *swapout++ = swapin[4];
15398944Sobrien	  *swapout++ = swapin[5];
15498944Sobrien	  *swapout++ = swapin[6];
15598944Sobrien	  *swapout++ = swapin[7];
15698944Sobrien	  *swapout++ = swapin[0];
15798944Sobrien	  *swapout++ = swapin[1];
15898944Sobrien	  *swapout++ = swapin[2];
15998944Sobrien	  *swapout++ = swapin[3];
16098944Sobrien	  swapin += 8;
16198944Sobrien	}
16298944Sobrien    }
16398944Sobrien
16498944Sobrien  exponent = get_field (ufrom, fmt->byteorder, fmt->totalsize,
16598944Sobrien			fmt->exp_start, fmt->exp_len);
16698944Sobrien  /* Note that if exponent indicates a NaN, we can't really do anything useful
16798944Sobrien     (not knowing if the host has NaN's, or how to build one).  So it will
16898944Sobrien     end up as an infinity or something close; that is OK.  */
16998944Sobrien
17098944Sobrien  mant_bits_left = fmt->man_len;
17198944Sobrien  mant_off = fmt->man_start;
17298944Sobrien  dto = 0.0;
17398944Sobrien
17498944Sobrien  special_exponent = exponent == 0 || exponent == fmt->exp_nan;
17598944Sobrien
176130803Smarcel  /* Don't bias NaNs. Use minimum exponent for denorms. For simplicity,
177130803Smarcel     we don't check for zero as the exponent doesn't matter.  Note the cast
178130803Smarcel     to int; exp_bias is unsigned, so it's important to make sure the
179130803Smarcel     operation is done in signed arithmetic.  */
18098944Sobrien  if (!special_exponent)
18198944Sobrien    exponent -= fmt->exp_bias;
18298944Sobrien  else if (exponent == 0)
18398944Sobrien    exponent = 1 - fmt->exp_bias;
18498944Sobrien
18598944Sobrien  /* Build the result algebraically.  Might go infinite, underflow, etc;
18698944Sobrien     who cares. */
18798944Sobrien
18898944Sobrien/* If this format uses a hidden bit, explicitly add it in now.  Otherwise,
18998944Sobrien   increment the exponent by one to account for the integer bit.  */
19098944Sobrien
19198944Sobrien  if (!special_exponent)
19298944Sobrien    {
19398944Sobrien      if (fmt->intbit == floatformat_intbit_no)
19498944Sobrien	dto = ldexp (1.0, exponent);
19598944Sobrien      else
19698944Sobrien	exponent++;
19798944Sobrien    }
19898944Sobrien
19998944Sobrien  while (mant_bits_left > 0)
20098944Sobrien    {
20198944Sobrien      mant_bits = min (mant_bits_left, 32);
20298944Sobrien
20398944Sobrien      mant = get_field (ufrom, fmt->byteorder, fmt->totalsize,
20498944Sobrien			mant_off, mant_bits);
20598944Sobrien
20698944Sobrien      dto += ldexp ((double) mant, exponent - mant_bits);
20798944Sobrien      exponent -= mant_bits;
20898944Sobrien      mant_off += mant_bits;
20998944Sobrien      mant_bits_left -= mant_bits;
21098944Sobrien    }
21198944Sobrien
21298944Sobrien  /* Negate it if negative.  */
21398944Sobrien  if (get_field (ufrom, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1))
21498944Sobrien    dto = -dto;
21598944Sobrien  *to = dto;
21698944Sobrien}
21798944Sobrien
21898944Sobrienstatic void put_field (unsigned char *, enum floatformat_byteorders,
21998944Sobrien		       unsigned int,
22098944Sobrien		       unsigned int, unsigned int, unsigned long);
22198944Sobrien
22298944Sobrien/* Set a field which starts at START and is LEN bytes long.  DATA and
22398944Sobrien   TOTAL_LEN are the thing we are extracting it from, in byteorder ORDER.  */
22498944Sobrienstatic void
22598944Sobrienput_field (unsigned char *data, enum floatformat_byteorders order,
22698944Sobrien	   unsigned int total_len, unsigned int start, unsigned int len,
22798944Sobrien	   unsigned long stuff_to_put)
22898944Sobrien{
22998944Sobrien  unsigned int cur_byte;
23098944Sobrien  int cur_bitshift;
23198944Sobrien
23298944Sobrien  /* Start at the least significant part of the field.  */
23398944Sobrien  if (order == floatformat_little || order == floatformat_littlebyte_bigword)
23498944Sobrien    {
23598944Sobrien      int excess = FLOATFORMAT_CHAR_BIT - (total_len % FLOATFORMAT_CHAR_BIT);
23698944Sobrien      cur_byte = (total_len / FLOATFORMAT_CHAR_BIT)
23798944Sobrien                 - ((start + len + excess) / FLOATFORMAT_CHAR_BIT);
23898944Sobrien      cur_bitshift = ((start + len + excess) % FLOATFORMAT_CHAR_BIT)
23998944Sobrien                     - FLOATFORMAT_CHAR_BIT;
24098944Sobrien    }
24198944Sobrien  else
24298944Sobrien    {
24398944Sobrien      cur_byte = (start + len) / FLOATFORMAT_CHAR_BIT;
24498944Sobrien      cur_bitshift =
24598944Sobrien	((start + len) % FLOATFORMAT_CHAR_BIT) - FLOATFORMAT_CHAR_BIT;
24698944Sobrien    }
24798944Sobrien  if (cur_bitshift > -FLOATFORMAT_CHAR_BIT)
24898944Sobrien    {
24998944Sobrien      *(data + cur_byte) &=
25098944Sobrien	~(((1 << ((start + len) % FLOATFORMAT_CHAR_BIT)) - 1)
25198944Sobrien	  << (-cur_bitshift));
25298944Sobrien      *(data + cur_byte) |=
25398944Sobrien	(stuff_to_put & ((1 << FLOATFORMAT_CHAR_BIT) - 1)) << (-cur_bitshift);
25498944Sobrien    }
25598944Sobrien  cur_bitshift += FLOATFORMAT_CHAR_BIT;
25698944Sobrien  if (order == floatformat_little || order == floatformat_littlebyte_bigword)
25798944Sobrien    ++cur_byte;
25898944Sobrien  else
25998944Sobrien    --cur_byte;
26098944Sobrien
26198944Sobrien  /* Move towards the most significant part of the field.  */
26298944Sobrien  while (cur_bitshift < len)
26398944Sobrien    {
26498944Sobrien      if (len - cur_bitshift < FLOATFORMAT_CHAR_BIT)
26598944Sobrien	{
26698944Sobrien	  /* This is the last byte.  */
26798944Sobrien	  *(data + cur_byte) &=
26898944Sobrien	    ~((1 << (len - cur_bitshift)) - 1);
26998944Sobrien	  *(data + cur_byte) |= (stuff_to_put >> cur_bitshift);
27098944Sobrien	}
27198944Sobrien      else
27298944Sobrien	*(data + cur_byte) = ((stuff_to_put >> cur_bitshift)
27398944Sobrien			      & ((1 << FLOATFORMAT_CHAR_BIT) - 1));
27498944Sobrien      cur_bitshift += FLOATFORMAT_CHAR_BIT;
27598944Sobrien      if (order == floatformat_little || order == floatformat_littlebyte_bigword)
27698944Sobrien	++cur_byte;
27798944Sobrien      else
27898944Sobrien	--cur_byte;
27998944Sobrien    }
28098944Sobrien}
28198944Sobrien
28298944Sobrien#ifdef HAVE_LONG_DOUBLE
28398944Sobrien/* Return the fractional part of VALUE, and put the exponent of VALUE in *EPTR.
28498944Sobrien   The range of the returned value is >= 0.5 and < 1.0.  This is equivalent to
28598944Sobrien   frexp, but operates on the long double data type.  */
28698944Sobrien
28798944Sobrienstatic long double ldfrexp (long double value, int *eptr);
28898944Sobrien
28998944Sobrienstatic long double
29098944Sobrienldfrexp (long double value, int *eptr)
29198944Sobrien{
29298944Sobrien  long double tmp;
29398944Sobrien  int exp;
29498944Sobrien
29598944Sobrien  /* Unfortunately, there are no portable functions for extracting the exponent
29698944Sobrien     of a long double, so we have to do it iteratively by multiplying or dividing
29798944Sobrien     by two until the fraction is between 0.5 and 1.0.  */
29898944Sobrien
29998944Sobrien  if (value < 0.0l)
30098944Sobrien    value = -value;
30198944Sobrien
30298944Sobrien  tmp = 1.0l;
30398944Sobrien  exp = 0;
30498944Sobrien
30598944Sobrien  if (value >= tmp)		/* Value >= 1.0 */
30698944Sobrien    while (value >= tmp)
30798944Sobrien      {
30898944Sobrien	tmp *= 2.0l;
30998944Sobrien	exp++;
31098944Sobrien      }
31198944Sobrien  else if (value != 0.0l)	/* Value < 1.0  and > 0.0 */
31298944Sobrien    {
31398944Sobrien      while (value < tmp)
31498944Sobrien	{
31598944Sobrien	  tmp /= 2.0l;
31698944Sobrien	  exp--;
31798944Sobrien	}
31898944Sobrien      tmp *= 2.0l;
31998944Sobrien      exp++;
32098944Sobrien    }
32198944Sobrien
32298944Sobrien  *eptr = exp;
32398944Sobrien  return value / tmp;
32498944Sobrien}
32598944Sobrien#endif /* HAVE_LONG_DOUBLE */
32698944Sobrien
32798944Sobrien
32898944Sobrien/* The converse: convert the DOUBLEST *FROM to an extended float
32998944Sobrien   and store where TO points.  Neither FROM nor TO have any alignment
33098944Sobrien   restrictions.  */
33198944Sobrien
33298944Sobrienstatic void
33398944Sobrienconvert_doublest_to_floatformat (CONST struct floatformat *fmt,
33498944Sobrien				 const DOUBLEST *from,
33598944Sobrien				 void *to)
33698944Sobrien{
33798944Sobrien  DOUBLEST dfrom;
33898944Sobrien  int exponent;
33998944Sobrien  DOUBLEST mant;
34098944Sobrien  unsigned int mant_bits, mant_off;
34198944Sobrien  int mant_bits_left;
34298944Sobrien  unsigned char *uto = (unsigned char *) to;
34398944Sobrien
34498944Sobrien  memcpy (&dfrom, from, sizeof (dfrom));
34598944Sobrien  memset (uto, 0, (fmt->totalsize + FLOATFORMAT_CHAR_BIT - 1)
34698944Sobrien                    / FLOATFORMAT_CHAR_BIT);
34798944Sobrien  if (dfrom == 0)
34898944Sobrien    return;			/* Result is zero */
34998944Sobrien  if (dfrom != dfrom)		/* Result is NaN */
35098944Sobrien    {
35198944Sobrien      /* From is NaN */
35298944Sobrien      put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start,
35398944Sobrien		 fmt->exp_len, fmt->exp_nan);
35498944Sobrien      /* Be sure it's not infinity, but NaN value is irrel */
35598944Sobrien      put_field (uto, fmt->byteorder, fmt->totalsize, fmt->man_start,
35698944Sobrien		 32, 1);
35798944Sobrien      return;
35898944Sobrien    }
35998944Sobrien
36098944Sobrien  /* If negative, set the sign bit.  */
36198944Sobrien  if (dfrom < 0)
36298944Sobrien    {
36398944Sobrien      put_field (uto, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1, 1);
36498944Sobrien      dfrom = -dfrom;
36598944Sobrien    }
36698944Sobrien
36798944Sobrien  if (dfrom + dfrom == dfrom && dfrom != 0.0)	/* Result is Infinity */
36898944Sobrien    {
36998944Sobrien      /* Infinity exponent is same as NaN's.  */
37098944Sobrien      put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start,
37198944Sobrien		 fmt->exp_len, fmt->exp_nan);
37298944Sobrien      /* Infinity mantissa is all zeroes.  */
37398944Sobrien      put_field (uto, fmt->byteorder, fmt->totalsize, fmt->man_start,
37498944Sobrien		 fmt->man_len, 0);
37598944Sobrien      return;
37698944Sobrien    }
37798944Sobrien
37898944Sobrien#ifdef HAVE_LONG_DOUBLE
37998944Sobrien  mant = ldfrexp (dfrom, &exponent);
38098944Sobrien#else
38198944Sobrien  mant = frexp (dfrom, &exponent);
38298944Sobrien#endif
38398944Sobrien
38498944Sobrien  put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start, fmt->exp_len,
38598944Sobrien	     exponent + fmt->exp_bias - 1);
38698944Sobrien
38798944Sobrien  mant_bits_left = fmt->man_len;
38898944Sobrien  mant_off = fmt->man_start;
38998944Sobrien  while (mant_bits_left > 0)
39098944Sobrien    {
39198944Sobrien      unsigned long mant_long;
39298944Sobrien      mant_bits = mant_bits_left < 32 ? mant_bits_left : 32;
39398944Sobrien
39498944Sobrien      mant *= 4294967296.0;
39598944Sobrien      mant_long = ((unsigned long) mant) & 0xffffffffL;
39698944Sobrien      mant -= mant_long;
39798944Sobrien
39898944Sobrien      /* If the integer bit is implicit, then we need to discard it.
39998944Sobrien         If we are discarding a zero, we should be (but are not) creating
40098944Sobrien         a denormalized number which means adjusting the exponent
40198944Sobrien         (I think).  */
40298944Sobrien      if (mant_bits_left == fmt->man_len
40398944Sobrien	  && fmt->intbit == floatformat_intbit_no)
40498944Sobrien	{
40598944Sobrien	  mant_long <<= 1;
40698944Sobrien	  mant_long &= 0xffffffffL;
407130803Smarcel          /* If we are processing the top 32 mantissa bits of a doublest
408130803Smarcel             so as to convert to a float value with implied integer bit,
409130803Smarcel             we will only be putting 31 of those 32 bits into the
410130803Smarcel             final value due to the discarding of the top bit.  In the
411130803Smarcel             case of a small float value where the number of mantissa
412130803Smarcel             bits is less than 32, discarding the top bit does not alter
413130803Smarcel             the number of bits we will be adding to the result.  */
414130803Smarcel          if (mant_bits == 32)
415130803Smarcel            mant_bits -= 1;
41698944Sobrien	}
41798944Sobrien
41898944Sobrien      if (mant_bits < 32)
41998944Sobrien	{
42098944Sobrien	  /* The bits we want are in the most significant MANT_BITS bits of
42198944Sobrien	     mant_long.  Move them to the least significant.  */
42298944Sobrien	  mant_long >>= 32 - mant_bits;
42398944Sobrien	}
42498944Sobrien
42598944Sobrien      put_field (uto, fmt->byteorder, fmt->totalsize,
42698944Sobrien		 mant_off, mant_bits, mant_long);
42798944Sobrien      mant_off += mant_bits;
42898944Sobrien      mant_bits_left -= mant_bits;
42998944Sobrien    }
43098944Sobrien  if (fmt->byteorder == floatformat_littlebyte_bigword)
43198944Sobrien    {
43298944Sobrien      int count;
43398944Sobrien      unsigned char *swaplow = uto;
43498944Sobrien      unsigned char *swaphigh = uto + 4;
43598944Sobrien      unsigned char tmp;
43698944Sobrien
43798944Sobrien      for (count = 0; count < 4; count++)
43898944Sobrien	{
43998944Sobrien	  tmp = *swaplow;
44098944Sobrien	  *swaplow++ = *swaphigh;
44198944Sobrien	  *swaphigh++ = tmp;
44298944Sobrien	}
44398944Sobrien    }
44498944Sobrien}
44598944Sobrien
44698944Sobrien/* Check if VAL (which is assumed to be a floating point number whose
44798944Sobrien   format is described by FMT) is negative.  */
44898944Sobrien
44998944Sobrienint
45098944Sobrienfloatformat_is_negative (const struct floatformat *fmt, char *val)
45198944Sobrien{
45298944Sobrien  unsigned char *uval = (unsigned char *) val;
45398944Sobrien  gdb_assert (fmt != NULL);
45498944Sobrien  return get_field (uval, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1);
45598944Sobrien}
45698944Sobrien
45798944Sobrien/* Check if VAL is "not a number" (NaN) for FMT.  */
45898944Sobrien
45998944Sobrienint
46098944Sobrienfloatformat_is_nan (const struct floatformat *fmt, char *val)
46198944Sobrien{
46298944Sobrien  unsigned char *uval = (unsigned char *) val;
46398944Sobrien  long exponent;
46498944Sobrien  unsigned long mant;
46598944Sobrien  unsigned int mant_bits, mant_off;
46698944Sobrien  int mant_bits_left;
46798944Sobrien
46898944Sobrien  gdb_assert (fmt != NULL);
46998944Sobrien
47098944Sobrien  if (! fmt->exp_nan)
47198944Sobrien    return 0;
47298944Sobrien
47398944Sobrien  exponent = get_field (uval, fmt->byteorder, fmt->totalsize,
47498944Sobrien			fmt->exp_start, fmt->exp_len);
47598944Sobrien
47698944Sobrien  if (exponent != fmt->exp_nan)
47798944Sobrien    return 0;
47898944Sobrien
47998944Sobrien  mant_bits_left = fmt->man_len;
48098944Sobrien  mant_off = fmt->man_start;
48198944Sobrien
48298944Sobrien  while (mant_bits_left > 0)
48398944Sobrien    {
48498944Sobrien      mant_bits = min (mant_bits_left, 32);
48598944Sobrien
48698944Sobrien      mant = get_field (uval, fmt->byteorder, fmt->totalsize,
48798944Sobrien			mant_off, mant_bits);
48898944Sobrien
48998944Sobrien      /* If there is an explicit integer bit, mask it off.  */
49098944Sobrien      if (mant_off == fmt->man_start
49198944Sobrien	  && fmt->intbit == floatformat_intbit_yes)
49298944Sobrien	mant &= ~(1 << (mant_bits - 1));
49398944Sobrien
49498944Sobrien      if (mant)
49598944Sobrien	return 1;
49698944Sobrien
49798944Sobrien      mant_off += mant_bits;
49898944Sobrien      mant_bits_left -= mant_bits;
49998944Sobrien    }
50098944Sobrien
50198944Sobrien  return 0;
50298944Sobrien}
50398944Sobrien
50498944Sobrien/* Convert the mantissa of VAL (which is assumed to be a floating
50598944Sobrien   point number whose format is described by FMT) into a hexadecimal
50698944Sobrien   and store it in a static string.  Return a pointer to that string.  */
50798944Sobrien
50898944Sobrienchar *
50998944Sobrienfloatformat_mantissa (const struct floatformat *fmt, char *val)
51098944Sobrien{
51198944Sobrien  unsigned char *uval = (unsigned char *) val;
51298944Sobrien  unsigned long mant;
51398944Sobrien  unsigned int mant_bits, mant_off;
51498944Sobrien  int mant_bits_left;
51598944Sobrien  static char res[50];
51698944Sobrien  char buf[9];
51798944Sobrien
51898944Sobrien  /* Make sure we have enough room to store the mantissa.  */
51998944Sobrien  gdb_assert (fmt != NULL);
52098944Sobrien  gdb_assert (sizeof res > ((fmt->man_len + 7) / 8) * 2);
52198944Sobrien
52298944Sobrien  mant_off = fmt->man_start;
52398944Sobrien  mant_bits_left = fmt->man_len;
52498944Sobrien  mant_bits = (mant_bits_left % 32) > 0 ? mant_bits_left % 32 : 32;
52598944Sobrien
52698944Sobrien  mant = get_field (uval, fmt->byteorder, fmt->totalsize,
52798944Sobrien		    mant_off, mant_bits);
52898944Sobrien
52998944Sobrien  sprintf (res, "%lx", mant);
53098944Sobrien
53198944Sobrien  mant_off += mant_bits;
53298944Sobrien  mant_bits_left -= mant_bits;
53398944Sobrien
53498944Sobrien  while (mant_bits_left > 0)
53598944Sobrien    {
53698944Sobrien      mant = get_field (uval, fmt->byteorder, fmt->totalsize,
53798944Sobrien			mant_off, 32);
53898944Sobrien
53998944Sobrien      sprintf (buf, "%08lx", mant);
54098944Sobrien      strcat (res, buf);
54198944Sobrien
54298944Sobrien      mant_off += 32;
54398944Sobrien      mant_bits_left -= 32;
54498944Sobrien    }
54598944Sobrien
54698944Sobrien  return res;
54798944Sobrien}
54898944Sobrien
54998944Sobrien
55098944Sobrien/* Convert TO/FROM target to the hosts DOUBLEST floating-point format.
55198944Sobrien
55298944Sobrien   If the host and target formats agree, we just copy the raw data
55398944Sobrien   into the appropriate type of variable and return, letting the host
55498944Sobrien   increase precision as necessary.  Otherwise, we call the conversion
55598944Sobrien   routine and let it do the dirty work.  */
55698944Sobrien
55798944Sobrien#ifndef HOST_FLOAT_FORMAT
55898944Sobrien#define HOST_FLOAT_FORMAT 0
55998944Sobrien#endif
56098944Sobrien#ifndef HOST_DOUBLE_FORMAT
56198944Sobrien#define HOST_DOUBLE_FORMAT 0
56298944Sobrien#endif
56398944Sobrien#ifndef HOST_LONG_DOUBLE_FORMAT
56498944Sobrien#define HOST_LONG_DOUBLE_FORMAT 0
56598944Sobrien#endif
56698944Sobrien
56798944Sobrienstatic const struct floatformat *host_float_format = HOST_FLOAT_FORMAT;
56898944Sobrienstatic const struct floatformat *host_double_format = HOST_DOUBLE_FORMAT;
56998944Sobrienstatic const struct floatformat *host_long_double_format = HOST_LONG_DOUBLE_FORMAT;
57098944Sobrien
57198944Sobrienvoid
57298944Sobrienfloatformat_to_doublest (const struct floatformat *fmt,
57398944Sobrien			 const void *in, DOUBLEST *out)
57498944Sobrien{
57598944Sobrien  gdb_assert (fmt != NULL);
57698944Sobrien  if (fmt == host_float_format)
57798944Sobrien    {
57898944Sobrien      float val;
57998944Sobrien      memcpy (&val, in, sizeof (val));
58098944Sobrien      *out = val;
58198944Sobrien    }
58298944Sobrien  else if (fmt == host_double_format)
58398944Sobrien    {
58498944Sobrien      double val;
58598944Sobrien      memcpy (&val, in, sizeof (val));
58698944Sobrien      *out = val;
58798944Sobrien    }
58898944Sobrien  else if (fmt == host_long_double_format)
58998944Sobrien    {
59098944Sobrien      long double val;
59198944Sobrien      memcpy (&val, in, sizeof (val));
59298944Sobrien      *out = val;
59398944Sobrien    }
59498944Sobrien  else
59598944Sobrien    convert_floatformat_to_doublest (fmt, in, out);
59698944Sobrien}
59798944Sobrien
59898944Sobrienvoid
59998944Sobrienfloatformat_from_doublest (const struct floatformat *fmt,
60098944Sobrien			   const DOUBLEST *in, void *out)
60198944Sobrien{
60298944Sobrien  gdb_assert (fmt != NULL);
60398944Sobrien  if (fmt == host_float_format)
60498944Sobrien    {
60598944Sobrien      float val = *in;
60698944Sobrien      memcpy (out, &val, sizeof (val));
60798944Sobrien    }
60898944Sobrien  else if (fmt == host_double_format)
60998944Sobrien    {
61098944Sobrien      double val = *in;
61198944Sobrien      memcpy (out, &val, sizeof (val));
61298944Sobrien    }
61398944Sobrien  else if (fmt == host_long_double_format)
61498944Sobrien    {
61598944Sobrien      long double val = *in;
61698944Sobrien      memcpy (out, &val, sizeof (val));
61798944Sobrien    }
61898944Sobrien  else
61998944Sobrien    convert_doublest_to_floatformat (fmt, in, out);
62098944Sobrien}
62198944Sobrien
62298944Sobrien
62398944Sobrien/* Return a floating-point format for a floating-point variable of
62498944Sobrien   length LEN.  Return NULL, if no suitable floating-point format
62598944Sobrien   could be found.
62698944Sobrien
62798944Sobrien   We need this functionality since information about the
62898944Sobrien   floating-point format of a type is not always available to GDB; the
62998944Sobrien   debug information typically only tells us the size of a
63098944Sobrien   floating-point type.
63198944Sobrien
63298944Sobrien   FIXME: kettenis/2001-10-28: In many places, particularly in
63398944Sobrien   target-dependent code, the format of floating-point types is known,
63498944Sobrien   but not passed on by GDB.  This should be fixed.  */
63598944Sobrien
636130803Smarcelstatic const struct floatformat *
63798944Sobrienfloatformat_from_length (int len)
63898944Sobrien{
63998944Sobrien  if (len * TARGET_CHAR_BIT == TARGET_FLOAT_BIT)
64098944Sobrien    return TARGET_FLOAT_FORMAT;
64198944Sobrien  else if (len * TARGET_CHAR_BIT == TARGET_DOUBLE_BIT)
64298944Sobrien    return TARGET_DOUBLE_FORMAT;
64398944Sobrien  else if (len * TARGET_CHAR_BIT == TARGET_LONG_DOUBLE_BIT)
64498944Sobrien    return TARGET_LONG_DOUBLE_FORMAT;
645130803Smarcel  /* On i386 the 'long double' type takes 96 bits,
646130803Smarcel     while the real number of used bits is only 80,
647130803Smarcel     both in processor and in memory.
648130803Smarcel     The code below accepts the real bit size.  */
649130803Smarcel  else if ((TARGET_LONG_DOUBLE_FORMAT != NULL)
650130803Smarcel	   && (len * TARGET_CHAR_BIT ==
651130803Smarcel               TARGET_LONG_DOUBLE_FORMAT->totalsize))
652130803Smarcel    return TARGET_LONG_DOUBLE_FORMAT;
65398944Sobrien
65498944Sobrien  return NULL;
65598944Sobrien}
65698944Sobrien
65798944Sobrienconst struct floatformat *
65898944Sobrienfloatformat_from_type (const struct type *type)
65998944Sobrien{
66098944Sobrien  gdb_assert (TYPE_CODE (type) == TYPE_CODE_FLT);
66198944Sobrien  if (TYPE_FLOATFORMAT (type) != NULL)
66298944Sobrien    return TYPE_FLOATFORMAT (type);
66398944Sobrien  else
66498944Sobrien    return floatformat_from_length (TYPE_LENGTH (type));
66598944Sobrien}
66698944Sobrien
66798944Sobrien/* If the host doesn't define NAN, use zero instead.  */
66898944Sobrien#ifndef NAN
66998944Sobrien#define NAN 0.0
67098944Sobrien#endif
67198944Sobrien
67298944Sobrien/* Extract a floating-point number of length LEN from a target-order
67398944Sobrien   byte-stream at ADDR.  Returns the value as type DOUBLEST.  */
67498944Sobrien
675130803Smarcelstatic DOUBLEST
676130803Smarcelextract_floating_by_length (const void *addr, int len)
67798944Sobrien{
67898944Sobrien  const struct floatformat *fmt = floatformat_from_length (len);
67998944Sobrien  DOUBLEST val;
68098944Sobrien
68198944Sobrien  if (fmt == NULL)
68298944Sobrien    {
683130803Smarcel      warning ("Can't extract a floating-point number of %d bytes.", len);
68498944Sobrien      return NAN;
68598944Sobrien    }
68698944Sobrien
68798944Sobrien  floatformat_to_doublest (fmt, addr, &val);
68898944Sobrien  return val;
68998944Sobrien}
69098944Sobrien
691130803SmarcelDOUBLEST
692130803Smarceldeprecated_extract_floating (const void *addr, int len)
693130803Smarcel{
694130803Smarcel  return extract_floating_by_length (addr, len);
695130803Smarcel}
696130803Smarcel
69798944Sobrien/* Store VAL as a floating-point number of length LEN to a
69898944Sobrien   target-order byte-stream at ADDR.  */
69998944Sobrien
700130803Smarcelstatic void
701130803Smarcelstore_floating_by_length (void *addr, int len, DOUBLEST val)
70298944Sobrien{
70398944Sobrien  const struct floatformat *fmt = floatformat_from_length (len);
70498944Sobrien
70598944Sobrien  if (fmt == NULL)
70698944Sobrien    {
70798944Sobrien      warning ("Can't store a floating-point number of %d bytes.", len);
70898944Sobrien      memset (addr, 0, len);
709130803Smarcel      return;
71098944Sobrien    }
71198944Sobrien
71298944Sobrien  floatformat_from_doublest (fmt, &val, addr);
71398944Sobrien}
71498944Sobrien
715130803Smarcelvoid
716130803Smarceldeprecated_store_floating (void *addr, int len, DOUBLEST val)
717130803Smarcel{
718130803Smarcel  store_floating_by_length (addr, len, val);
719130803Smarcel}
720130803Smarcel
72198944Sobrien/* Extract a floating-point number of type TYPE from a target-order
72298944Sobrien   byte-stream at ADDR.  Returns the value as type DOUBLEST.  */
72398944Sobrien
72498944SobrienDOUBLEST
72598944Sobrienextract_typed_floating (const void *addr, const struct type *type)
72698944Sobrien{
72798944Sobrien  DOUBLEST retval;
72898944Sobrien
72998944Sobrien  gdb_assert (TYPE_CODE (type) == TYPE_CODE_FLT);
73098944Sobrien
73198944Sobrien  if (TYPE_FLOATFORMAT (type) == NULL)
732130803Smarcel    /* Not all code remembers to set the FLOATFORMAT (language
733130803Smarcel       specific code? stabs?) so handle that here as a special case.  */
734130803Smarcel    return extract_floating_by_length (addr, TYPE_LENGTH (type));
73598944Sobrien
73698944Sobrien  floatformat_to_doublest (TYPE_FLOATFORMAT (type), addr, &retval);
73798944Sobrien  return retval;
73898944Sobrien}
73998944Sobrien
74098944Sobrien/* Store VAL as a floating-point number of type TYPE to a target-order
74198944Sobrien   byte-stream at ADDR.  */
74298944Sobrien
74398944Sobrienvoid
74498944Sobrienstore_typed_floating (void *addr, const struct type *type, DOUBLEST val)
74598944Sobrien{
74698944Sobrien  gdb_assert (TYPE_CODE (type) == TYPE_CODE_FLT);
74798944Sobrien
74898944Sobrien  /* FIXME: kettenis/2001-10-28: It is debatable whether we should
74998944Sobrien     zero out any remaining bytes in the target buffer when TYPE is
75098944Sobrien     longer than the actual underlying floating-point format.  Perhaps
75198944Sobrien     we should store a fixed bitpattern in those remaining bytes,
75298944Sobrien     instead of zero, or perhaps we shouldn't touch those remaining
75398944Sobrien     bytes at all.
75498944Sobrien
75598944Sobrien     NOTE: cagney/2001-10-28: With the way things currently work, it
75698944Sobrien     isn't a good idea to leave the end bits undefined.  This is
75798944Sobrien     because GDB writes out the entire sizeof(<floating>) bits of the
75898944Sobrien     floating-point type even though the value might only be stored
75998944Sobrien     in, and the target processor may only refer to, the first N <
76098944Sobrien     TYPE_LENGTH (type) bits.  If the end of the buffer wasn't
76198944Sobrien     initialized, GDB would write undefined data to the target.  An
76298944Sobrien     errant program, refering to that undefined data, would then
76398944Sobrien     become non-deterministic.
76498944Sobrien
76598944Sobrien     See also the function convert_typed_floating below.  */
76698944Sobrien  memset (addr, 0, TYPE_LENGTH (type));
76798944Sobrien
76898944Sobrien  if (TYPE_FLOATFORMAT (type) == NULL)
769130803Smarcel    /* Not all code remembers to set the FLOATFORMAT (language
770130803Smarcel       specific code? stabs?) so handle that here as a special case.  */
771130803Smarcel    store_floating_by_length (addr, TYPE_LENGTH (type), val);
77298944Sobrien  else
77398944Sobrien    floatformat_from_doublest (TYPE_FLOATFORMAT (type), &val, addr);
77498944Sobrien}
77598944Sobrien
77698944Sobrien/* Convert a floating-point number of type FROM_TYPE from a
77798944Sobrien   target-order byte-stream at FROM to a floating-point number of type
77898944Sobrien   TO_TYPE, and store it to a target-order byte-stream at TO.  */
77998944Sobrien
78098944Sobrienvoid
78198944Sobrienconvert_typed_floating (const void *from, const struct type *from_type,
78298944Sobrien                        void *to, const struct type *to_type)
78398944Sobrien{
78498944Sobrien  const struct floatformat *from_fmt = floatformat_from_type (from_type);
78598944Sobrien  const struct floatformat *to_fmt = floatformat_from_type (to_type);
78698944Sobrien
78798944Sobrien  gdb_assert (TYPE_CODE (from_type) == TYPE_CODE_FLT);
78898944Sobrien  gdb_assert (TYPE_CODE (to_type) == TYPE_CODE_FLT);
78998944Sobrien
79098944Sobrien  if (from_fmt == NULL || to_fmt == NULL)
79198944Sobrien    {
79298944Sobrien      /* If we don't know the floating-point format of FROM_TYPE or
79398944Sobrien         TO_TYPE, there's not much we can do.  We might make the
79498944Sobrien         assumption that if the length of FROM_TYPE and TO_TYPE match,
79598944Sobrien         their floating-point format would match too, but that
79698944Sobrien         assumption might be wrong on targets that support
79798944Sobrien         floating-point types that only differ in endianness for
79898944Sobrien         example.  So we warn instead, and zero out the target buffer.  */
79998944Sobrien      warning ("Can't convert floating-point number to desired type.");
80098944Sobrien      memset (to, 0, TYPE_LENGTH (to_type));
80198944Sobrien    }
80298944Sobrien  else if (from_fmt == to_fmt)
80398944Sobrien    {
80498944Sobrien      /* We're in business.  The floating-point format of FROM_TYPE
80598944Sobrien         and TO_TYPE match.  However, even though the floating-point
80698944Sobrien         format matches, the length of the type might still be
80798944Sobrien         different.  Make sure we don't overrun any buffers.  See
80898944Sobrien         comment in store_typed_floating for a discussion about
80998944Sobrien         zeroing out remaining bytes in the target buffer.  */
81098944Sobrien      memset (to, 0, TYPE_LENGTH (to_type));
81198944Sobrien      memcpy (to, from, min (TYPE_LENGTH (from_type), TYPE_LENGTH (to_type)));
81298944Sobrien    }
81398944Sobrien  else
81498944Sobrien    {
81598944Sobrien      /* The floating-point types don't match.  The best we can do
81698944Sobrien         (aport from simulating the target FPU) is converting to the
81798944Sobrien         widest floating-point type supported by the host, and then
81898944Sobrien         again to the desired type.  */
81998944Sobrien      DOUBLEST d;
82098944Sobrien
82198944Sobrien      floatformat_to_doublest (from_fmt, from, &d);
82298944Sobrien      floatformat_from_doublest (to_fmt, &d, to);
82398944Sobrien    }
82498944Sobrien}
825