Back to index

cell-binutils  2.17cvs20070401
floatformat.c
Go to the documentation of this file.
00001 /* IEEE floating point support routines, for GDB, the GNU Debugger.
00002    Copyright 1991, 1994, 1999, 2000, 2003, 2005, 2006
00003    Free Software Foundation, Inc.
00004 
00005 This file is part of GDB.
00006 
00007 This program is free software; you can redistribute it and/or modify
00008 it under the terms of the GNU General Public License as published by
00009 the Free Software Foundation; either version 2 of the License, or
00010 (at your option) any later version.
00011 
00012 This program is distributed in the hope that it will be useful,
00013 but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 GNU General Public License for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with this program; if not, write to the Free Software
00019 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
00020 
00021 /* This is needed to pick up the NAN macro on some systems.  */
00022 #define _GNU_SOURCE
00023 
00024 #ifdef HAVE_CONFIG_H
00025 #include "config.h"
00026 #endif
00027 
00028 #include <math.h>
00029 
00030 #ifdef HAVE_STRING_H
00031 #include <string.h>
00032 #endif
00033 
00034 /* On some platforms, <float.h> provides DBL_QNAN.  */
00035 #ifdef STDC_HEADERS
00036 #include <float.h>
00037 #endif
00038 
00039 #include "ansidecl.h"
00040 #include "libiberty.h"
00041 #include "floatformat.h"
00042 
00043 #ifndef INFINITY
00044 #ifdef HUGE_VAL
00045 #define INFINITY HUGE_VAL
00046 #else
00047 #define INFINITY (1.0 / 0.0)
00048 #endif
00049 #endif
00050 
00051 #ifndef NAN
00052 #ifdef DBL_QNAN
00053 #define NAN DBL_QNAN
00054 #else
00055 #define NAN (0.0 / 0.0)
00056 #endif
00057 #endif
00058 
00059 static unsigned long get_field (const unsigned char *,
00060                                 enum floatformat_byteorders,
00061                                 unsigned int,
00062                                 unsigned int,
00063                                 unsigned int);
00064 static int floatformat_always_valid (const struct floatformat *fmt,
00065                                      const void *from);
00066 
00067 static int
00068 floatformat_always_valid (const struct floatformat *fmt ATTRIBUTE_UNUSED,
00069                           const void *from ATTRIBUTE_UNUSED)
00070 {
00071   return 1;
00072 }
00073 
00074 /* The odds that CHAR_BIT will be anything but 8 are low enough that I'm not
00075    going to bother with trying to muck around with whether it is defined in
00076    a system header, what we do if not, etc.  */
00077 #define FLOATFORMAT_CHAR_BIT 8
00078 
00079 /* floatformats for IEEE single and double, big and little endian.  */
00080 const struct floatformat floatformat_ieee_single_big =
00081 {
00082   floatformat_big, 32, 0, 1, 8, 127, 255, 9, 23,
00083   floatformat_intbit_no,
00084   "floatformat_ieee_single_big",
00085   floatformat_always_valid
00086 };
00087 const struct floatformat floatformat_ieee_single_little =
00088 {
00089   floatformat_little, 32, 0, 1, 8, 127, 255, 9, 23,
00090   floatformat_intbit_no,
00091   "floatformat_ieee_single_little",
00092   floatformat_always_valid
00093 };
00094 const struct floatformat floatformat_ieee_double_big =
00095 {
00096   floatformat_big, 64, 0, 1, 11, 1023, 2047, 12, 52,
00097   floatformat_intbit_no,
00098   "floatformat_ieee_double_big",
00099   floatformat_always_valid
00100 };
00101 const struct floatformat floatformat_ieee_double_little =
00102 {
00103   floatformat_little, 64, 0, 1, 11, 1023, 2047, 12, 52,
00104   floatformat_intbit_no,
00105   "floatformat_ieee_double_little",
00106   floatformat_always_valid
00107 };
00108 
00109 /* floatformat for IEEE double, little endian byte order, with big endian word
00110    ordering, as on the ARM.  */
00111 
00112 const struct floatformat floatformat_ieee_double_littlebyte_bigword =
00113 {
00114   floatformat_littlebyte_bigword, 64, 0, 1, 11, 1023, 2047, 12, 52,
00115   floatformat_intbit_no,
00116   "floatformat_ieee_double_littlebyte_bigword",
00117   floatformat_always_valid
00118 };
00119 
00120 /* floatformat for VAX.  Not quite IEEE, but close enough.  */
00121 
00122 const struct floatformat floatformat_vax_f =
00123 {
00124   floatformat_vax, 32, 0, 1, 8, 129, 0, 9, 23,
00125   floatformat_intbit_no,
00126   "floatformat_vax_f",
00127   floatformat_always_valid
00128 };
00129 const struct floatformat floatformat_vax_d =
00130 {
00131   floatformat_vax, 64, 0, 1, 8, 129, 0, 9, 55,
00132   floatformat_intbit_no,
00133   "floatformat_vax_d",
00134   floatformat_always_valid
00135 };
00136 const struct floatformat floatformat_vax_g =
00137 {
00138   floatformat_vax, 64, 0, 1, 11, 1025, 0, 12, 52,
00139   floatformat_intbit_no,
00140   "floatformat_vax_g",
00141   floatformat_always_valid
00142 };
00143 
00144 static int floatformat_i387_ext_is_valid (const struct floatformat *fmt,
00145                                      const void *from);
00146 
00147 static int
00148 floatformat_i387_ext_is_valid (const struct floatformat *fmt, const void *from)
00149 {
00150   /* In the i387 double-extended format, if the exponent is all ones,
00151      then the integer bit must be set.  If the exponent is neither 0
00152      nor ~0, the intbit must also be set.  Only if the exponent is
00153      zero can it be zero, and then it must be zero.  */
00154   unsigned long exponent, int_bit;
00155   const unsigned char *ufrom = (const unsigned char *) from;
00156 
00157   exponent = get_field (ufrom, fmt->byteorder, fmt->totalsize,
00158                      fmt->exp_start, fmt->exp_len);
00159   int_bit = get_field (ufrom, fmt->byteorder, fmt->totalsize,
00160                      fmt->man_start, 1);
00161 
00162   if ((exponent == 0) != (int_bit == 0))
00163     return 0;
00164   else
00165     return 1;
00166 }
00167 
00168 const struct floatformat floatformat_i387_ext =
00169 {
00170   floatformat_little, 80, 0, 1, 15, 0x3fff, 0x7fff, 16, 64,
00171   floatformat_intbit_yes,
00172   "floatformat_i387_ext",
00173   floatformat_i387_ext_is_valid
00174 };
00175 const struct floatformat floatformat_m68881_ext =
00176 {
00177   /* Note that the bits from 16 to 31 are unused.  */
00178   floatformat_big, 96, 0, 1, 15, 0x3fff, 0x7fff, 32, 64,
00179   floatformat_intbit_yes,
00180   "floatformat_m68881_ext",
00181   floatformat_always_valid
00182 };
00183 const struct floatformat floatformat_i960_ext =
00184 {
00185   /* Note that the bits from 0 to 15 are unused.  */
00186   floatformat_little, 96, 16, 17, 15, 0x3fff, 0x7fff, 32, 64,
00187   floatformat_intbit_yes,
00188   "floatformat_i960_ext",
00189   floatformat_always_valid
00190 };
00191 const struct floatformat floatformat_m88110_ext =
00192 {
00193   floatformat_big, 80, 0, 1, 15, 0x3fff, 0x7fff, 16, 64,
00194   floatformat_intbit_yes,
00195   "floatformat_m88110_ext",
00196   floatformat_always_valid
00197 };
00198 const struct floatformat floatformat_m88110_harris_ext =
00199 {
00200   /* Harris uses raw format 128 bytes long, but the number is just an ieee
00201      double, and the last 64 bits are wasted. */
00202   floatformat_big,128, 0, 1, 11,  0x3ff,  0x7ff, 12, 52,
00203   floatformat_intbit_no,
00204   "floatformat_m88110_ext_harris",
00205   floatformat_always_valid
00206 };
00207 const struct floatformat floatformat_arm_ext_big =
00208 {
00209   /* Bits 1 to 16 are unused.  */
00210   floatformat_big, 96, 0, 17, 15, 0x3fff, 0x7fff, 32, 64,
00211   floatformat_intbit_yes,
00212   "floatformat_arm_ext_big",
00213   floatformat_always_valid
00214 };
00215 const struct floatformat floatformat_arm_ext_littlebyte_bigword =
00216 {
00217   /* Bits 1 to 16 are unused.  */
00218   floatformat_littlebyte_bigword, 96, 0, 17, 15, 0x3fff, 0x7fff, 32, 64,
00219   floatformat_intbit_yes,
00220   "floatformat_arm_ext_littlebyte_bigword",
00221   floatformat_always_valid
00222 };
00223 const struct floatformat floatformat_ia64_spill_big =
00224 {
00225   floatformat_big, 128, 0, 1, 17, 65535, 0x1ffff, 18, 64,
00226   floatformat_intbit_yes,
00227   "floatformat_ia64_spill_big",
00228   floatformat_always_valid
00229 };
00230 const struct floatformat floatformat_ia64_spill_little =
00231 {
00232   floatformat_little, 128, 0, 1, 17, 65535, 0x1ffff, 18, 64,
00233   floatformat_intbit_yes,
00234   "floatformat_ia64_spill_little",
00235   floatformat_always_valid
00236 };
00237 const struct floatformat floatformat_ia64_quad_big =
00238 {
00239   floatformat_big, 128, 0, 1, 15, 16383, 0x7fff, 16, 112,
00240   floatformat_intbit_no,
00241   "floatformat_ia64_quad_big",
00242   floatformat_always_valid
00243 };
00244 const struct floatformat floatformat_ia64_quad_little =
00245 {
00246   floatformat_little, 128, 0, 1, 15, 16383, 0x7fff, 16, 112,
00247   floatformat_intbit_no,
00248   "floatformat_ia64_quad_little",
00249   floatformat_always_valid
00250 };
00251 
00252 
00253 #ifndef min
00254 #define min(a, b) ((a) < (b) ? (a) : (b))
00255 #endif
00256 
00257 /* Extract a field which starts at START and is LEN bits long.  DATA and
00258    TOTAL_LEN are the thing we are extracting it from, in byteorder ORDER.  */
00259 static unsigned long
00260 get_field (const unsigned char *data, enum floatformat_byteorders order,
00261            unsigned int total_len, unsigned int start, unsigned int len)
00262 {
00263   unsigned long result = 0;
00264   unsigned int cur_byte;
00265   int lo_bit, hi_bit, cur_bitshift = 0;
00266   int nextbyte = (order == floatformat_little) ? 1 : -1;
00267 
00268   /* Start is in big-endian bit order!  Fix that first.  */
00269   start = total_len - (start + len);
00270 
00271   /* Start at the least significant part of the field.  */
00272   if (order == floatformat_little)
00273     cur_byte = start / FLOATFORMAT_CHAR_BIT;
00274   else
00275     cur_byte = (total_len - start - 1) / FLOATFORMAT_CHAR_BIT;
00276 
00277   lo_bit = start % FLOATFORMAT_CHAR_BIT;
00278   hi_bit = min (lo_bit + len, FLOATFORMAT_CHAR_BIT);
00279   
00280   do
00281     {
00282       unsigned int shifted = *(data + cur_byte) >> lo_bit;
00283       unsigned int bits = hi_bit - lo_bit;
00284       unsigned int mask = (1 << bits) - 1;
00285       result |= (shifted & mask) << cur_bitshift;
00286       len -= bits;
00287       cur_bitshift += bits;
00288       cur_byte += nextbyte;
00289       lo_bit = 0;
00290       hi_bit = min (len, FLOATFORMAT_CHAR_BIT);
00291     }
00292   while (len != 0);
00293 
00294   return result;
00295 }
00296   
00297 /* Convert from FMT to a double.
00298    FROM is the address of the extended float.
00299    Store the double in *TO.  */
00300 
00301 void
00302 floatformat_to_double (const struct floatformat *fmt,
00303                        const void *from, double *to)
00304 {
00305   const unsigned char *ufrom = (const unsigned char *) from;
00306   double dto;
00307   long exponent;
00308   unsigned long mant;
00309   unsigned int mant_bits, mant_off;
00310   int mant_bits_left;
00311   int special_exponent;            /* It's a NaN, denorm or zero */
00312 
00313   exponent = get_field (ufrom, fmt->byteorder, fmt->totalsize,
00314                      fmt->exp_start, fmt->exp_len);
00315 
00316   /* If the exponent indicates a NaN, we don't have information to
00317      decide what to do.  So we handle it like IEEE, except that we
00318      don't try to preserve the type of NaN.  FIXME.  */
00319   if ((unsigned long) exponent == fmt->exp_nan)
00320     {
00321       int nan;
00322 
00323       mant_off = fmt->man_start;
00324       mant_bits_left = fmt->man_len;
00325       nan = 0;
00326       while (mant_bits_left > 0)
00327        {
00328          mant_bits = min (mant_bits_left, 32);
00329 
00330          if (get_field (ufrom, fmt->byteorder, fmt->totalsize,
00331                       mant_off, mant_bits) != 0)
00332            {
00333              /* This is a NaN.  */
00334              nan = 1;
00335              break;
00336            }
00337 
00338          mant_off += mant_bits;
00339          mant_bits_left -= mant_bits;
00340        }
00341 
00342       /* On certain systems (such as GNU/Linux), the use of the
00343         INFINITY macro below may generate a warning that can not be
00344         silenced due to a bug in GCC (PR preprocessor/11931).  The
00345         preprocessor fails to recognise the __extension__ keyword in
00346         conjunction with the GNU/C99 extension for hexadecimal
00347         floating point constants and will issue a warning when
00348         compiling with -pedantic.  */
00349       if (nan)
00350        dto = NAN;
00351       else
00352        dto = INFINITY;
00353 
00354       if (get_field (ufrom, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1))
00355        dto = -dto;
00356 
00357       *to = dto;
00358 
00359       return;
00360     }
00361 
00362   mant_bits_left = fmt->man_len;
00363   mant_off = fmt->man_start;
00364   dto = 0.0;
00365 
00366   special_exponent = exponent == 0 || (unsigned long) exponent == fmt->exp_nan;
00367 
00368   /* Don't bias zero's, denorms or NaNs.  */
00369   if (!special_exponent)
00370     exponent -= fmt->exp_bias;
00371 
00372   /* Build the result algebraically.  Might go infinite, underflow, etc;
00373      who cares. */
00374 
00375   /* If this format uses a hidden bit, explicitly add it in now.  Otherwise,
00376      increment the exponent by one to account for the integer bit.  */
00377 
00378   if (!special_exponent)
00379     {
00380       if (fmt->intbit == floatformat_intbit_no)
00381        dto = ldexp (1.0, exponent);
00382       else
00383        exponent++;
00384     }
00385 
00386   while (mant_bits_left > 0)
00387     {
00388       mant_bits = min (mant_bits_left, 32);
00389 
00390       mant = get_field (ufrom, fmt->byteorder, fmt->totalsize,
00391                       mant_off, mant_bits);
00392 
00393       /* Handle denormalized numbers.  FIXME: What should we do for
00394         non-IEEE formats?  */
00395       if (special_exponent && exponent == 0 && mant != 0)
00396        dto += ldexp ((double)mant,
00397                     (- fmt->exp_bias
00398                      - mant_bits
00399                      - (mant_off - fmt->man_start)
00400                      + 1));
00401       else
00402        dto += ldexp ((double)mant, exponent - mant_bits);
00403       if (exponent != 0)
00404        exponent -= mant_bits;
00405       mant_off += mant_bits;
00406       mant_bits_left -= mant_bits;
00407     }
00408 
00409   /* Negate it if negative.  */
00410   if (get_field (ufrom, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1))
00411     dto = -dto;
00412   *to = dto;
00413 }
00414 
00415 static void put_field (unsigned char *, enum floatformat_byteorders,
00416                        unsigned int,
00417                        unsigned int,
00418                        unsigned int,
00419                        unsigned long);
00420 
00421 /* Set a field which starts at START and is LEN bits long.  DATA and
00422    TOTAL_LEN are the thing we are extracting it from, in byteorder ORDER.  */
00423 static void
00424 put_field (unsigned char *data, enum floatformat_byteorders order,
00425            unsigned int total_len, unsigned int start, unsigned int len,
00426            unsigned long stuff_to_put)
00427 {
00428   unsigned int cur_byte;
00429   int lo_bit, hi_bit;
00430   int nextbyte = (order == floatformat_little) ? 1 : -1;
00431 
00432   /* Start is in big-endian bit order!  Fix that first.  */
00433   start = total_len - (start + len);
00434 
00435   /* Start at the least significant part of the field.  */
00436   if (order == floatformat_little)
00437     cur_byte = start / FLOATFORMAT_CHAR_BIT;
00438   else
00439     cur_byte = (total_len - start - 1) / FLOATFORMAT_CHAR_BIT;
00440 
00441   lo_bit = start % FLOATFORMAT_CHAR_BIT;
00442   hi_bit = min (lo_bit + len, FLOATFORMAT_CHAR_BIT);
00443   
00444   do
00445     {
00446       unsigned char *byte_ptr = data + cur_byte;
00447       unsigned int bits = hi_bit - lo_bit;
00448       unsigned int mask = ((1 << bits) - 1) << lo_bit;
00449       *byte_ptr = (*byte_ptr & ~mask) | ((stuff_to_put << lo_bit) & mask);
00450       stuff_to_put >>= bits;
00451       len -= bits;
00452       cur_byte += nextbyte;
00453       lo_bit = 0;
00454       hi_bit = min (len, FLOATFORMAT_CHAR_BIT);
00455     }
00456   while (len != 0);
00457 }
00458 
00459 /* The converse: convert the double *FROM to an extended float
00460    and store where TO points.  Neither FROM nor TO have any alignment
00461    restrictions.  */
00462 
00463 void
00464 floatformat_from_double (const struct floatformat *fmt,
00465                          const double *from, void *to)
00466 {
00467   double dfrom;
00468   int exponent;
00469   double mant;
00470   unsigned int mant_bits, mant_off;
00471   int mant_bits_left;
00472   unsigned char *uto = (unsigned char *) to;
00473 
00474   dfrom = *from;
00475   memset (uto, 0, fmt->totalsize / FLOATFORMAT_CHAR_BIT);
00476 
00477   /* If negative, set the sign bit.  */
00478   if (dfrom < 0)
00479     {
00480       put_field (uto, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1, 1);
00481       dfrom = -dfrom;
00482     }
00483 
00484   if (dfrom == 0)
00485     {
00486       /* 0.0.  */
00487       return;
00488     }
00489 
00490   if (dfrom != dfrom)
00491     {
00492       /* NaN.  */
00493       put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start,
00494                fmt->exp_len, fmt->exp_nan);
00495       /* Be sure it's not infinity, but NaN value is irrelevant.  */
00496       put_field (uto, fmt->byteorder, fmt->totalsize, fmt->man_start,
00497                32, 1);
00498       return;
00499     }
00500 
00501   if (dfrom + dfrom == dfrom)
00502     {
00503       /* This can only happen for an infinite value (or zero, which we
00504         already handled above).  */
00505       put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start,
00506                fmt->exp_len, fmt->exp_nan);
00507       return;
00508     }
00509 
00510   mant = frexp (dfrom, &exponent);
00511   if (exponent + fmt->exp_bias - 1 > 0)
00512     put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start,
00513               fmt->exp_len, exponent + fmt->exp_bias - 1);
00514   else
00515     {
00516       /* Handle a denormalized number.  FIXME: What should we do for
00517         non-IEEE formats?  */
00518       put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start,
00519                fmt->exp_len, 0);
00520       mant = ldexp (mant, exponent + fmt->exp_bias - 1);
00521     }
00522 
00523   mant_bits_left = fmt->man_len;
00524   mant_off = fmt->man_start;
00525   while (mant_bits_left > 0)
00526     {
00527       unsigned long mant_long;
00528       mant_bits = mant_bits_left < 32 ? mant_bits_left : 32;
00529 
00530       mant *= 4294967296.0;
00531       mant_long = (unsigned long)mant;
00532       mant -= mant_long;
00533 
00534       /* If the integer bit is implicit, and we are not creating a
00535         denormalized number, then we need to discard it.  */
00536       if ((unsigned int) mant_bits_left == fmt->man_len
00537          && fmt->intbit == floatformat_intbit_no
00538          && exponent + fmt->exp_bias - 1 > 0)
00539        {
00540          mant_long &= 0x7fffffff;
00541          mant_bits -= 1;
00542        }
00543       else if (mant_bits < 32)
00544        {
00545          /* The bits we want are in the most significant MANT_BITS bits of
00546             mant_long.  Move them to the least significant.  */
00547          mant_long >>= 32 - mant_bits;
00548        }
00549 
00550       put_field (uto, fmt->byteorder, fmt->totalsize,
00551                mant_off, mant_bits, mant_long);
00552       mant_off += mant_bits;
00553       mant_bits_left -= mant_bits;
00554     }
00555 }
00556 
00557 /* Return non-zero iff the data at FROM is a valid number in format FMT.  */
00558 
00559 int
00560 floatformat_is_valid (const struct floatformat *fmt, const void *from)
00561 {
00562   return fmt->is_valid (fmt, from);
00563 }
00564 
00565 
00566 #ifdef IEEE_DEBUG
00567 
00568 #include <stdio.h>
00569 
00570 /* This is to be run on a host which uses IEEE floating point.  */
00571 
00572 void
00573 ieee_test (double n)
00574 {
00575   double result;
00576 
00577   floatformat_to_double (&floatformat_ieee_double_little, &n, &result);
00578   if ((n != result && (! isnan (n) || ! isnan (result)))
00579       || (n < 0 && result >= 0)
00580       || (n >= 0 && result < 0))
00581     printf ("Differ(to): %.20g -> %.20g\n", n, result);
00582 
00583   floatformat_from_double (&floatformat_ieee_double_little, &n, &result);
00584   if ((n != result && (! isnan (n) || ! isnan (result)))
00585       || (n < 0 && result >= 0)
00586       || (n >= 0 && result < 0))
00587     printf ("Differ(from): %.20g -> %.20g\n", n, result);
00588 
00589 #if 0
00590   {
00591     char exten[16];
00592 
00593     floatformat_from_double (&floatformat_m68881_ext, &n, exten);
00594     floatformat_to_double (&floatformat_m68881_ext, exten, &result);
00595     if (n != result)
00596       printf ("Differ(to+from): %.20g -> %.20g\n", n, result);
00597   }
00598 #endif
00599 
00600 #if IEEE_DEBUG > 1
00601   /* This is to be run on a host which uses 68881 format.  */
00602   {
00603     long double ex = *(long double *)exten;
00604     if (ex != n)
00605       printf ("Differ(from vs. extended): %.20g\n", n);
00606   }
00607 #endif
00608 }
00609 
00610 int
00611 main (void)
00612 {
00613   ieee_test (0.0);
00614   ieee_test (0.5);
00615   ieee_test (256.0);
00616   ieee_test (0.12345);
00617   ieee_test (234235.78907234);
00618   ieee_test (-512.0);
00619   ieee_test (-0.004321);
00620   ieee_test (1.2E-70);
00621   ieee_test (1.2E-316);
00622   ieee_test (4.9406564584124654E-324);
00623   ieee_test (- 4.9406564584124654E-324);
00624   ieee_test (- 0.0);
00625   ieee_test (- INFINITY);
00626   ieee_test (- NAN);
00627   ieee_test (INFINITY);
00628   ieee_test (NAN);
00629   return 0;
00630 }
00631 #endif