Back to index

cell-binutils  2.17cvs20070401
Defines | Functions
floatformat.c File Reference
#include <math.h>
#include "ansidecl.h"
#include "libiberty.h"
#include "floatformat.h"

Go to the source code of this file.

Defines

#define _GNU_SOURCE
#define INFINITY   (1.0 / 0.0)
#define NAN   (0.0 / 0.0)
#define FLOATFORMAT_CHAR_BIT   8
#define min(a, b)   ((a) < (b) ? (a) : (b))

Functions

static unsigned long get_field (const unsigned char *, enum floatformat_byteorders, unsigned int, unsigned int, unsigned int)
static int floatformat_always_valid (const struct floatformat *fmt, const void *from)
static int floatformat_always_valid (const struct floatformat *fmt ATTRIBUTE_UNUSED, const void *from ATTRIBUTE_UNUSED)
static int floatformat_i387_ext_is_valid (const struct floatformat *fmt, const void *from)
void floatformat_to_double (const struct floatformat *fmt, const void *from, double *to)
static void put_field (unsigned char *, enum floatformat_byteorders, unsigned int, unsigned int, unsigned int, unsigned long)
void floatformat_from_double (const struct floatformat *fmt, const double *from, void *to)
int floatformat_is_valid (const struct floatformat *fmt, const void *from)

Define Documentation

#define _GNU_SOURCE

Definition at line 22 of file floatformat.c.

#define FLOATFORMAT_CHAR_BIT   8

Definition at line 77 of file floatformat.c.

#define INFINITY   (1.0 / 0.0)

Definition at line 47 of file floatformat.c.

#define min (   a,
  b 
)    ((a) < (b) ? (a) : (b))

Definition at line 254 of file floatformat.c.

#define NAN   (0.0 / 0.0)

Definition at line 55 of file floatformat.c.


Function Documentation

static int floatformat_always_valid ( const struct floatformat fmt,
const void *  from 
) [static]
static int floatformat_always_valid ( const struct floatformat *fmt  ATTRIBUTE_UNUSED,
const void *from  ATTRIBUTE_UNUSED 
) [static]

Definition at line 68 of file floatformat.c.

{
  return 1;
}
void floatformat_from_double ( const struct floatformat fmt,
const double from,
void *  to 
)

Definition at line 464 of file floatformat.c.

{
  double dfrom;
  int exponent;
  double mant;
  unsigned int mant_bits, mant_off;
  int mant_bits_left;
  unsigned char *uto = (unsigned char *) to;

  dfrom = *from;
  memset (uto, 0, fmt->totalsize / FLOATFORMAT_CHAR_BIT);

  /* If negative, set the sign bit.  */
  if (dfrom < 0)
    {
      put_field (uto, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1, 1);
      dfrom = -dfrom;
    }

  if (dfrom == 0)
    {
      /* 0.0.  */
      return;
    }

  if (dfrom != dfrom)
    {
      /* NaN.  */
      put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start,
               fmt->exp_len, fmt->exp_nan);
      /* Be sure it's not infinity, but NaN value is irrelevant.  */
      put_field (uto, fmt->byteorder, fmt->totalsize, fmt->man_start,
               32, 1);
      return;
    }

  if (dfrom + dfrom == dfrom)
    {
      /* This can only happen for an infinite value (or zero, which we
        already handled above).  */
      put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start,
               fmt->exp_len, fmt->exp_nan);
      return;
    }

  mant = frexp (dfrom, &exponent);
  if (exponent + fmt->exp_bias - 1 > 0)
    put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start,
              fmt->exp_len, exponent + fmt->exp_bias - 1);
  else
    {
      /* Handle a denormalized number.  FIXME: What should we do for
        non-IEEE formats?  */
      put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start,
               fmt->exp_len, 0);
      mant = ldexp (mant, 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;
      mant -= mant_long;

      /* If the integer bit is implicit, and we are not creating a
        denormalized number, then we need to discard it.  */
      if ((unsigned int) mant_bits_left == fmt->man_len
         && fmt->intbit == floatformat_intbit_no
         && exponent + fmt->exp_bias - 1 > 0)
       {
         mant_long &= 0x7fffffff;
         mant_bits -= 1;
       }
      else 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, fmt->byteorder, fmt->totalsize,
               mant_off, mant_bits, mant_long);
      mant_off += mant_bits;
      mant_bits_left -= mant_bits;
    }
}

Here is the call graph for this function:

static int floatformat_i387_ext_is_valid ( const struct floatformat fmt,
const void *  from 
) [static]

Definition at line 148 of file floatformat.c.

{
  /* In the i387 double-extended format, if the exponent is all ones,
     then the integer bit must be set.  If the exponent is neither 0
     nor ~0, the intbit must also be set.  Only if the exponent is
     zero can it be zero, and then it must be zero.  */
  unsigned long exponent, int_bit;
  const unsigned char *ufrom = (const unsigned char *) from;

  exponent = get_field (ufrom, fmt->byteorder, fmt->totalsize,
                     fmt->exp_start, fmt->exp_len);
  int_bit = get_field (ufrom, fmt->byteorder, fmt->totalsize,
                     fmt->man_start, 1);

  if ((exponent == 0) != (int_bit == 0))
    return 0;
  else
    return 1;
}

Here is the call graph for this function:

int floatformat_is_valid ( const struct floatformat fmt,
const void *  from 
)

Definition at line 560 of file floatformat.c.

{
  return fmt->is_valid (fmt, from);
}
void floatformat_to_double ( const struct floatformat fmt,
const void *  from,
double to 
)

