source: trunk/src/gcc/libiberty/floatformat.c@ 1392

Last change on this file since 1392 was 1392, checked in by bird, 21 years ago

This commit was generated by cvs2svn to compensate for changes in r1391,
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.0 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 "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_big =
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_big"
112};
113const struct floatformat floatformat_arm_ext_littlebyte_bigword =
114{
115 /* Bits 1 to 16 are unused. */
116 floatformat_littlebyte_bigword, 96, 0, 17, 15, 0x3fff, 0x7fff, 32, 64,
117 floatformat_intbit_yes,
118 "floatformat_arm_ext_littlebyte_bigword"
119};
120const struct floatformat floatformat_ia64_spill_big =
121{
122 floatformat_big, 128, 0, 1, 17, 65535, 0x1ffff, 18, 64,
123 floatformat_intbit_yes,
124 "floatformat_ia64_spill_big"
125};
126const struct floatformat floatformat_ia64_spill_little =
127{
128 floatformat_little, 128, 0, 1, 17, 65535, 0x1ffff, 18, 64,
129 floatformat_intbit_yes,
130 "floatformat_ia64_spill_little"
131};
132const struct floatformat floatformat_ia64_quad_big =
133{
134 floatformat_big, 128, 0, 1, 15, 16383, 0x7fff, 16, 112,
135 floatformat_intbit_no,
136 "floatformat_ia64_quad_big"
137};
138const struct floatformat floatformat_ia64_quad_little =
139{
140 floatformat_little, 128, 0, 1, 15, 16383, 0x7fff, 16, 112,
141 floatformat_intbit_no,
142 "floatformat_ia64_quad_little"
143};
144
145
146static unsigned long get_field PARAMS ((unsigned char *,
147 enum floatformat_byteorders,
148 unsigned int,
149 unsigned int,
150 unsigned int));
151
152/* Extract a field which starts at START and is LEN bytes long. DATA and
153 TOTAL_LEN are the thing we are extracting it from, in byteorder ORDER. */
154static unsigned long
155get_field (data, order, total_len, start, len)
156 unsigned char *data;
157 enum floatformat_byteorders order;
158 unsigned int total_len;
159 unsigned int start;
160 unsigned int len;
161{
162 unsigned long result;
163 unsigned int cur_byte;
164 int cur_bitshift;
165
166 /* Start at the least significant part of the field. */
167 cur_byte = (start + len) / FLOATFORMAT_CHAR_BIT;
168 if (order == floatformat_little)
169 cur_byte = (total_len / FLOATFORMAT_CHAR_BIT) - cur_byte - 1;
170 cur_bitshift =
171 ((start + len) % FLOATFORMAT_CHAR_BIT) - FLOATFORMAT_CHAR_BIT;
172 result = *(data + cur_byte) >> (-cur_bitshift);
173 cur_bitshift += FLOATFORMAT_CHAR_BIT;
174 if (order == floatformat_little)
175 ++cur_byte;
176 else
177 --cur_byte;
178
179 /* Move towards the most significant part of the field. */
180 while ((unsigned int) cur_bitshift < len)
181 {
182 if (len - cur_bitshift < FLOATFORMAT_CHAR_BIT)
183 /* This is the last byte; zero out the bits which are not part of
184 this field. */
185 result |=
186 (*(data + cur_byte) & ((1 << (len - cur_bitshift)) - 1))
187 << cur_bitshift;
188 else
189 result |= *(data + cur_byte) << cur_bitshift;
190 cur_bitshift += FLOATFORMAT_CHAR_BIT;
191 if (order == floatformat_little)
192 ++cur_byte;
193 else
194 --cur_byte;
195 }
196 return result;
197}
198
199#ifndef min
200#define min(a, b) ((a) < (b) ? (a) : (b))
201#endif
202
203/* Convert from FMT to a double.
204 FROM is the address of the extended float.
205 Store the double in *TO. */
206
207void
208floatformat_to_double (fmt, from, to)
209 const struct floatformat *fmt;
210 char *from;
211 double *to;
212{
213 unsigned char *ufrom = (unsigned char *)from;
214 double dto;
215 long exponent;
216 unsigned long mant;
217 unsigned int mant_bits, mant_off;
218 int mant_bits_left;
219 int special_exponent; /* It's a NaN, denorm or zero */
220
221 exponent = get_field (ufrom, fmt->byteorder, fmt->totalsize,
222 fmt->exp_start, fmt->exp_len);
223 /* Note that if exponent indicates a NaN, we can't really do anything useful
224 (not knowing if the host has NaN's, or how to build one). So it will
225 end up as an infinity or something close; that is OK. */
226
227 mant_bits_left = fmt->man_len;
228 mant_off = fmt->man_start;
229 dto = 0.0;
230
231 special_exponent = exponent == 0 || (unsigned long) exponent == fmt->exp_nan;
232
233 /* Don't bias zero's, denorms or NaNs. */
234 if (!special_exponent)
235 exponent -= fmt->exp_bias;
236
237 /* Build the result algebraically. Might go infinite, underflow, etc;
238 who cares. */
239
240 /* If this format uses a hidden bit, explicitly add it in now. Otherwise,
241 increment the exponent by one to account for the integer bit. */
242
243 if (!special_exponent)
244 {
245 if (fmt->intbit == floatformat_intbit_no)
246 dto = ldexp (1.0, exponent);
247 else
248 exponent++;
249 }
250
251 while (mant_bits_left > 0)
252 {
253 mant_bits = min (mant_bits_left, 32);
254
255 mant = get_field (ufrom, fmt->byteorder, fmt->totalsize,
256 mant_off, mant_bits);
257
258 dto += ldexp ((double)mant, exponent - mant_bits);
259 exponent -= mant_bits;
260 mant_off += mant_bits;
261 mant_bits_left -= mant_bits;
262 }
263
264 /* Negate it if negative. */
265 if (get_field (ufrom, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1))
266 dto = -dto;
267 *to = dto;
268}
269
270
271static void put_field PARAMS ((unsigned char *, enum floatformat_byteorders,
272 unsigned int,
273 unsigned int,
274 unsigned int,
275 unsigned long));
276
277/* Set a field which starts at START and is LEN bytes long. DATA and
278 TOTAL_LEN are the thing we are extracting it from, in byteorder ORDER. */
279static void
280put_field (data, order, total_len, start, len, stuff_to_put)
281 unsigned char *data;
282 enum floatformat_byteorders order;
283 unsigned int total_len;
284 unsigned int start;
285 unsigned int len;
286 unsigned long stuff_to_put;
287{
288 unsigned int cur_byte;
289 int cur_bitshift;
290
291 /* Start at the least significant part of the field. */
292 cur_byte = (start + len) / FLOATFORMAT_CHAR_BIT;
293 if (order == floatformat_little)
294 cur_byte = (total_len / FLOATFORMAT_CHAR_BIT) - cur_byte - 1;
295 cur_bitshift =
296 ((start + len) % FLOATFORMAT_CHAR_BIT) - FLOATFORMAT_CHAR_BIT;
297 *(data + cur_byte) &=
298 ~(((1 << ((start + len) % FLOATFORMAT_CHAR_BIT)) - 1) << (-cur_bitshift));
299 *(data + cur_byte) |=
300 (stuff_to_put & ((1 << FLOATFORMAT_CHAR_BIT) - 1)) << (-cur_bitshift);
301 cur_bitshift += FLOATFORMAT_CHAR_BIT;
302 if (order == floatformat_little)
303 ++cur_byte;
304 else
305 --cur_byte;
306
307 /* Move towards the most significant part of the field. */
308 while ((unsigned int) cur_bitshift < len)
309 {
310 if (len - cur_bitshift < FLOATFORMAT_CHAR_BIT)
311 {
312 /* This is the last byte. */
313 *(data + cur_byte) &=
314 ~((1 << (len - cur_bitshift)) - 1);
315 *(data + cur_byte) |= (stuff_to_put >> cur_bitshift);
316 }
317 else
318 *(data + cur_byte) = ((stuff_to_put >> cur_bitshift)
319 & ((1 << FLOATFORMAT_CHAR_BIT) - 1));
320 cur_bitshift += FLOATFORMAT_CHAR_BIT;
321 if (order == floatformat_little)
322 ++cur_byte;
323 else
324 --cur_byte;
325 }
326}
327
328/* The converse: convert the double *FROM to an extended float
329 and store where TO points. Neither FROM nor TO have any alignment
330 restrictions. */
331
332void
333floatformat_from_double (fmt, from, to)
334 const struct floatformat *fmt;
335 double *from;
336 char *to;
337{
338 double dfrom;
339 int exponent;
340 double mant;
341 unsigned int mant_bits, mant_off;
342 int mant_bits_left;
343 unsigned char *uto = (unsigned char *)to;
344
345 memcpy (&dfrom, from, sizeof (dfrom));
346 memset (uto, 0, fmt->totalsize / FLOATFORMAT_CHAR_BIT);
347 if (dfrom == 0)
348 return; /* Result is zero */
349 if (dfrom != dfrom)
350 {
351 /* From is NaN */
352 put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start,
353 fmt->exp_len, fmt->exp_nan);
354 /* Be sure it's not infinity, but NaN value is irrel */
355 put_field (uto, fmt->byteorder, fmt->totalsize, fmt->man_start,
356 32, 1);
357 return;
358 }
359
360 /* If negative, set the sign bit. */
361 if (dfrom < 0)
362 {
363 put_field (uto, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1, 1);
364 dfrom = -dfrom;
365 }
366
367 /* How to tell an infinity from an ordinary number? FIXME-someday */
368
369 mant = frexp (dfrom, &exponent);
370 put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start, fmt->exp_len,
371 exponent + fmt->exp_bias - 1);
372
373 mant_bits_left = fmt->man_len;
374 mant_off = fmt->man_start;
375 while (mant_bits_left > 0)
376 {
377 unsigned long mant_long;
378 mant_bits = mant_bits_left < 32 ? mant_bits_left : 32;
379
380 mant *= 4294967296.0;
381 mant_long = (unsigned long)mant;
382 mant -= mant_long;
383
384 /* If the integer bit is implicit, then we need to discard it.
385 If we are discarding a zero, we should be (but are not) creating
386 a denormalized number which means adjusting the exponent
387 (I think). */
388 if ((unsigned int) mant_bits_left == fmt->man_len
389 && fmt->intbit == floatformat_intbit_no)
390 {
391 mant_long &= 0x7fffffff;
392 mant_bits -= 1;
393 }
394 else if (mant_bits < 32)
395 {
396 /* The bits we want are in the most significant MANT_BITS bits of
397 mant_long. Move them to the least significant. */
398 mant_long >>= 32 - mant_bits;
399 }
400
401 put_field (uto, fmt->byteorder, fmt->totalsize,
402 mant_off, mant_bits, mant_long);
403 mant_off += mant_bits;
404 mant_bits_left -= mant_bits;
405 }
406}
407
408
409#ifdef IEEE_DEBUG
410
411/* This is to be run on a host which uses IEEE floating point. */
412
413void
414ieee_test (n)
415 double n;
416{
417 double result;
418 char exten[16];
419
420 floatformat_to_double (&floatformat_ieee_double_big, &n, &result);
421 if (n != result)
422 printf ("Differ(to): %.20g -> %.20g\n", n, result);
423 floatformat_from_double (&floatformat_ieee_double_big, &n, &result);
424 if (n != result)
425 printf ("Differ(from): %.20g -> %.20g\n", n, result);
426
427 floatformat_from_double (&floatformat_m68881_ext, &n, exten);
428 floatformat_to_double (&floatformat_m68881_ext, exten, &result);
429 if (n != result)
430 printf ("Differ(to+from): %.20g -> %.20g\n", n, result);
431
432#if IEEE_DEBUG > 1
433 /* This is to be run on a host which uses 68881 format. */
434 {
435 long double ex = *(long double *)exten;
436 if (ex != n)
437 printf ("Differ(from vs. extended): %.20g\n", n);
438 }
439#endif
440}
441
442int
443main ()
444{
445 ieee_test (0.5);
446 ieee_test (256.0);
447 ieee_test (0.12345);
448 ieee_test (234235.78907234);
449 ieee_test (-512.0);
450 ieee_test (-0.004321);
451 return 0;
452}
453#endif
Note: See TracBrowser for help on using the repository browser.