source: branches/libc-0.6/src/binutils/libiberty/floatformat.c

Last change on this file was 610, checked in by bird, 22 years ago

This commit was generated by cvs2svn to compensate for changes in r609,
which included commits to RCS files with non-trunk default branches.

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