source: trunk/third/gcc/libiberty/floatformat.c @ 18477

Revision 18477, 13.2 KB checked in by ghudson, 21 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r18476, which included commits to RCS files with non-trunk default branches.
Line 
1/* IEEE floating point support routines, for GDB, the GNU Debugger.
2   Copyright (C) 1991, 1994, 1999, 2000 Free Software Foundation, Inc.
3
4This file is part of GDB.
5
6This program is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2 of the License, or
9(at your option) any later version.
10
11This program is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with this program; if not, write to the Free Software
18Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
19
20#include "floatformat.h"
21#include <math.h>               /* ldexp */
22#ifdef __STDC__
23#include <stddef.h>
24extern void *memcpy (void *s1, const void *s2, size_t n);
25extern void *memset (void *s, int c, size_t n);
26#else
27extern char *memcpy ();
28extern char *memset ();
29#endif
30
31/* The odds that CHAR_BIT will be anything but 8 are low enough that I'm not
32   going to bother with trying to muck around with whether it is defined in
33   a system header, what we do if not, etc.  */
34#define FLOATFORMAT_CHAR_BIT 8
35
36/* floatformats for IEEE single and double, big and little endian.  */
37const struct floatformat floatformat_ieee_single_big =
38{
39  floatformat_big, 32, 0, 1, 8, 127, 255, 9, 23,
40  floatformat_intbit_no,
41  "floatformat_ieee_single_big"
42};
43const struct floatformat floatformat_ieee_single_little =
44{
45  floatformat_little, 32, 0, 1, 8, 127, 255, 9, 23,
46  floatformat_intbit_no,
47  "floatformat_ieee_single_little"
48};
49const struct floatformat floatformat_ieee_double_big =
50{
51  floatformat_big, 64, 0, 1, 11, 1023, 2047, 12, 52,
52  floatformat_intbit_no,
53  "floatformat_ieee_double_big"
54};
55const struct floatformat floatformat_ieee_double_little =
56{
57  floatformat_little, 64, 0, 1, 11, 1023, 2047, 12, 52,
58  floatformat_intbit_no,
59  "floatformat_ieee_double_little"
60};
61
62/* floatformat for IEEE double, little endian byte order, with big endian word
63   ordering, as on the ARM.  */
64
65const struct floatformat floatformat_ieee_double_littlebyte_bigword =
66{
67  floatformat_littlebyte_bigword, 64, 0, 1, 11, 1023, 2047, 12, 52,
68  floatformat_intbit_no,
69  "floatformat_ieee_double_littlebyte_bigword"
70};
71
72const struct floatformat floatformat_i387_ext =
73{
74  floatformat_little, 80, 0, 1, 15, 0x3fff, 0x7fff, 16, 64,
75  floatformat_intbit_yes,
76  "floatformat_i387_ext"
77};
78const struct floatformat floatformat_m68881_ext =
79{
80  /* Note that the bits from 16 to 31 are unused.  */
81  floatformat_big, 96, 0, 1, 15, 0x3fff, 0x7fff, 32, 64,
82  floatformat_intbit_yes,
83  "floatformat_m68881_ext"
84};
85const struct floatformat floatformat_i960_ext =
86{
87  /* Note that the bits from 0 to 15 are unused.  */
88  floatformat_little, 96, 16, 17, 15, 0x3fff, 0x7fff, 32, 64,
89  floatformat_intbit_yes,
90  "floatformat_i960_ext"
91};
92const struct floatformat floatformat_m88110_ext =
93{
94  floatformat_big, 80, 0, 1, 15, 0x3fff, 0x7fff, 16, 64,
95  floatformat_intbit_yes,
96  "floatformat_m88110_ext"
97};
98const struct floatformat floatformat_m88110_harris_ext =
99{
100  /* Harris uses raw format 128 bytes long, but the number is just an ieee
101     double, and the last 64 bits are wasted. */
102  floatformat_big,128, 0, 1, 11,  0x3ff,  0x7ff, 12, 52,
103  floatformat_intbit_no,
104  "floatformat_m88110_ext_harris"
105};
106const struct floatformat floatformat_arm_ext =
107{
108  /* Bits 1 to 16 are unused.  */
109  floatformat_big, 96, 0, 17, 15, 0x3fff, 0x7fff, 32, 64,
110  floatformat_intbit_yes,
111  "floatformat_arm_ext"
112};
113const struct floatformat floatformat_arm_ext_big =
114{
115  /* Bits 1 to 16 are unused.  */
116  floatformat_big, 96, 0, 17, 15, 0x3fff, 0x7fff, 32, 64,
117  floatformat_intbit_yes,
118  "floatformat_arm_ext_big"
119};
120const struct floatformat floatformat_arm_ext_littlebyte_bigword =
121{
122  /* Bits 1 to 16 are unused.  */
123  floatformat_littlebyte_bigword, 96, 0, 17, 15, 0x3fff, 0x7fff, 32, 64,
124  floatformat_intbit_yes,
125  "floatformat_arm_ext_littlebyte_bigword"
126};
127const struct floatformat floatformat_ia64_spill_big =
128{
129  floatformat_big, 128, 0, 1, 17, 65535, 0x1ffff, 18, 64,
130  floatformat_intbit_yes,
131  "floatformat_ia64_spill_big"
132};
133const struct floatformat floatformat_ia64_spill_little =
134{
135  floatformat_little, 128, 0, 1, 17, 65535, 0x1ffff, 18, 64,
136  floatformat_intbit_yes,
137  "floatformat_ia64_spill_little"
138};
139const struct floatformat floatformat_ia64_quad_big =
140{
141  floatformat_big, 128, 0, 1, 15, 16383, 0x7fff, 16, 112,
142  floatformat_intbit_no,
143  "floatformat_ia64_quad_big"
144};
145const struct floatformat floatformat_ia64_quad_little =
146{
147  floatformat_little, 128, 0, 1, 15, 16383, 0x7fff, 16, 112,
148  floatformat_intbit_no,
149  "floatformat_ia64_quad_little"
150};
151
152static unsigned long get_field PARAMS ((unsigned char *,
153                                        enum floatformat_byteorders,
154                                        unsigned int,
155                                        unsigned int,
156                                        unsigned int));
157
158/* Extract a field which starts at START and is LEN bytes long.  DATA and
159   TOTAL_LEN are the thing we are extracting it from, in byteorder ORDER.  */
160static unsigned long
161get_field (data, order, total_len, start, len)
162     unsigned char *data;
163     enum floatformat_byteorders order;
164     unsigned int total_len;
165     unsigned int start;
166     unsigned int len;
167{
168  unsigned long result;
169  unsigned int cur_byte;
170  int cur_bitshift;
171
172  /* Start at the least significant part of the field.  */
173  cur_byte = (start + len) / FLOATFORMAT_CHAR_BIT;
174  if (order == floatformat_little)
175    cur_byte = (total_len / FLOATFORMAT_CHAR_BIT) - cur_byte - 1;
176  cur_bitshift =
177    ((start + len) % FLOATFORMAT_CHAR_BIT) - FLOATFORMAT_CHAR_BIT;
178  result = *(data + cur_byte) >> (-cur_bitshift);
179  cur_bitshift += FLOATFORMAT_CHAR_BIT;
180  if (order == floatformat_little)
181    ++cur_byte;
182  else
183    --cur_byte;
184
185  /* Move towards the most significant part of the field.  */
186  while ((unsigned int) cur_bitshift < len)
187    {
188      if (len - cur_bitshift < FLOATFORMAT_CHAR_BIT)
189        /* This is the last byte; zero out the bits which are not part of
190           this field.  */
191        result |=
192          (*(data + cur_byte) & ((1 << (len - cur_bitshift)) - 1))
193            << cur_bitshift;
194      else
195        result |= *(data + cur_byte) << cur_bitshift;
196      cur_bitshift += FLOATFORMAT_CHAR_BIT;
197      if (order == floatformat_little)
198        ++cur_byte;
199      else
200        --cur_byte;
201    }
202  return result;
203}
204 
205#ifndef min
206#define min(a, b) ((a) < (b) ? (a) : (b))
207#endif
208
209/* Convert from FMT to a double.
210   FROM is the address of the extended float.
211   Store the double in *TO.  */
212
213void
214floatformat_to_double (fmt, from, to)
215     const struct floatformat *fmt;
216     char *from;
217     double *to;
218{
219  unsigned char *ufrom = (unsigned char *)from;
220  double dto;
221  long exponent;
222  unsigned long mant;
223  unsigned int mant_bits, mant_off;
224  int mant_bits_left;
225  int special_exponent;         /* It's a NaN, denorm or zero */
226
227  exponent = get_field (ufrom, fmt->byteorder, fmt->totalsize,
228                        fmt->exp_start, fmt->exp_len);
229  /* Note that if exponent indicates a NaN, we can't really do anything useful
230     (not knowing if the host has NaN's, or how to build one).  So it will
231     end up as an infinity or something close; that is OK.  */
232
233  mant_bits_left = fmt->man_len;
234  mant_off = fmt->man_start;
235  dto = 0.0;
236
237  special_exponent = exponent == 0 || (unsigned long) exponent == fmt->exp_nan;
238
239  /* Don't bias zero's, denorms or NaNs.  */
240  if (!special_exponent)
241    exponent -= fmt->exp_bias;
242
243  /* Build the result algebraically.  Might go infinite, underflow, etc;
244     who cares. */
245
246  /* If this format uses a hidden bit, explicitly add it in now.  Otherwise,
247     increment the exponent by one to account for the integer bit.  */
248
249  if (!special_exponent)
250    {
251      if (fmt->intbit == floatformat_intbit_no)
252        dto = ldexp (1.0, exponent);
253      else
254        exponent++;
255    }
256
257  while (mant_bits_left > 0)
258    {
259      mant_bits = min (mant_bits_left, 32);
260
261      mant = get_field (ufrom, fmt->byteorder, fmt->totalsize,
262                         mant_off, mant_bits);
263
264      dto += ldexp ((double)mant, exponent - mant_bits);
265      exponent -= mant_bits;
266      mant_off += mant_bits;
267      mant_bits_left -= mant_bits;
268    }
269
270  /* Negate it if negative.  */
271  if (get_field (ufrom, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1))
272    dto = -dto;
273  *to = dto;
274}
275
276static void put_field PARAMS ((unsigned char *, enum floatformat_byteorders,
277                               unsigned int,
278                               unsigned int,
279                               unsigned int,
280                               unsigned long));
281
282/* Set a field which starts at START and is LEN bytes long.  DATA and
283   TOTAL_LEN are the thing we are extracting it from, in byteorder ORDER.  */
284static void
285put_field (data, order, total_len, start, len, stuff_to_put)
286     unsigned char *data;
287     enum floatformat_byteorders order;
288     unsigned int total_len;
289     unsigned int start;
290     unsigned int len;
291     unsigned long stuff_to_put;
292{
293  unsigned int cur_byte;
294  int cur_bitshift;
295
296  /* Start at the least significant part of the field.  */
297  cur_byte = (start + len) / FLOATFORMAT_CHAR_BIT;
298  if (order == floatformat_little)
299    cur_byte = (total_len / FLOATFORMAT_CHAR_BIT) - cur_byte - 1;
300  cur_bitshift =
301    ((start + len) % FLOATFORMAT_CHAR_BIT) - FLOATFORMAT_CHAR_BIT;
302  *(data + cur_byte) &=
303    ~(((1 << ((start + len) % FLOATFORMAT_CHAR_BIT)) - 1) << (-cur_bitshift));
304  *(data + cur_byte) |=
305    (stuff_to_put & ((1 << FLOATFORMAT_CHAR_BIT) - 1)) << (-cur_bitshift);
306  cur_bitshift += FLOATFORMAT_CHAR_BIT;
307  if (order == floatformat_little)
308    ++cur_byte;
309  else
310    --cur_byte;
311
312  /* Move towards the most significant part of the field.  */
313  while ((unsigned int) cur_bitshift < len)
314    {
315      if (len - cur_bitshift < FLOATFORMAT_CHAR_BIT)
316        {
317          /* This is the last byte.  */
318          *(data + cur_byte) &=
319            ~((1 << (len - cur_bitshift)) - 1);
320          *(data + cur_byte) |= (stuff_to_put >> cur_bitshift);
321        }
322      else
323        *(data + cur_byte) = ((stuff_to_put >> cur_bitshift)
324                              & ((1 << FLOATFORMAT_CHAR_BIT) - 1));
325      cur_bitshift += FLOATFORMAT_CHAR_BIT;
326      if (order == floatformat_little)
327        ++cur_byte;
328      else
329        --cur_byte;
330    }
331}
332
333/* The converse: convert the double *FROM to an extended float
334   and store where TO points.  Neither FROM nor TO have any alignment
335   restrictions.  */
336
337void
338floatformat_from_double (fmt, from, to)
339     const struct floatformat *fmt;
340     double *from;
341     char *to;
342{
343  double dfrom;
344  int exponent;
345  double mant;
346  unsigned int mant_bits, mant_off;
347  int mant_bits_left;
348  unsigned char *uto = (unsigned char *)to;
349
350  memcpy (&dfrom, from, sizeof (dfrom));
351  memset (uto, 0, fmt->totalsize / FLOATFORMAT_CHAR_BIT);
352  if (dfrom == 0)
353    return;                     /* Result is zero */
354  if (dfrom != dfrom)
355    {
356      /* From is NaN */
357      put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start,
358                 fmt->exp_len, fmt->exp_nan);
359      /* Be sure it's not infinity, but NaN value is irrel */
360      put_field (uto, fmt->byteorder, fmt->totalsize, fmt->man_start,
361                 32, 1);
362      return;
363    }
364
365  /* If negative, set the sign bit.  */
366  if (dfrom < 0)
367    {
368      put_field (uto, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1, 1);
369      dfrom = -dfrom;
370    }
371
372  /* How to tell an infinity from an ordinary number?  FIXME-someday */
373
374  mant = frexp (dfrom, &exponent);
375  put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start, fmt->exp_len,
376             exponent + fmt->exp_bias - 1);
377
378  mant_bits_left = fmt->man_len;
379  mant_off = fmt->man_start;
380  while (mant_bits_left > 0)
381    {
382      unsigned long mant_long;
383      mant_bits = mant_bits_left < 32 ? mant_bits_left : 32;
384
385      mant *= 4294967296.0;
386      mant_long = (unsigned long)mant;
387      mant -= mant_long;
388
389      /* If the integer bit is implicit, then we need to discard it.
390         If we are discarding a zero, we should be (but are not) creating
391         a denormalized number which means adjusting the exponent
392         (I think).  */
393      if ((unsigned int) mant_bits_left == fmt->man_len
394          && fmt->intbit == floatformat_intbit_no)
395        {
396          mant_long &= 0x7fffffff;
397          mant_bits -= 1;
398        }
399      else if (mant_bits < 32)
400        {
401          /* The bits we want are in the most significant MANT_BITS bits of
402             mant_long.  Move them to the least significant.  */
403          mant_long >>= 32 - mant_bits;
404        }
405
406      put_field (uto, fmt->byteorder, fmt->totalsize,
407                 mant_off, mant_bits, mant_long);
408      mant_off += mant_bits;
409      mant_bits_left -= mant_bits;
410    }
411}
412
413
414#ifdef IEEE_DEBUG
415
416/* This is to be run on a host which uses IEEE floating point.  */
417
418void
419ieee_test (n)
420     double n;
421{
422  double result;
423  char exten[16];
424
425  floatformat_to_double (&floatformat_ieee_double_big, &n, &result);
426  if (n != result)
427    printf ("Differ(to): %.20g -> %.20g\n", n, result);
428  floatformat_from_double (&floatformat_ieee_double_big, &n, &result);
429  if (n != result)
430    printf ("Differ(from): %.20g -> %.20g\n", n, result);
431
432  floatformat_from_double (&floatformat_m68881_ext, &n, exten);
433  floatformat_to_double (&floatformat_m68881_ext, exten, &result);
434  if (n != result)
435    printf ("Differ(to+from): %.20g -> %.20g\n", n, result);
436
437#if IEEE_DEBUG > 1
438  /* This is to be run on a host which uses 68881 format.  */
439  {
440    long double ex = *(long double *)exten;
441    if (ex != n)
442      printf ("Differ(from vs. extended): %.20g\n", n);
443  }
444#endif
445}
446
447int
448main ()
449{
450  ieee_test (0.5);
451  ieee_test (256.0);
452  ieee_test (0.12345);
453  ieee_test (234235.78907234);
454  ieee_test (-512.0);
455  ieee_test (-0.004321);
456  return 0;
457}
458#endif
Note: See TracBrowser for help on using the repository browser.