100bf4279Sespie /* IEEE floating point support routines, for GDB, the GNU Debugger.
2*150b7e42Smiod Copyright 1991, 1994, 1999, 2000, 2003, 2005, 2006
3*150b7e42Smiod Free Software Foundation, Inc.
400bf4279Sespie
500bf4279Sespie This file is part of GDB.
600bf4279Sespie
700bf4279Sespie This program is free software; you can redistribute it and/or modify
800bf4279Sespie it under the terms of the GNU General Public License as published by
900bf4279Sespie the Free Software Foundation; either version 2 of the License, or
1000bf4279Sespie (at your option) any later version.
1100bf4279Sespie
1200bf4279Sespie This program is distributed in the hope that it will be useful,
1300bf4279Sespie but WITHOUT ANY WARRANTY; without even the implied warranty of
1400bf4279Sespie MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1500bf4279Sespie GNU General Public License for more details.
1600bf4279Sespie
1700bf4279Sespie You should have received a copy of the GNU General Public License
1800bf4279Sespie along with this program; if not, write to the Free Software
19*150b7e42Smiod Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
2000bf4279Sespie
212579ccdbSkettenis /* This is needed to pick up the NAN macro on some systems. */
222579ccdbSkettenis #define _GNU_SOURCE
232579ccdbSkettenis
242579ccdbSkettenis #ifdef HAVE_CONFIG_H
252579ccdbSkettenis #include "config.h"
2600bf4279Sespie #endif
2700bf4279Sespie
282579ccdbSkettenis #include <math.h>
292579ccdbSkettenis
302579ccdbSkettenis #ifdef HAVE_STRING_H
312579ccdbSkettenis #include <string.h>
322579ccdbSkettenis #endif
332579ccdbSkettenis
34*150b7e42Smiod /* On some platforms, <float.h> provides DBL_QNAN. */
35*150b7e42Smiod #ifdef STDC_HEADERS
36*150b7e42Smiod #include <float.h>
37*150b7e42Smiod #endif
38*150b7e42Smiod
392579ccdbSkettenis #include "ansidecl.h"
402579ccdbSkettenis #include "libiberty.h"
412579ccdbSkettenis #include "floatformat.h"
422579ccdbSkettenis
432579ccdbSkettenis #ifndef INFINITY
442579ccdbSkettenis #ifdef HUGE_VAL
452579ccdbSkettenis #define INFINITY HUGE_VAL
462579ccdbSkettenis #else
472579ccdbSkettenis #define INFINITY (1.0 / 0.0)
482579ccdbSkettenis #endif
492579ccdbSkettenis #endif
502579ccdbSkettenis
512579ccdbSkettenis #ifndef NAN
52*150b7e42Smiod #ifdef DBL_QNAN
53*150b7e42Smiod #define NAN DBL_QNAN
54*150b7e42Smiod #else
552579ccdbSkettenis #define NAN (0.0 / 0.0)
562579ccdbSkettenis #endif
57*150b7e42Smiod #endif
582579ccdbSkettenis
59*150b7e42Smiod static unsigned long get_field (const unsigned char *,
602579ccdbSkettenis enum floatformat_byteorders,
612579ccdbSkettenis unsigned int,
622579ccdbSkettenis unsigned int,
63*150b7e42Smiod unsigned int);
64*150b7e42Smiod static int floatformat_always_valid (const struct floatformat *fmt,
65*150b7e42Smiod const void *from);
662579ccdbSkettenis
672579ccdbSkettenis static int
floatformat_always_valid(const struct floatformat * fmt ATTRIBUTE_UNUSED,const void * from ATTRIBUTE_UNUSED)68*150b7e42Smiod floatformat_always_valid (const struct floatformat *fmt ATTRIBUTE_UNUSED,
69*150b7e42Smiod const void *from ATTRIBUTE_UNUSED)
702579ccdbSkettenis {
712579ccdbSkettenis return 1;
722579ccdbSkettenis }
732579ccdbSkettenis
7400bf4279Sespie /* The odds that CHAR_BIT will be anything but 8 are low enough that I'm not
7500bf4279Sespie going to bother with trying to muck around with whether it is defined in
7600bf4279Sespie a system header, what we do if not, etc. */
7700bf4279Sespie #define FLOATFORMAT_CHAR_BIT 8
7800bf4279Sespie
7900bf4279Sespie /* floatformats for IEEE single and double, big and little endian. */
8000bf4279Sespie const struct floatformat floatformat_ieee_single_big =
8100bf4279Sespie {
8237c53322Sespie floatformat_big, 32, 0, 1, 8, 127, 255, 9, 23,
8337c53322Sespie floatformat_intbit_no,
842579ccdbSkettenis "floatformat_ieee_single_big",
852579ccdbSkettenis floatformat_always_valid
8600bf4279Sespie };
8700bf4279Sespie const struct floatformat floatformat_ieee_single_little =
8800bf4279Sespie {
8937c53322Sespie floatformat_little, 32, 0, 1, 8, 127, 255, 9, 23,
9037c53322Sespie floatformat_intbit_no,
912579ccdbSkettenis "floatformat_ieee_single_little",
922579ccdbSkettenis floatformat_always_valid
9300bf4279Sespie };
9400bf4279Sespie const struct floatformat floatformat_ieee_double_big =
9500bf4279Sespie {
9637c53322Sespie floatformat_big, 64, 0, 1, 11, 1023, 2047, 12, 52,
9737c53322Sespie floatformat_intbit_no,
982579ccdbSkettenis "floatformat_ieee_double_big",
992579ccdbSkettenis floatformat_always_valid
10000bf4279Sespie };
10100bf4279Sespie const struct floatformat floatformat_ieee_double_little =
10200bf4279Sespie {
10337c53322Sespie floatformat_little, 64, 0, 1, 11, 1023, 2047, 12, 52,
10437c53322Sespie floatformat_intbit_no,
1052579ccdbSkettenis "floatformat_ieee_double_little",
1062579ccdbSkettenis floatformat_always_valid
10700bf4279Sespie };
10800bf4279Sespie
10900bf4279Sespie /* floatformat for IEEE double, little endian byte order, with big endian word
11000bf4279Sespie ordering, as on the ARM. */
11100bf4279Sespie
11200bf4279Sespie const struct floatformat floatformat_ieee_double_littlebyte_bigword =
11300bf4279Sespie {
11437c53322Sespie floatformat_littlebyte_bigword, 64, 0, 1, 11, 1023, 2047, 12, 52,
11537c53322Sespie floatformat_intbit_no,
1162579ccdbSkettenis "floatformat_ieee_double_littlebyte_bigword",
1172579ccdbSkettenis floatformat_always_valid
11800bf4279Sespie };
11900bf4279Sespie
120*150b7e42Smiod /* floatformat for VAX. Not quite IEEE, but close enough. */
121*150b7e42Smiod
122*150b7e42Smiod const struct floatformat floatformat_vax_f =
123*150b7e42Smiod {
124*150b7e42Smiod floatformat_vax, 32, 0, 1, 8, 129, 0, 9, 23,
125*150b7e42Smiod floatformat_intbit_no,
126*150b7e42Smiod "floatformat_vax_f",
127*150b7e42Smiod floatformat_always_valid
128*150b7e42Smiod };
129*150b7e42Smiod const struct floatformat floatformat_vax_d =
130*150b7e42Smiod {
131*150b7e42Smiod floatformat_vax, 64, 0, 1, 8, 129, 0, 9, 55,
132*150b7e42Smiod floatformat_intbit_no,
133*150b7e42Smiod "floatformat_vax_d",
134*150b7e42Smiod floatformat_always_valid
135*150b7e42Smiod };
136*150b7e42Smiod const struct floatformat floatformat_vax_g =
137*150b7e42Smiod {
138*150b7e42Smiod floatformat_vax, 64, 0, 1, 11, 1025, 0, 12, 52,
139*150b7e42Smiod floatformat_intbit_no,
140*150b7e42Smiod "floatformat_vax_g",
141*150b7e42Smiod floatformat_always_valid
142*150b7e42Smiod };
143*150b7e42Smiod
144*150b7e42Smiod static int floatformat_i387_ext_is_valid (const struct floatformat *fmt,
145*150b7e42Smiod const void *from);
1462579ccdbSkettenis
1472579ccdbSkettenis static int
floatformat_i387_ext_is_valid(const struct floatformat * fmt,const void * from)148*150b7e42Smiod floatformat_i387_ext_is_valid (const struct floatformat *fmt, const void *from)
1492579ccdbSkettenis {
1502579ccdbSkettenis /* In the i387 double-extended format, if the exponent is all ones,
1512579ccdbSkettenis then the integer bit must be set. If the exponent is neither 0
1522579ccdbSkettenis nor ~0, the intbit must also be set. Only if the exponent is
1532579ccdbSkettenis zero can it be zero, and then it must be zero. */
1542579ccdbSkettenis unsigned long exponent, int_bit;
1552579ccdbSkettenis const unsigned char *ufrom = (const unsigned char *) from;
1562579ccdbSkettenis
1572579ccdbSkettenis exponent = get_field (ufrom, fmt->byteorder, fmt->totalsize,
1582579ccdbSkettenis fmt->exp_start, fmt->exp_len);
1592579ccdbSkettenis int_bit = get_field (ufrom, fmt->byteorder, fmt->totalsize,
1602579ccdbSkettenis fmt->man_start, 1);
1612579ccdbSkettenis
1622579ccdbSkettenis if ((exponent == 0) != (int_bit == 0))
1632579ccdbSkettenis return 0;
1642579ccdbSkettenis else
1652579ccdbSkettenis return 1;
1662579ccdbSkettenis }
1672579ccdbSkettenis
16800bf4279Sespie const struct floatformat floatformat_i387_ext =
16900bf4279Sespie {
17000bf4279Sespie floatformat_little, 80, 0, 1, 15, 0x3fff, 0x7fff, 16, 64,
17137c53322Sespie floatformat_intbit_yes,
1722579ccdbSkettenis "floatformat_i387_ext",
1732579ccdbSkettenis floatformat_i387_ext_is_valid
17400bf4279Sespie };
17500bf4279Sespie const struct floatformat floatformat_m68881_ext =
17600bf4279Sespie {
17700bf4279Sespie /* Note that the bits from 16 to 31 are unused. */
17837c53322Sespie floatformat_big, 96, 0, 1, 15, 0x3fff, 0x7fff, 32, 64,
17937c53322Sespie floatformat_intbit_yes,
1802579ccdbSkettenis "floatformat_m68881_ext",
1812579ccdbSkettenis floatformat_always_valid
18200bf4279Sespie };
18300bf4279Sespie const struct floatformat floatformat_i960_ext =
18400bf4279Sespie {
18500bf4279Sespie /* Note that the bits from 0 to 15 are unused. */
18600bf4279Sespie floatformat_little, 96, 16, 17, 15, 0x3fff, 0x7fff, 32, 64,
18737c53322Sespie floatformat_intbit_yes,
1882579ccdbSkettenis "floatformat_i960_ext",
1892579ccdbSkettenis floatformat_always_valid
19000bf4279Sespie };
19100bf4279Sespie const struct floatformat floatformat_m88110_ext =
19200bf4279Sespie {
19337c53322Sespie floatformat_big, 80, 0, 1, 15, 0x3fff, 0x7fff, 16, 64,
19437c53322Sespie floatformat_intbit_yes,
1952579ccdbSkettenis "floatformat_m88110_ext",
1962579ccdbSkettenis floatformat_always_valid
19737c53322Sespie };
19837c53322Sespie const struct floatformat floatformat_m88110_harris_ext =
19937c53322Sespie {
20000bf4279Sespie /* Harris uses raw format 128 bytes long, but the number is just an ieee
20100bf4279Sespie double, and the last 64 bits are wasted. */
20200bf4279Sespie floatformat_big,128, 0, 1, 11, 0x3ff, 0x7ff, 12, 52,
20337c53322Sespie floatformat_intbit_no,
2042579ccdbSkettenis "floatformat_m88110_ext_harris",
2052579ccdbSkettenis floatformat_always_valid
20600bf4279Sespie };
20737c53322Sespie const struct floatformat floatformat_arm_ext_big =
20800bf4279Sespie {
20900bf4279Sespie /* Bits 1 to 16 are unused. */
21000bf4279Sespie floatformat_big, 96, 0, 17, 15, 0x3fff, 0x7fff, 32, 64,
21137c53322Sespie floatformat_intbit_yes,
2122579ccdbSkettenis "floatformat_arm_ext_big",
2132579ccdbSkettenis floatformat_always_valid
21437c53322Sespie };
21537c53322Sespie const struct floatformat floatformat_arm_ext_littlebyte_bigword =
21637c53322Sespie {
21737c53322Sespie /* Bits 1 to 16 are unused. */
21837c53322Sespie floatformat_littlebyte_bigword, 96, 0, 17, 15, 0x3fff, 0x7fff, 32, 64,
21937c53322Sespie floatformat_intbit_yes,
2202579ccdbSkettenis "floatformat_arm_ext_littlebyte_bigword",
2212579ccdbSkettenis floatformat_always_valid
22237c53322Sespie };
22337c53322Sespie const struct floatformat floatformat_ia64_spill_big =
22437c53322Sespie {
22537c53322Sespie floatformat_big, 128, 0, 1, 17, 65535, 0x1ffff, 18, 64,
22637c53322Sespie floatformat_intbit_yes,
2272579ccdbSkettenis "floatformat_ia64_spill_big",
2282579ccdbSkettenis floatformat_always_valid
22937c53322Sespie };
23037c53322Sespie const struct floatformat floatformat_ia64_spill_little =
23137c53322Sespie {
23237c53322Sespie floatformat_little, 128, 0, 1, 17, 65535, 0x1ffff, 18, 64,
23337c53322Sespie floatformat_intbit_yes,
2342579ccdbSkettenis "floatformat_ia64_spill_little",
2352579ccdbSkettenis floatformat_always_valid
23637c53322Sespie };
23737c53322Sespie const struct floatformat floatformat_ia64_quad_big =
23837c53322Sespie {
23937c53322Sespie floatformat_big, 128, 0, 1, 15, 16383, 0x7fff, 16, 112,
24037c53322Sespie floatformat_intbit_no,
2412579ccdbSkettenis "floatformat_ia64_quad_big",
2422579ccdbSkettenis floatformat_always_valid
24337c53322Sespie };
24437c53322Sespie const struct floatformat floatformat_ia64_quad_little =
24537c53322Sespie {
24637c53322Sespie floatformat_little, 128, 0, 1, 15, 16383, 0x7fff, 16, 112,
24737c53322Sespie floatformat_intbit_no,
2482579ccdbSkettenis "floatformat_ia64_quad_little",
2492579ccdbSkettenis floatformat_always_valid
25000bf4279Sespie };
25100bf4279Sespie
2522579ccdbSkettenis /* Extract a field which starts at START and is LEN bits long. DATA and
25300bf4279Sespie TOTAL_LEN are the thing we are extracting it from, in byteorder ORDER. */
25400bf4279Sespie static unsigned long
get_field(const unsigned char * data,enum floatformat_byteorders order,unsigned int total_len,unsigned int start,unsigned int len)255*150b7e42Smiod get_field (const unsigned char *data, enum floatformat_byteorders order,
256*150b7e42Smiod unsigned int total_len, unsigned int start, unsigned int len)
25700bf4279Sespie {
25800bf4279Sespie unsigned long result;
25900bf4279Sespie unsigned int cur_byte;
26000bf4279Sespie int cur_bitshift;
26100bf4279Sespie
26200bf4279Sespie /* Start at the least significant part of the field. */
26300bf4279Sespie cur_byte = (start + len) / FLOATFORMAT_CHAR_BIT;
26400bf4279Sespie if (order == floatformat_little)
26500bf4279Sespie cur_byte = (total_len / FLOATFORMAT_CHAR_BIT) - cur_byte - 1;
26600bf4279Sespie cur_bitshift =
26700bf4279Sespie ((start + len) % FLOATFORMAT_CHAR_BIT) - FLOATFORMAT_CHAR_BIT;
26800bf4279Sespie result = *(data + cur_byte) >> (-cur_bitshift);
26900bf4279Sespie cur_bitshift += FLOATFORMAT_CHAR_BIT;
27000bf4279Sespie if (order == floatformat_little)
27100bf4279Sespie ++cur_byte;
27200bf4279Sespie else
27300bf4279Sespie --cur_byte;
27400bf4279Sespie
27500bf4279Sespie /* Move towards the most significant part of the field. */
27600bf4279Sespie while ((unsigned int) cur_bitshift < len)
27700bf4279Sespie {
27800bf4279Sespie if (len - cur_bitshift < FLOATFORMAT_CHAR_BIT)
27900bf4279Sespie /* This is the last byte; zero out the bits which are not part of
28000bf4279Sespie this field. */
28100bf4279Sespie result |=
28200bf4279Sespie (*(data + cur_byte) & ((1 << (len - cur_bitshift)) - 1))
28300bf4279Sespie << cur_bitshift;
28400bf4279Sespie else
28500bf4279Sespie result |= *(data + cur_byte) << cur_bitshift;
28600bf4279Sespie cur_bitshift += FLOATFORMAT_CHAR_BIT;
28700bf4279Sespie if (order == floatformat_little)
28800bf4279Sespie ++cur_byte;
28900bf4279Sespie else
29000bf4279Sespie --cur_byte;
29100bf4279Sespie }
29200bf4279Sespie return result;
29300bf4279Sespie }
29400bf4279Sespie
29500bf4279Sespie #ifndef min
29600bf4279Sespie #define min(a, b) ((a) < (b) ? (a) : (b))
29700bf4279Sespie #endif
29800bf4279Sespie
29900bf4279Sespie /* Convert from FMT to a double.
30000bf4279Sespie FROM is the address of the extended float.
30100bf4279Sespie Store the double in *TO. */
30200bf4279Sespie
30300bf4279Sespie void
floatformat_to_double(const struct floatformat * fmt,const void * from,double * to)304*150b7e42Smiod floatformat_to_double (const struct floatformat *fmt,
305*150b7e42Smiod const void *from, double *to)
30600bf4279Sespie {
3072579ccdbSkettenis const unsigned char *ufrom = (const unsigned char *) from;
30800bf4279Sespie double dto;
30900bf4279Sespie long exponent;
31000bf4279Sespie unsigned long mant;
31100bf4279Sespie unsigned int mant_bits, mant_off;
31200bf4279Sespie int mant_bits_left;
31300bf4279Sespie int special_exponent; /* It's a NaN, denorm or zero */
31400bf4279Sespie
31500bf4279Sespie exponent = get_field (ufrom, fmt->byteorder, fmt->totalsize,
31600bf4279Sespie fmt->exp_start, fmt->exp_len);
3172579ccdbSkettenis
3182579ccdbSkettenis /* If the exponent indicates a NaN, we don't have information to
3192579ccdbSkettenis decide what to do. So we handle it like IEEE, except that we
3202579ccdbSkettenis don't try to preserve the type of NaN. FIXME. */
3212579ccdbSkettenis if ((unsigned long) exponent == fmt->exp_nan)
3222579ccdbSkettenis {
3232579ccdbSkettenis int nan;
3242579ccdbSkettenis
3252579ccdbSkettenis mant_off = fmt->man_start;
3262579ccdbSkettenis mant_bits_left = fmt->man_len;
3272579ccdbSkettenis nan = 0;
3282579ccdbSkettenis while (mant_bits_left > 0)
3292579ccdbSkettenis {
3302579ccdbSkettenis mant_bits = min (mant_bits_left, 32);
3312579ccdbSkettenis
3322579ccdbSkettenis if (get_field (ufrom, fmt->byteorder, fmt->totalsize,
3332579ccdbSkettenis mant_off, mant_bits) != 0)
3342579ccdbSkettenis {
3352579ccdbSkettenis /* This is a NaN. */
3362579ccdbSkettenis nan = 1;
3372579ccdbSkettenis break;
3382579ccdbSkettenis }
3392579ccdbSkettenis
3402579ccdbSkettenis mant_off += mant_bits;
3412579ccdbSkettenis mant_bits_left -= mant_bits;
3422579ccdbSkettenis }
3432579ccdbSkettenis
344*150b7e42Smiod /* On certain systems (such as GNU/Linux), the use of the
345*150b7e42Smiod INFINITY macro below may generate a warning that can not be
346*150b7e42Smiod silenced due to a bug in GCC (PR preprocessor/11931). The
347*150b7e42Smiod preprocessor fails to recognise the __extension__ keyword in
348*150b7e42Smiod conjunction with the GNU/C99 extension for hexadecimal
349*150b7e42Smiod floating point constants and will issue a warning when
350*150b7e42Smiod compiling with -pedantic. */
3512579ccdbSkettenis if (nan)
3522579ccdbSkettenis dto = NAN;
3532579ccdbSkettenis else
3542579ccdbSkettenis dto = INFINITY;
3552579ccdbSkettenis
3562579ccdbSkettenis if (get_field (ufrom, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1))
3572579ccdbSkettenis dto = -dto;
3582579ccdbSkettenis
3592579ccdbSkettenis *to = dto;
3602579ccdbSkettenis
3612579ccdbSkettenis return;
3622579ccdbSkettenis }
36300bf4279Sespie
36400bf4279Sespie mant_bits_left = fmt->man_len;
36500bf4279Sespie mant_off = fmt->man_start;
36600bf4279Sespie dto = 0.0;
36700bf4279Sespie
36800bf4279Sespie special_exponent = exponent == 0 || (unsigned long) exponent == fmt->exp_nan;
36900bf4279Sespie
37000bf4279Sespie /* Don't bias zero's, denorms or NaNs. */
37100bf4279Sespie if (!special_exponent)
37200bf4279Sespie exponent -= fmt->exp_bias;
37300bf4279Sespie
37400bf4279Sespie /* Build the result algebraically. Might go infinite, underflow, etc;
37500bf4279Sespie who cares. */
37600bf4279Sespie
37700bf4279Sespie /* If this format uses a hidden bit, explicitly add it in now. Otherwise,
37800bf4279Sespie increment the exponent by one to account for the integer bit. */
37900bf4279Sespie
38000bf4279Sespie if (!special_exponent)
38100bf4279Sespie {
38200bf4279Sespie if (fmt->intbit == floatformat_intbit_no)
38300bf4279Sespie dto = ldexp (1.0, exponent);
38400bf4279Sespie else
38500bf4279Sespie exponent++;
38600bf4279Sespie }
38700bf4279Sespie
38800bf4279Sespie while (mant_bits_left > 0)
38900bf4279Sespie {
39000bf4279Sespie mant_bits = min (mant_bits_left, 32);
39100bf4279Sespie
39200bf4279Sespie mant = get_field (ufrom, fmt->byteorder, fmt->totalsize,
39300bf4279Sespie mant_off, mant_bits);
39400bf4279Sespie
3952579ccdbSkettenis /* Handle denormalized numbers. FIXME: What should we do for
3962579ccdbSkettenis non-IEEE formats? */
3972579ccdbSkettenis if (exponent == 0 && mant != 0)
3982579ccdbSkettenis dto += ldexp ((double)mant,
3992579ccdbSkettenis (- fmt->exp_bias
4002579ccdbSkettenis - mant_bits
4012579ccdbSkettenis - (mant_off - fmt->man_start)
4022579ccdbSkettenis + 1));
4032579ccdbSkettenis else
40400bf4279Sespie dto += ldexp ((double)mant, exponent - mant_bits);
4052579ccdbSkettenis if (exponent != 0)
40600bf4279Sespie exponent -= mant_bits;
40700bf4279Sespie mant_off += mant_bits;
40800bf4279Sespie mant_bits_left -= mant_bits;
40900bf4279Sespie }
41000bf4279Sespie
41100bf4279Sespie /* Negate it if negative. */
41200bf4279Sespie if (get_field (ufrom, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1))
41300bf4279Sespie dto = -dto;
41400bf4279Sespie *to = dto;
41500bf4279Sespie }
41600bf4279Sespie
417*150b7e42Smiod static void put_field (unsigned char *, enum floatformat_byteorders,
41800bf4279Sespie unsigned int,
41900bf4279Sespie unsigned int,
42000bf4279Sespie unsigned int,
421*150b7e42Smiod unsigned long);
42200bf4279Sespie
4232579ccdbSkettenis /* Set a field which starts at START and is LEN bits long. DATA and
42400bf4279Sespie TOTAL_LEN are the thing we are extracting it from, in byteorder ORDER. */
42500bf4279Sespie static void
put_field(unsigned char * data,enum floatformat_byteorders order,unsigned int total_len,unsigned int start,unsigned int len,unsigned long stuff_to_put)426*150b7e42Smiod put_field (unsigned char *data, enum floatformat_byteorders order,
427*150b7e42Smiod unsigned int total_len, unsigned int start, unsigned int len,
428*150b7e42Smiod unsigned long stuff_to_put)
42900bf4279Sespie {
43000bf4279Sespie unsigned int cur_byte;
43100bf4279Sespie int cur_bitshift;
43200bf4279Sespie
43300bf4279Sespie /* Start at the least significant part of the field. */
43400bf4279Sespie cur_byte = (start + len) / FLOATFORMAT_CHAR_BIT;
43500bf4279Sespie if (order == floatformat_little)
43600bf4279Sespie cur_byte = (total_len / FLOATFORMAT_CHAR_BIT) - cur_byte - 1;
43700bf4279Sespie cur_bitshift =
43800bf4279Sespie ((start + len) % FLOATFORMAT_CHAR_BIT) - FLOATFORMAT_CHAR_BIT;
43900bf4279Sespie *(data + cur_byte) &=
44000bf4279Sespie ~(((1 << ((start + len) % FLOATFORMAT_CHAR_BIT)) - 1) << (-cur_bitshift));
44100bf4279Sespie *(data + cur_byte) |=
44200bf4279Sespie (stuff_to_put & ((1 << FLOATFORMAT_CHAR_BIT) - 1)) << (-cur_bitshift);
44300bf4279Sespie cur_bitshift += FLOATFORMAT_CHAR_BIT;
44400bf4279Sespie if (order == floatformat_little)
44500bf4279Sespie ++cur_byte;
44600bf4279Sespie else
44700bf4279Sespie --cur_byte;
44800bf4279Sespie
44900bf4279Sespie /* Move towards the most significant part of the field. */
45000bf4279Sespie while ((unsigned int) cur_bitshift < len)
45100bf4279Sespie {
45200bf4279Sespie if (len - cur_bitshift < FLOATFORMAT_CHAR_BIT)
45300bf4279Sespie {
45400bf4279Sespie /* This is the last byte. */
45500bf4279Sespie *(data + cur_byte) &=
45600bf4279Sespie ~((1 << (len - cur_bitshift)) - 1);
45700bf4279Sespie *(data + cur_byte) |= (stuff_to_put >> cur_bitshift);
45800bf4279Sespie }
45900bf4279Sespie else
46000bf4279Sespie *(data + cur_byte) = ((stuff_to_put >> cur_bitshift)
46100bf4279Sespie & ((1 << FLOATFORMAT_CHAR_BIT) - 1));
46200bf4279Sespie cur_bitshift += FLOATFORMAT_CHAR_BIT;
46300bf4279Sespie if (order == floatformat_little)
46400bf4279Sespie ++cur_byte;
46500bf4279Sespie else
46600bf4279Sespie --cur_byte;
46700bf4279Sespie }
46800bf4279Sespie }
46900bf4279Sespie
47000bf4279Sespie /* The converse: convert the double *FROM to an extended float
47100bf4279Sespie and store where TO points. Neither FROM nor TO have any alignment
47200bf4279Sespie restrictions. */
47300bf4279Sespie
47400bf4279Sespie void
floatformat_from_double(const struct floatformat * fmt,const double * from,void * to)475*150b7e42Smiod floatformat_from_double (const struct floatformat *fmt,
476*150b7e42Smiod const double *from, void *to)
47700bf4279Sespie {
47800bf4279Sespie double dfrom;
47900bf4279Sespie int exponent;
48000bf4279Sespie double mant;
48100bf4279Sespie unsigned int mant_bits, mant_off;
48200bf4279Sespie int mant_bits_left;
48300bf4279Sespie unsigned char *uto = (unsigned char *) to;
48400bf4279Sespie
4852579ccdbSkettenis dfrom = *from;
48600bf4279Sespie memset (uto, 0, fmt->totalsize / FLOATFORMAT_CHAR_BIT);
48700bf4279Sespie
48800bf4279Sespie /* If negative, set the sign bit. */
48900bf4279Sespie if (dfrom < 0)
49000bf4279Sespie {
49100bf4279Sespie put_field (uto, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1, 1);
49200bf4279Sespie dfrom = -dfrom;
49300bf4279Sespie }
49400bf4279Sespie
4952579ccdbSkettenis if (dfrom == 0)
4962579ccdbSkettenis {
4972579ccdbSkettenis /* 0.0. */
4982579ccdbSkettenis return;
4992579ccdbSkettenis }
5002579ccdbSkettenis
5012579ccdbSkettenis if (dfrom != dfrom)
5022579ccdbSkettenis {
5032579ccdbSkettenis /* NaN. */
5042579ccdbSkettenis put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start,
5052579ccdbSkettenis fmt->exp_len, fmt->exp_nan);
5062579ccdbSkettenis /* Be sure it's not infinity, but NaN value is irrelevant. */
5072579ccdbSkettenis put_field (uto, fmt->byteorder, fmt->totalsize, fmt->man_start,
5082579ccdbSkettenis 32, 1);
5092579ccdbSkettenis return;
5102579ccdbSkettenis }
5112579ccdbSkettenis
5122579ccdbSkettenis if (dfrom + dfrom == dfrom)
5132579ccdbSkettenis {
5142579ccdbSkettenis /* This can only happen for an infinite value (or zero, which we
5152579ccdbSkettenis already handled above). */
5162579ccdbSkettenis put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start,
5172579ccdbSkettenis fmt->exp_len, fmt->exp_nan);
5182579ccdbSkettenis return;
5192579ccdbSkettenis }
52000bf4279Sespie
52100bf4279Sespie mant = frexp (dfrom, &exponent);
5222579ccdbSkettenis if (exponent + fmt->exp_bias - 1 > 0)
5232579ccdbSkettenis put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start,
5242579ccdbSkettenis fmt->exp_len, exponent + fmt->exp_bias - 1);
5252579ccdbSkettenis else
5262579ccdbSkettenis {
5272579ccdbSkettenis /* Handle a denormalized number. FIXME: What should we do for
5282579ccdbSkettenis non-IEEE formats? */
5292579ccdbSkettenis put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start,
5302579ccdbSkettenis fmt->exp_len, 0);
5312579ccdbSkettenis mant = ldexp (mant, exponent + fmt->exp_bias - 1);
5322579ccdbSkettenis }
53300bf4279Sespie
53400bf4279Sespie mant_bits_left = fmt->man_len;
53500bf4279Sespie mant_off = fmt->man_start;
53600bf4279Sespie while (mant_bits_left > 0)
53700bf4279Sespie {
53800bf4279Sespie unsigned long mant_long;
53900bf4279Sespie mant_bits = mant_bits_left < 32 ? mant_bits_left : 32;
54000bf4279Sespie
54100bf4279Sespie mant *= 4294967296.0;
54200bf4279Sespie mant_long = (unsigned long)mant;
54300bf4279Sespie mant -= mant_long;
54400bf4279Sespie
5452579ccdbSkettenis /* If the integer bit is implicit, and we are not creating a
5462579ccdbSkettenis denormalized number, then we need to discard it. */
54700bf4279Sespie if ((unsigned int) mant_bits_left == fmt->man_len
5482579ccdbSkettenis && fmt->intbit == floatformat_intbit_no
5492579ccdbSkettenis && exponent + fmt->exp_bias - 1 > 0)
55000bf4279Sespie {
55100bf4279Sespie mant_long &= 0x7fffffff;
55200bf4279Sespie mant_bits -= 1;
55300bf4279Sespie }
55400bf4279Sespie else if (mant_bits < 32)
55500bf4279Sespie {
55600bf4279Sespie /* The bits we want are in the most significant MANT_BITS bits of
55700bf4279Sespie mant_long. Move them to the least significant. */
55800bf4279Sespie mant_long >>= 32 - mant_bits;
55900bf4279Sespie }
56000bf4279Sespie
56100bf4279Sespie put_field (uto, fmt->byteorder, fmt->totalsize,
56200bf4279Sespie mant_off, mant_bits, mant_long);
56300bf4279Sespie mant_off += mant_bits;
56400bf4279Sespie mant_bits_left -= mant_bits;
56500bf4279Sespie }
56600bf4279Sespie }
56700bf4279Sespie
5682579ccdbSkettenis /* Return non-zero iff the data at FROM is a valid number in format FMT. */
5692579ccdbSkettenis
5702579ccdbSkettenis int
floatformat_is_valid(const struct floatformat * fmt,const void * from)571*150b7e42Smiod floatformat_is_valid (const struct floatformat *fmt, const void *from)
5722579ccdbSkettenis {
5732579ccdbSkettenis return fmt->is_valid (fmt, from);
5742579ccdbSkettenis }
5752579ccdbSkettenis
57600bf4279Sespie
57700bf4279Sespie #ifdef IEEE_DEBUG
57800bf4279Sespie
5792579ccdbSkettenis #include <stdio.h>
5802579ccdbSkettenis
58100bf4279Sespie /* This is to be run on a host which uses IEEE floating point. */
58200bf4279Sespie
58300bf4279Sespie void
ieee_test(double n)584*150b7e42Smiod ieee_test (double n)
58500bf4279Sespie {
58600bf4279Sespie double result;
58700bf4279Sespie
588*150b7e42Smiod floatformat_to_double (&floatformat_ieee_double_little, &n, &result);
5892579ccdbSkettenis if ((n != result && (! isnan (n) || ! isnan (result)))
5902579ccdbSkettenis || (n < 0 && result >= 0)
5912579ccdbSkettenis || (n >= 0 && result < 0))
59200bf4279Sespie printf ("Differ(to): %.20g -> %.20g\n", n, result);
5932579ccdbSkettenis
594*150b7e42Smiod floatformat_from_double (&floatformat_ieee_double_little, &n, &result);
5952579ccdbSkettenis if ((n != result && (! isnan (n) || ! isnan (result)))
5962579ccdbSkettenis || (n < 0 && result >= 0)
5972579ccdbSkettenis || (n >= 0 && result < 0))
59800bf4279Sespie printf ("Differ(from): %.20g -> %.20g\n", n, result);
59900bf4279Sespie
6002579ccdbSkettenis #if 0
6012579ccdbSkettenis {
6022579ccdbSkettenis char exten[16];
6032579ccdbSkettenis
60400bf4279Sespie floatformat_from_double (&floatformat_m68881_ext, &n, exten);
60500bf4279Sespie floatformat_to_double (&floatformat_m68881_ext, exten, &result);
60600bf4279Sespie if (n != result)
60700bf4279Sespie printf ("Differ(to+from): %.20g -> %.20g\n", n, result);
6082579ccdbSkettenis }
6092579ccdbSkettenis #endif
61000bf4279Sespie
61100bf4279Sespie #if IEEE_DEBUG > 1
61200bf4279Sespie /* This is to be run on a host which uses 68881 format. */
61300bf4279Sespie {
61400bf4279Sespie long double ex = *(long double *)exten;
61500bf4279Sespie if (ex != n)
61600bf4279Sespie printf ("Differ(from vs. extended): %.20g\n", n);
61700bf4279Sespie }
61800bf4279Sespie #endif
61900bf4279Sespie }
62000bf4279Sespie
62100bf4279Sespie int
main(void)622*150b7e42Smiod main (void)
62300bf4279Sespie {
6242579ccdbSkettenis ieee_test (0.0);
62500bf4279Sespie ieee_test (0.5);
62600bf4279Sespie ieee_test (256.0);
62700bf4279Sespie ieee_test (0.12345);
62800bf4279Sespie ieee_test (234235.78907234);
62900bf4279Sespie ieee_test (-512.0);
63000bf4279Sespie ieee_test (-0.004321);
6312579ccdbSkettenis ieee_test (1.2E-70);
6322579ccdbSkettenis ieee_test (1.2E-316);
6332579ccdbSkettenis ieee_test (4.9406564584124654E-324);
6342579ccdbSkettenis ieee_test (- 4.9406564584124654E-324);
6352579ccdbSkettenis ieee_test (- 0.0);
6362579ccdbSkettenis ieee_test (- INFINITY);
6372579ccdbSkettenis ieee_test (- NAN);
6382579ccdbSkettenis ieee_test (INFINITY);
6392579ccdbSkettenis ieee_test (NAN);
64000bf4279Sespie return 0;
64100bf4279Sespie }
64200bf4279Sespie #endif
643