OSDN Git Service

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