Definition at line 302 of file floatformat.c.

{
  const unsigned char *ufrom = (const unsigned char *) from;
  double dto;
  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 */

  exponent = get_field (ufrom, fmt->byteorder, fmt->totalsize,
                     fmt->exp_start, fmt->exp_len);

  /* If the exponent indicates a NaN, we don't have information to
     decide what to do.  So we handle it like IEEE, except that we
     don't try to preserve the type of NaN.  FIXME.  */
  if ((unsigned long) exponent == fmt->exp_nan)
    {
      int nan;

      mant_off = fmt->man_start;
      mant_bits_left = fmt->man_len;
      nan = 0;
      while (mant_bits_left > 0)
       {
         mant_bits = min (mant_bits_left, 32);

         if (get_field (ufrom, fmt->byteorder, fmt->totalsize,
                      mant_off, mant_bits) != 0)
           {
             /* This is a NaN.  */
             nan = 1;
             break;
           }

         mant_off += mant_bits;
         mant_bits_left -= mant_bits;
       }

      /* On certain systems (such as GNU/Linux), the use of the
        INFINITY macro below may generate a warning that can not be
        silenced due to a bug in GCC (PR preprocessor/11931).  The
        preprocessor fails to recognise the __extension__ keyword in
        conjunction with the GNU/C99 extension for hexadecimal
        floating point constants and will issue a warning when
        compiling with -pedantic.  */
      if (nan)
       dto = NAN;
      else
       dto = INFINITY;

      if (get_field (ufrom, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1))
       dto = -dto;

      *to = dto;

      return;
    }

  mant_bits_left = fmt->man_len;
  mant_off = fmt->man_start;
  dto = 0.0;

  special_exponent = exponent == 0 || (unsigned long) exponent == fmt->exp_nan;

  /* Don't bias zero's, denorms or NaNs.  */
  if (!special_exponent)
    exponent -= 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 = min (mant_bits_left, 32);

      mant = get_field (ufrom, fmt->byteorder, fmt->totalsize,
                      mant_off, mant_bits);

      /* Handle denormalized numbers.  FIXME: What should we do for
        non-IEEE formats?  */
      if (special_exponent && exponent == 0 && mant != 0)
       dto += ldexp ((double)mant,
                    (- fmt->exp_bias
                     - mant_bits
                     - (mant_off - fmt->man_start)
                     + 1));
      else
       dto += ldexp ((double)mant, exponent - mant_bits);
      if (exponent != 0)
       exponent -= mant_bits;
      mant_off += mant_bits;
      mant_bits_left -= mant_bits;
    }

  /* Negate it if negative.  */
  if (get_field (ufrom, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1))
    dto = -dto;
  *to = dto;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static unsigned long get_field ( const unsigned char *  data,
enum floatformat_byteorders  order,
unsigned int  total_len,
unsigned int  start,
unsigned int  len 
) [static]

Definition at line 260 of file floatformat.c.

{
  unsigned long result = 0;
  unsigned int cur_byte;
  int lo_bit, hi_bit, cur_bitshift = 0;
  int nextbyte = (order == floatformat_little) ? 1 : -1;

  /* Start is in big-endian bit order!  Fix that first.  */
  start = total_len - (start + len);

  /* Start at the least significant part of the field.  */
  if (order == floatformat_little)
    cur_byte = start / FLOATFORMAT_CHAR_BIT;
  else
    cur_byte = (total_len - start - 1) / FLOATFORMAT_CHAR_BIT;

  lo_bit = start % FLOATFORMAT_CHAR_BIT;
  hi_bit = min (lo_bit + len, FLOATFORMAT_CHAR_BIT);
  
  do
    {
      unsigned int shifted = *(data + cur_byte) >> lo_bit;
      unsigned int bits = hi_bit - lo_bit;
      unsigned int mask = (1 << bits) - 1;
      result |= (shifted & mask) << cur_bitshift;
      len -= bits;
      cur_bitshift += bits;
      cur_byte += nextbyte;
      lo_bit = 0;
      hi_bit = min (len, FLOATFORMAT_CHAR_BIT);
    }
  while (len != 0);

  return result;
}

Here is the caller graph for this function:

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 
) [static]

Definition at line 424 of file floatformat.c.

{
  unsigned int cur_byte;
  int lo_bit, hi_bit;
  int nextbyte = (order == floatformat_little) ? 1 : -1;

  /* Start is in big-endian bit order!  Fix that first.  */
  start = total_len - (start + len);

  /* Start at the least significant part of the field.  */
  if (order == floatformat_little)
    cur_byte = start / FLOATFORMAT_CHAR_BIT;
  else
    cur_byte = (total_len - start - 1) / FLOATFORMAT_CHAR_BIT;

  lo_bit = start % FLOATFORMAT_CHAR_BIT;
  hi_bit = min (lo_bit + len, FLOATFORMAT_CHAR_BIT);
  
  do
    {
      unsigned char *byte_ptr = data + cur_byte;
      unsigned int bits = hi_bit - lo_bit;
      unsigned int mask = ((1 << bits) - 1) << lo_bit;
      *byte_ptr = (*byte_ptr & ~mask) | ((stuff_to_put << lo_bit) & mask);
      stuff_to_put >>= bits;
      len -= bits;
      cur_byte += nextbyte;
      lo_bit = 0;
      hi_bit = min (len, FLOATFORMAT_CHAR_BIT);
    }
  while (len != 0);
}

Here is the caller graph for this function: