xref: /openbsd-src/gnu/lib/libiberty/src/floatformat.c (revision 150b7e42cfa21e6546d96ae514ca23e80d970ac7)
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