xref: /netbsd-src/external/gpl3/gdb/dist/libiberty/floatformat.c (revision 7e120ff03ede3fe64e2c8620c01465d528502ddb)
198b9484cSchristos /* IEEE floating point support routines, for GDB, the GNU Debugger.
2*7e120ff0Schristos    Copyright (C) 1991-2024 Free Software Foundation, Inc.
398b9484cSchristos 
498b9484cSchristos This file is part of GDB.
598b9484cSchristos 
698b9484cSchristos This program is free software; you can redistribute it and/or modify
798b9484cSchristos it under the terms of the GNU General Public License as published by
898b9484cSchristos the Free Software Foundation; either version 2 of the License, or
998b9484cSchristos (at your option) any later version.
1098b9484cSchristos 
1198b9484cSchristos This program is distributed in the hope that it will be useful,
1298b9484cSchristos but WITHOUT ANY WARRANTY; without even the implied warranty of
1398b9484cSchristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1498b9484cSchristos GNU General Public License for more details.
1598b9484cSchristos 
1698b9484cSchristos You should have received a copy of the GNU General Public License
1798b9484cSchristos along with this program; if not, write to the Free Software
1898b9484cSchristos Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
1998b9484cSchristos 
2098b9484cSchristos /* This is needed to pick up the NAN macro on some systems.  */
21212397c6Schristos #ifndef _GNU_SOURCE
2298b9484cSchristos #define _GNU_SOURCE
23212397c6Schristos #endif
2498b9484cSchristos 
2598b9484cSchristos #ifdef HAVE_CONFIG_H
2698b9484cSchristos #include "config.h"
2798b9484cSchristos #endif
2898b9484cSchristos 
2998b9484cSchristos #include <math.h>
3098b9484cSchristos 
3198b9484cSchristos #ifdef HAVE_STRING_H
3298b9484cSchristos #include <string.h>
3398b9484cSchristos #endif
3498b9484cSchristos 
3598b9484cSchristos /* On some platforms, <float.h> provides DBL_QNAN.  */
3698b9484cSchristos #ifdef STDC_HEADERS
3798b9484cSchristos #include <float.h>
3898b9484cSchristos #endif
3998b9484cSchristos 
4098b9484cSchristos #include "ansidecl.h"
4198b9484cSchristos #include "libiberty.h"
4298b9484cSchristos #include "floatformat.h"
4398b9484cSchristos 
4498b9484cSchristos #ifndef INFINITY
4598b9484cSchristos #ifdef HUGE_VAL
4698b9484cSchristos #define INFINITY HUGE_VAL
4798b9484cSchristos #else
4898b9484cSchristos #define INFINITY (1.0 / 0.0)
4998b9484cSchristos #endif
5098b9484cSchristos #endif
5198b9484cSchristos 
5298b9484cSchristos #ifndef NAN
5398b9484cSchristos #ifdef DBL_QNAN
5498b9484cSchristos #define NAN DBL_QNAN
5598b9484cSchristos #else
5698b9484cSchristos #define NAN (0.0 / 0.0)
5798b9484cSchristos #endif
5898b9484cSchristos #endif
5998b9484cSchristos 
6098b9484cSchristos static int mant_bits_set (const struct floatformat *, const unsigned char *);
6198b9484cSchristos static unsigned long get_field (const unsigned char *,
6298b9484cSchristos                                 enum floatformat_byteorders,
6398b9484cSchristos                                 unsigned int,
6498b9484cSchristos                                 unsigned int,
6598b9484cSchristos                                 unsigned int);
6698b9484cSchristos static int floatformat_always_valid (const struct floatformat *fmt,
6798b9484cSchristos                                      const void *from);
6898b9484cSchristos 
6998b9484cSchristos static int
7098b9484cSchristos floatformat_always_valid (const struct floatformat *fmt ATTRIBUTE_UNUSED,
7198b9484cSchristos                           const void *from ATTRIBUTE_UNUSED)
7298b9484cSchristos {
7398b9484cSchristos   return 1;
7498b9484cSchristos }
7598b9484cSchristos 
7698b9484cSchristos /* The odds that CHAR_BIT will be anything but 8 are low enough that I'm not
7798b9484cSchristos    going to bother with trying to muck around with whether it is defined in
7898b9484cSchristos    a system header, what we do if not, etc.  */
7998b9484cSchristos #define FLOATFORMAT_CHAR_BIT 8
8098b9484cSchristos 
814b169a6bSchristos /* floatformats for IEEE half, single, double and quad, big and little endian.  */
8298b9484cSchristos const struct floatformat floatformat_ieee_half_big =
8398b9484cSchristos {
8498b9484cSchristos   floatformat_big, 16, 0, 1, 5, 15, 31, 6, 10,
8598b9484cSchristos   floatformat_intbit_no,
8698b9484cSchristos   "floatformat_ieee_half_big",
8798b9484cSchristos   floatformat_always_valid,
8898b9484cSchristos   NULL
8998b9484cSchristos };
9098b9484cSchristos const struct floatformat floatformat_ieee_half_little =
9198b9484cSchristos {
9298b9484cSchristos   floatformat_little, 16, 0, 1, 5, 15, 31, 6, 10,
9398b9484cSchristos   floatformat_intbit_no,
9498b9484cSchristos   "floatformat_ieee_half_little",
9598b9484cSchristos   floatformat_always_valid,
9698b9484cSchristos   NULL
9798b9484cSchristos };
9898b9484cSchristos const struct floatformat floatformat_ieee_single_big =
9998b9484cSchristos {
10098b9484cSchristos   floatformat_big, 32, 0, 1, 8, 127, 255, 9, 23,
10198b9484cSchristos   floatformat_intbit_no,
10298b9484cSchristos   "floatformat_ieee_single_big",
10398b9484cSchristos   floatformat_always_valid,
10498b9484cSchristos   NULL
10598b9484cSchristos };
10698b9484cSchristos const struct floatformat floatformat_ieee_single_little =
10798b9484cSchristos {
10898b9484cSchristos   floatformat_little, 32, 0, 1, 8, 127, 255, 9, 23,
10998b9484cSchristos   floatformat_intbit_no,
11098b9484cSchristos   "floatformat_ieee_single_little",
11198b9484cSchristos   floatformat_always_valid,
11298b9484cSchristos   NULL
11398b9484cSchristos };
11498b9484cSchristos const struct floatformat floatformat_ieee_double_big =
11598b9484cSchristos {
11698b9484cSchristos   floatformat_big, 64, 0, 1, 11, 1023, 2047, 12, 52,
11798b9484cSchristos   floatformat_intbit_no,
11898b9484cSchristos   "floatformat_ieee_double_big",
11998b9484cSchristos   floatformat_always_valid,
12098b9484cSchristos   NULL
12198b9484cSchristos };
12298b9484cSchristos const struct floatformat floatformat_ieee_double_little =
12398b9484cSchristos {
12498b9484cSchristos   floatformat_little, 64, 0, 1, 11, 1023, 2047, 12, 52,
12598b9484cSchristos   floatformat_intbit_no,
12698b9484cSchristos   "floatformat_ieee_double_little",
12798b9484cSchristos   floatformat_always_valid,
12898b9484cSchristos   NULL
12998b9484cSchristos };
1304b169a6bSchristos const struct floatformat floatformat_ieee_quad_big =
1314b169a6bSchristos {
1324b169a6bSchristos   floatformat_big, 128, 0, 1, 15, 16383, 0x7fff, 16, 112,
1334b169a6bSchristos   floatformat_intbit_no,
1344b169a6bSchristos   "floatformat_ieee_quad_big",
1354b169a6bSchristos   floatformat_always_valid,
1364b169a6bSchristos   NULL
1374b169a6bSchristos };
1384b169a6bSchristos const struct floatformat floatformat_ieee_quad_little =
1394b169a6bSchristos {
1404b169a6bSchristos   floatformat_little, 128, 0, 1, 15, 16383, 0x7fff, 16, 112,
1414b169a6bSchristos   floatformat_intbit_no,
1424b169a6bSchristos   "floatformat_ieee_quad_little",
1434b169a6bSchristos   floatformat_always_valid,
1444b169a6bSchristos   NULL
1454b169a6bSchristos };
14698b9484cSchristos 
14798b9484cSchristos /* floatformat for IEEE double, little endian byte order, with big endian word
14898b9484cSchristos    ordering, as on the ARM.  */
14998b9484cSchristos 
15098b9484cSchristos const struct floatformat floatformat_ieee_double_littlebyte_bigword =
15198b9484cSchristos {
15298b9484cSchristos   floatformat_littlebyte_bigword, 64, 0, 1, 11, 1023, 2047, 12, 52,
15398b9484cSchristos   floatformat_intbit_no,
15498b9484cSchristos   "floatformat_ieee_double_littlebyte_bigword",
15598b9484cSchristos   floatformat_always_valid,
15698b9484cSchristos   NULL
15798b9484cSchristos };
15898b9484cSchristos 
15998b9484cSchristos /* floatformat for VAX.  Not quite IEEE, but close enough.  */
16098b9484cSchristos 
16198b9484cSchristos const struct floatformat floatformat_vax_f =
16298b9484cSchristos {
16398b9484cSchristos   floatformat_vax, 32, 0, 1, 8, 129, 0, 9, 23,
16498b9484cSchristos   floatformat_intbit_no,
16598b9484cSchristos   "floatformat_vax_f",
16698b9484cSchristos   floatformat_always_valid,
16798b9484cSchristos   NULL
16898b9484cSchristos };
16998b9484cSchristos const struct floatformat floatformat_vax_d =
17098b9484cSchristos {
17198b9484cSchristos   floatformat_vax, 64, 0, 1, 8, 129, 0, 9, 55,
17298b9484cSchristos   floatformat_intbit_no,
17398b9484cSchristos   "floatformat_vax_d",
17498b9484cSchristos   floatformat_always_valid,
17598b9484cSchristos   NULL
17698b9484cSchristos };
17798b9484cSchristos const struct floatformat floatformat_vax_g =
17898b9484cSchristos {
17998b9484cSchristos   floatformat_vax, 64, 0, 1, 11, 1025, 0, 12, 52,
18098b9484cSchristos   floatformat_intbit_no,
18198b9484cSchristos   "floatformat_vax_g",
18298b9484cSchristos   floatformat_always_valid,
18398b9484cSchristos   NULL
18498b9484cSchristos };
18598b9484cSchristos 
18698b9484cSchristos static int floatformat_i387_ext_is_valid (const struct floatformat *fmt,
18798b9484cSchristos 					  const void *from);
18898b9484cSchristos 
18998b9484cSchristos static int
19098b9484cSchristos floatformat_i387_ext_is_valid (const struct floatformat *fmt, const void *from)
19198b9484cSchristos {
19298b9484cSchristos   /* In the i387 double-extended format, if the exponent is all ones,
19398b9484cSchristos      then the integer bit must be set.  If the exponent is neither 0
19498b9484cSchristos      nor ~0, the intbit must also be set.  Only if the exponent is
19598b9484cSchristos      zero can it be zero, and then it must be zero.  */
19698b9484cSchristos   unsigned long exponent, int_bit;
19798b9484cSchristos   const unsigned char *ufrom = (const unsigned char *) from;
19898b9484cSchristos 
19998b9484cSchristos   exponent = get_field (ufrom, fmt->byteorder, fmt->totalsize,
20098b9484cSchristos 			fmt->exp_start, fmt->exp_len);
20198b9484cSchristos   int_bit = get_field (ufrom, fmt->byteorder, fmt->totalsize,
20298b9484cSchristos 		       fmt->man_start, 1);
20398b9484cSchristos 
20498b9484cSchristos   if ((exponent == 0) != (int_bit == 0))
20598b9484cSchristos     return 0;
20698b9484cSchristos   else
20798b9484cSchristos     return 1;
20898b9484cSchristos }
20998b9484cSchristos 
21098b9484cSchristos const struct floatformat floatformat_i387_ext =
21198b9484cSchristos {
21298b9484cSchristos   floatformat_little, 80, 0, 1, 15, 0x3fff, 0x7fff, 16, 64,
21398b9484cSchristos   floatformat_intbit_yes,
21498b9484cSchristos   "floatformat_i387_ext",
21598b9484cSchristos   floatformat_i387_ext_is_valid,
21698b9484cSchristos   NULL
21798b9484cSchristos };
21898b9484cSchristos const struct floatformat floatformat_m68881_ext =
21998b9484cSchristos {
22098b9484cSchristos   /* Note that the bits from 16 to 31 are unused.  */
22198b9484cSchristos   floatformat_big, 96, 0, 1, 15, 0x3fff, 0x7fff, 32, 64,
22298b9484cSchristos   floatformat_intbit_yes,
22398b9484cSchristos   "floatformat_m68881_ext",
22498b9484cSchristos   floatformat_always_valid,
22598b9484cSchristos   NULL
22698b9484cSchristos };
22798b9484cSchristos const struct floatformat floatformat_i960_ext =
22898b9484cSchristos {
22998b9484cSchristos   /* Note that the bits from 0 to 15 are unused.  */
23098b9484cSchristos   floatformat_little, 96, 16, 17, 15, 0x3fff, 0x7fff, 32, 64,
23198b9484cSchristos   floatformat_intbit_yes,
23298b9484cSchristos   "floatformat_i960_ext",
23398b9484cSchristos   floatformat_always_valid,
23498b9484cSchristos   NULL
23598b9484cSchristos };
23698b9484cSchristos const struct floatformat floatformat_m88110_ext =
23798b9484cSchristos {
23898b9484cSchristos   floatformat_big, 80, 0, 1, 15, 0x3fff, 0x7fff, 16, 64,
23998b9484cSchristos   floatformat_intbit_yes,
24098b9484cSchristos   "floatformat_m88110_ext",
24198b9484cSchristos   floatformat_always_valid,
24298b9484cSchristos   NULL
24398b9484cSchristos };
24498b9484cSchristos const struct floatformat floatformat_m88110_harris_ext =
24598b9484cSchristos {
24698b9484cSchristos   /* Harris uses raw format 128 bytes long, but the number is just an ieee
24798b9484cSchristos      double, and the last 64 bits are wasted. */
24898b9484cSchristos   floatformat_big,128, 0, 1, 11,  0x3ff,  0x7ff, 12, 52,
24998b9484cSchristos   floatformat_intbit_no,
25098b9484cSchristos   "floatformat_m88110_ext_harris",
25198b9484cSchristos   floatformat_always_valid,
25298b9484cSchristos   NULL
25398b9484cSchristos };
25498b9484cSchristos const struct floatformat floatformat_arm_ext_big =
25598b9484cSchristos {
25698b9484cSchristos   /* Bits 1 to 16 are unused.  */
25798b9484cSchristos   floatformat_big, 96, 0, 17, 15, 0x3fff, 0x7fff, 32, 64,
25898b9484cSchristos   floatformat_intbit_yes,
25998b9484cSchristos   "floatformat_arm_ext_big",
26098b9484cSchristos   floatformat_always_valid,
26198b9484cSchristos   NULL
26298b9484cSchristos };
26398b9484cSchristos const struct floatformat floatformat_arm_ext_littlebyte_bigword =
26498b9484cSchristos {
26598b9484cSchristos   /* Bits 1 to 16 are unused.  */
26698b9484cSchristos   floatformat_littlebyte_bigword, 96, 0, 17, 15, 0x3fff, 0x7fff, 32, 64,
26798b9484cSchristos   floatformat_intbit_yes,
26898b9484cSchristos   "floatformat_arm_ext_littlebyte_bigword",
26998b9484cSchristos   floatformat_always_valid,
27098b9484cSchristos   NULL
27198b9484cSchristos };
27298b9484cSchristos const struct floatformat floatformat_ia64_spill_big =
27398b9484cSchristos {
27498b9484cSchristos   floatformat_big, 128, 0, 1, 17, 65535, 0x1ffff, 18, 64,
27598b9484cSchristos   floatformat_intbit_yes,
27698b9484cSchristos   "floatformat_ia64_spill_big",
27798b9484cSchristos   floatformat_always_valid,
27898b9484cSchristos   NULL
27998b9484cSchristos };
28098b9484cSchristos const struct floatformat floatformat_ia64_spill_little =
28198b9484cSchristos {
28298b9484cSchristos   floatformat_little, 128, 0, 1, 17, 65535, 0x1ffff, 18, 64,
28398b9484cSchristos   floatformat_intbit_yes,
28498b9484cSchristos   "floatformat_ia64_spill_little",
28598b9484cSchristos   floatformat_always_valid,
28698b9484cSchristos   NULL
28798b9484cSchristos };
28898b9484cSchristos 
28998b9484cSchristos static int
29098b9484cSchristos floatformat_ibm_long_double_is_valid (const struct floatformat *fmt,
29198b9484cSchristos 				      const void *from)
29298b9484cSchristos {
29398b9484cSchristos   const unsigned char *ufrom = (const unsigned char *) from;
29498b9484cSchristos   const struct floatformat *hfmt = fmt->split_half;
29598b9484cSchristos   long top_exp, bot_exp;
29698b9484cSchristos   int top_nan = 0;
29798b9484cSchristos 
29898b9484cSchristos   top_exp = get_field (ufrom, hfmt->byteorder, hfmt->totalsize,
29998b9484cSchristos 		       hfmt->exp_start, hfmt->exp_len);
30098b9484cSchristos   bot_exp = get_field (ufrom + 8, hfmt->byteorder, hfmt->totalsize,
30198b9484cSchristos 		       hfmt->exp_start, hfmt->exp_len);
30298b9484cSchristos 
30398b9484cSchristos   if ((unsigned long) top_exp == hfmt->exp_nan)
30498b9484cSchristos     top_nan = mant_bits_set (hfmt, ufrom);
30598b9484cSchristos 
30698b9484cSchristos   /* A NaN is valid with any low part.  */
30798b9484cSchristos   if (top_nan)
30898b9484cSchristos     return 1;
30998b9484cSchristos 
31098b9484cSchristos   /* An infinity, zero or denormal requires low part 0 (positive or
31198b9484cSchristos      negative).  */
31298b9484cSchristos   if ((unsigned long) top_exp == hfmt->exp_nan || top_exp == 0)
31398b9484cSchristos     {
31498b9484cSchristos       if (bot_exp != 0)
31598b9484cSchristos 	return 0;
31698b9484cSchristos 
31798b9484cSchristos       return !mant_bits_set (hfmt, ufrom + 8);
31898b9484cSchristos     }
31998b9484cSchristos 
32098b9484cSchristos   /* The top part is now a finite normal value.  The long double value
32198b9484cSchristos      is the sum of the two parts, and the top part must equal the
32298b9484cSchristos      result of rounding the long double value to nearest double.  Thus
32398b9484cSchristos      the bottom part must be <= 0.5ulp of the top part in absolute
32498b9484cSchristos      value, and if it is < 0.5ulp then the long double is definitely
32598b9484cSchristos      valid.  */
32698b9484cSchristos   if (bot_exp < top_exp - 53)
32798b9484cSchristos     return 1;
32898b9484cSchristos   if (bot_exp > top_exp - 53 && bot_exp != 0)
32998b9484cSchristos     return 0;
33098b9484cSchristos   if (bot_exp == 0)
33198b9484cSchristos     {
33298b9484cSchristos       /* The bottom part is 0 or denormal.  Determine which, and if
33398b9484cSchristos 	 denormal the first two set bits.  */
33498b9484cSchristos       int first_bit = -1, second_bit = -1, cur_bit;
33598b9484cSchristos       for (cur_bit = 0; (unsigned int) cur_bit < hfmt->man_len; cur_bit++)
33698b9484cSchristos 	if (get_field (ufrom + 8, hfmt->byteorder, hfmt->totalsize,
33798b9484cSchristos 		       hfmt->man_start + cur_bit, 1))
33898b9484cSchristos 	  {
33998b9484cSchristos 	    if (first_bit == -1)
34098b9484cSchristos 	      first_bit = cur_bit;
34198b9484cSchristos 	    else
34298b9484cSchristos 	      {
34398b9484cSchristos 		second_bit = cur_bit;
34498b9484cSchristos 		break;
34598b9484cSchristos 	      }
34698b9484cSchristos 	  }
34798b9484cSchristos       /* Bottom part 0 is OK.  */
34898b9484cSchristos       if (first_bit == -1)
34998b9484cSchristos 	return 1;
35098b9484cSchristos       /* The real exponent of the bottom part is -first_bit.  */
35198b9484cSchristos       if (-first_bit < top_exp - 53)
35298b9484cSchristos 	return 1;
35398b9484cSchristos       if (-first_bit > top_exp - 53)
35498b9484cSchristos 	return 0;
35598b9484cSchristos       /* The bottom part is at least 0.5ulp of the top part.  For this
35698b9484cSchristos 	 to be OK, the bottom part must be exactly 0.5ulp (i.e. no
35798b9484cSchristos 	 more bits set) and the top part must have last bit 0.  */
35898b9484cSchristos       if (second_bit != -1)
35998b9484cSchristos 	return 0;
36098b9484cSchristos       return !get_field (ufrom, hfmt->byteorder, hfmt->totalsize,
36198b9484cSchristos 			 hfmt->man_start + hfmt->man_len - 1, 1);
36298b9484cSchristos     }
36398b9484cSchristos   else
36498b9484cSchristos     {
36598b9484cSchristos       /* The bottom part is at least 0.5ulp of the top part.  For this
36698b9484cSchristos 	 to be OK, it must be exactly 0.5ulp (i.e. no explicit bits
36798b9484cSchristos 	 set) and the top part must have last bit 0.  */
36898b9484cSchristos       if (get_field (ufrom, hfmt->byteorder, hfmt->totalsize,
36998b9484cSchristos 		     hfmt->man_start + hfmt->man_len - 1, 1))
37098b9484cSchristos 	return 0;
37198b9484cSchristos       return !mant_bits_set (hfmt, ufrom + 8);
37298b9484cSchristos     }
37398b9484cSchristos }
37498b9484cSchristos 
37503467a24Schristos const struct floatformat floatformat_ibm_long_double_big =
37698b9484cSchristos {
37798b9484cSchristos   floatformat_big, 128, 0, 1, 11, 1023, 2047, 12, 52,
37898b9484cSchristos   floatformat_intbit_no,
37903467a24Schristos   "floatformat_ibm_long_double_big",
38098b9484cSchristos   floatformat_ibm_long_double_is_valid,
38198b9484cSchristos   &floatformat_ieee_double_big
38298b9484cSchristos };
38303467a24Schristos 
38403467a24Schristos const struct floatformat floatformat_ibm_long_double_little =
38503467a24Schristos {
38603467a24Schristos   floatformat_little, 128, 0, 1, 11, 1023, 2047, 12, 52,
38703467a24Schristos   floatformat_intbit_no,
38803467a24Schristos   "floatformat_ibm_long_double_little",
38903467a24Schristos   floatformat_ibm_long_double_is_valid,
39003467a24Schristos   &floatformat_ieee_double_little
39103467a24Schristos };
3928dffb485Schristos 
3938dffb485Schristos const struct floatformat floatformat_bfloat16_big =
3948dffb485Schristos {
3958dffb485Schristos   floatformat_big, 16, 0, 1, 8, 127, 255, 9, 7,
3968dffb485Schristos   floatformat_intbit_no,
3978dffb485Schristos   "floatformat_bfloat16_big",
3988dffb485Schristos   floatformat_always_valid,
3998dffb485Schristos   NULL
4008dffb485Schristos };
4018dffb485Schristos 
4028dffb485Schristos const struct floatformat floatformat_bfloat16_little =
4038dffb485Schristos {
4048dffb485Schristos   floatformat_little, 16, 0, 1, 8, 127, 255, 9, 7,
4058dffb485Schristos   floatformat_intbit_no,
4068dffb485Schristos   "floatformat_bfloat16_little",
4078dffb485Schristos   floatformat_always_valid,
4088dffb485Schristos   NULL
4098dffb485Schristos };
41098b9484cSchristos 
41198b9484cSchristos #ifndef min
41298b9484cSchristos #define min(a, b) ((a) < (b) ? (a) : (b))
41398b9484cSchristos #endif
41498b9484cSchristos 
41598b9484cSchristos /* Return 1 if any bits are explicitly set in the mantissa of UFROM,
41698b9484cSchristos    format FMT, 0 otherwise.  */
41798b9484cSchristos static int
41898b9484cSchristos mant_bits_set (const struct floatformat *fmt, const unsigned char *ufrom)
41998b9484cSchristos {
42098b9484cSchristos   unsigned int mant_bits, mant_off;
42198b9484cSchristos   int mant_bits_left;
42298b9484cSchristos 
42398b9484cSchristos   mant_off = fmt->man_start;
42498b9484cSchristos   mant_bits_left = fmt->man_len;
42598b9484cSchristos   while (mant_bits_left > 0)
42698b9484cSchristos     {
42798b9484cSchristos       mant_bits = min (mant_bits_left, 32);
42898b9484cSchristos 
42998b9484cSchristos       if (get_field (ufrom, fmt->byteorder, fmt->totalsize,
43098b9484cSchristos 		     mant_off, mant_bits) != 0)
43198b9484cSchristos 	return 1;
43298b9484cSchristos 
43398b9484cSchristos       mant_off += mant_bits;
43498b9484cSchristos       mant_bits_left -= mant_bits;
43598b9484cSchristos     }
43698b9484cSchristos   return 0;
43798b9484cSchristos }
43898b9484cSchristos 
43998b9484cSchristos /* Extract a field which starts at START and is LEN bits long.  DATA and
44098b9484cSchristos    TOTAL_LEN are the thing we are extracting it from, in byteorder ORDER.  */
44198b9484cSchristos static unsigned long
44298b9484cSchristos get_field (const unsigned char *data, enum floatformat_byteorders order,
44398b9484cSchristos            unsigned int total_len, unsigned int start, unsigned int len)
44498b9484cSchristos {
44598b9484cSchristos   unsigned long result = 0;
44698b9484cSchristos   unsigned int cur_byte;
44798b9484cSchristos   int lo_bit, hi_bit, cur_bitshift = 0;
44898b9484cSchristos   int nextbyte = (order == floatformat_little) ? 1 : -1;
44998b9484cSchristos 
45098b9484cSchristos   /* Start is in big-endian bit order!  Fix that first.  */
45198b9484cSchristos   start = total_len - (start + len);
45298b9484cSchristos 
45398b9484cSchristos   /* Start at the least significant part of the field.  */
45498b9484cSchristos   if (order == floatformat_little)
45598b9484cSchristos     cur_byte = start / FLOATFORMAT_CHAR_BIT;
45698b9484cSchristos   else
45798b9484cSchristos     cur_byte = (total_len - start - 1) / FLOATFORMAT_CHAR_BIT;
45898b9484cSchristos 
45998b9484cSchristos   lo_bit = start % FLOATFORMAT_CHAR_BIT;
46098b9484cSchristos   hi_bit = min (lo_bit + len, FLOATFORMAT_CHAR_BIT);
46198b9484cSchristos 
46298b9484cSchristos   do
46398b9484cSchristos     {
46498b9484cSchristos       unsigned int shifted = *(data + cur_byte) >> lo_bit;
46598b9484cSchristos       unsigned int bits = hi_bit - lo_bit;
46698b9484cSchristos       unsigned int mask = (1 << bits) - 1;
46798b9484cSchristos       result |= (shifted & mask) << cur_bitshift;
46898b9484cSchristos       len -= bits;
46998b9484cSchristos       cur_bitshift += bits;
47098b9484cSchristos       cur_byte += nextbyte;
47198b9484cSchristos       lo_bit = 0;
47298b9484cSchristos       hi_bit = min (len, FLOATFORMAT_CHAR_BIT);
47398b9484cSchristos     }
47498b9484cSchristos   while (len != 0);
47598b9484cSchristos 
47698b9484cSchristos   return result;
47798b9484cSchristos }
47898b9484cSchristos 
47998b9484cSchristos /* Convert from FMT to a double.
48098b9484cSchristos    FROM is the address of the extended float.
48198b9484cSchristos    Store the double in *TO.  */
48298b9484cSchristos 
48398b9484cSchristos void
48498b9484cSchristos floatformat_to_double (const struct floatformat *fmt,
48598b9484cSchristos                        const void *from, double *to)
48698b9484cSchristos {
48798b9484cSchristos   const unsigned char *ufrom = (const unsigned char *) from;
48898b9484cSchristos   double dto;
48998b9484cSchristos   long exponent;
49098b9484cSchristos   unsigned long mant;
49198b9484cSchristos   unsigned int mant_bits, mant_off;
49298b9484cSchristos   int mant_bits_left;
49398b9484cSchristos 
49498b9484cSchristos   /* Split values are not handled specially, since the top half has
49598b9484cSchristos      the correctly rounded double value (in the only supported case of
49698b9484cSchristos      split values).  */
49798b9484cSchristos 
49898b9484cSchristos   exponent = get_field (ufrom, fmt->byteorder, fmt->totalsize,
49998b9484cSchristos 			fmt->exp_start, fmt->exp_len);
50098b9484cSchristos 
50198b9484cSchristos   /* If the exponent indicates a NaN, we don't have information to
50298b9484cSchristos      decide what to do.  So we handle it like IEEE, except that we
50398b9484cSchristos      don't try to preserve the type of NaN.  FIXME.  */
50498b9484cSchristos   if ((unsigned long) exponent == fmt->exp_nan)
50598b9484cSchristos     {
50698b9484cSchristos       int nan = mant_bits_set (fmt, ufrom);
50798b9484cSchristos 
50898b9484cSchristos       /* On certain systems (such as GNU/Linux), the use of the
50998b9484cSchristos 	 INFINITY macro below may generate a warning that cannot be
51098b9484cSchristos 	 silenced due to a bug in GCC (PR preprocessor/11931).  The
51198b9484cSchristos 	 preprocessor fails to recognise the __extension__ keyword in
51298b9484cSchristos 	 conjunction with the GNU/C99 extension for hexadecimal
51398b9484cSchristos 	 floating point constants and will issue a warning when
51498b9484cSchristos 	 compiling with -pedantic.  */
51598b9484cSchristos       if (nan)
51698b9484cSchristos 	dto = NAN;
51798b9484cSchristos       else
51898b9484cSchristos 	dto = INFINITY;
51998b9484cSchristos 
52098b9484cSchristos       if (get_field (ufrom, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1))
52198b9484cSchristos 	dto = -dto;
52298b9484cSchristos 
52398b9484cSchristos       *to = dto;
52498b9484cSchristos 
52598b9484cSchristos       return;
52698b9484cSchristos     }
52798b9484cSchristos 
52898b9484cSchristos   mant_bits_left = fmt->man_len;
52998b9484cSchristos   mant_off = fmt->man_start;
53098b9484cSchristos   dto = 0.0;
53198b9484cSchristos 
53298b9484cSchristos   /* Build the result algebraically.  Might go infinite, underflow, etc;
53398b9484cSchristos      who cares. */
53498b9484cSchristos 
535a2e2270fSchristos   /* For denorms use minimum exponent.  */
536a2e2270fSchristos   if (exponent == 0)
537a2e2270fSchristos     exponent = 1 - fmt->exp_bias;
538a2e2270fSchristos   else
53998b9484cSchristos     {
540a2e2270fSchristos       exponent -= fmt->exp_bias;
541a2e2270fSchristos 
542a2e2270fSchristos       /* If this format uses a hidden bit, explicitly add it in now.
543a2e2270fSchristos 	 Otherwise, increment the exponent by one to account for the
544a2e2270fSchristos 	 integer bit.  */
545a2e2270fSchristos 
54698b9484cSchristos       if (fmt->intbit == floatformat_intbit_no)
54798b9484cSchristos 	dto = ldexp (1.0, exponent);
54898b9484cSchristos       else
54998b9484cSchristos 	exponent++;
55098b9484cSchristos     }
55198b9484cSchristos 
55298b9484cSchristos   while (mant_bits_left > 0)
55398b9484cSchristos     {
55498b9484cSchristos       mant_bits = min (mant_bits_left, 32);
55598b9484cSchristos 
55698b9484cSchristos       mant = get_field (ufrom, fmt->byteorder, fmt->totalsize,
55798b9484cSchristos 			 mant_off, mant_bits);
55898b9484cSchristos 
55998b9484cSchristos       dto += ldexp ((double) mant, exponent - mant_bits);
56098b9484cSchristos       exponent -= mant_bits;
56198b9484cSchristos       mant_off += mant_bits;
56298b9484cSchristos       mant_bits_left -= mant_bits;
56398b9484cSchristos     }
56498b9484cSchristos 
56598b9484cSchristos   /* Negate it if negative.  */
56698b9484cSchristos   if (get_field (ufrom, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1))
56798b9484cSchristos     dto = -dto;
56898b9484cSchristos   *to = dto;
56998b9484cSchristos }
57098b9484cSchristos 
57198b9484cSchristos static void put_field (unsigned char *, enum floatformat_byteorders,
57298b9484cSchristos                        unsigned int,
57398b9484cSchristos                        unsigned int,
57498b9484cSchristos                        unsigned int,
57598b9484cSchristos                        unsigned long);
57698b9484cSchristos 
57798b9484cSchristos /* Set a field which starts at START and is LEN bits long.  DATA and
57898b9484cSchristos    TOTAL_LEN are the thing we are extracting it from, in byteorder ORDER.  */
57998b9484cSchristos static void
58098b9484cSchristos put_field (unsigned char *data, enum floatformat_byteorders order,
58198b9484cSchristos            unsigned int total_len, unsigned int start, unsigned int len,
58298b9484cSchristos            unsigned long stuff_to_put)
58398b9484cSchristos {
58498b9484cSchristos   unsigned int cur_byte;
58598b9484cSchristos   int lo_bit, hi_bit;
58698b9484cSchristos   int nextbyte = (order == floatformat_little) ? 1 : -1;
58798b9484cSchristos 
58898b9484cSchristos   /* Start is in big-endian bit order!  Fix that first.  */
58998b9484cSchristos   start = total_len - (start + len);
59098b9484cSchristos 
59198b9484cSchristos   /* Start at the least significant part of the field.  */
59298b9484cSchristos   if (order == floatformat_little)
59398b9484cSchristos     cur_byte = start / FLOATFORMAT_CHAR_BIT;
59498b9484cSchristos   else
59598b9484cSchristos     cur_byte = (total_len - start - 1) / FLOATFORMAT_CHAR_BIT;
59698b9484cSchristos 
59798b9484cSchristos   lo_bit = start % FLOATFORMAT_CHAR_BIT;
59898b9484cSchristos   hi_bit = min (lo_bit + len, FLOATFORMAT_CHAR_BIT);
59998b9484cSchristos 
60098b9484cSchristos   do
60198b9484cSchristos     {
60298b9484cSchristos       unsigned char *byte_ptr = data + cur_byte;
60398b9484cSchristos       unsigned int bits = hi_bit - lo_bit;
60498b9484cSchristos       unsigned int mask = ((1 << bits) - 1) << lo_bit;
60598b9484cSchristos       *byte_ptr = (*byte_ptr & ~mask) | ((stuff_to_put << lo_bit) & mask);
60698b9484cSchristos       stuff_to_put >>= bits;
60798b9484cSchristos       len -= bits;
60898b9484cSchristos       cur_byte += nextbyte;
60998b9484cSchristos       lo_bit = 0;
61098b9484cSchristos       hi_bit = min (len, FLOATFORMAT_CHAR_BIT);
61198b9484cSchristos     }
61298b9484cSchristos   while (len != 0);
61398b9484cSchristos }
61498b9484cSchristos 
61598b9484cSchristos /* The converse: convert the double *FROM to an extended float
61698b9484cSchristos    and store where TO points.  Neither FROM nor TO have any alignment
61798b9484cSchristos    restrictions.  */
61898b9484cSchristos 
61998b9484cSchristos void
62098b9484cSchristos floatformat_from_double (const struct floatformat *fmt,
62198b9484cSchristos                          const double *from, void *to)
62298b9484cSchristos {
62398b9484cSchristos   double dfrom;
62498b9484cSchristos   int exponent;
62598b9484cSchristos   double mant;
62698b9484cSchristos   unsigned int mant_bits, mant_off;
62798b9484cSchristos   int mant_bits_left;
62898b9484cSchristos   unsigned char *uto = (unsigned char *) to;
62998b9484cSchristos 
63098b9484cSchristos   dfrom = *from;
63198b9484cSchristos   memset (uto, 0, fmt->totalsize / FLOATFORMAT_CHAR_BIT);
63298b9484cSchristos 
63398b9484cSchristos   /* Split values are not handled specially, since a bottom half of
63498b9484cSchristos      zero is correct for any value representable as double (in the
63598b9484cSchristos      only supported case of split values).  */
63698b9484cSchristos 
63798b9484cSchristos   /* If negative, set the sign bit.  */
63898b9484cSchristos   if (dfrom < 0)
63998b9484cSchristos     {
64098b9484cSchristos       put_field (uto, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1, 1);
64198b9484cSchristos       dfrom = -dfrom;
64298b9484cSchristos     }
64398b9484cSchristos 
64498b9484cSchristos   if (dfrom == 0)
64598b9484cSchristos     {
64698b9484cSchristos       /* 0.0.  */
64798b9484cSchristos       return;
64898b9484cSchristos     }
64998b9484cSchristos 
65098b9484cSchristos   if (dfrom != dfrom)
65198b9484cSchristos     {
65298b9484cSchristos       /* NaN.  */
65398b9484cSchristos       put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start,
65498b9484cSchristos 		 fmt->exp_len, fmt->exp_nan);
65598b9484cSchristos       /* Be sure it's not infinity, but NaN value is irrelevant.  */
65698b9484cSchristos       put_field (uto, fmt->byteorder, fmt->totalsize, fmt->man_start,
65798b9484cSchristos 		 32, 1);
65898b9484cSchristos       return;
65998b9484cSchristos     }
66098b9484cSchristos 
66198b9484cSchristos   if (dfrom + dfrom == dfrom)
66298b9484cSchristos     {
66398b9484cSchristos       /* This can only happen for an infinite value (or zero, which we
66498b9484cSchristos 	 already handled above).  */
66598b9484cSchristos       put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start,
66698b9484cSchristos 		 fmt->exp_len, fmt->exp_nan);
66798b9484cSchristos       return;
66898b9484cSchristos     }
66998b9484cSchristos 
67098b9484cSchristos   mant = frexp (dfrom, &exponent);
67198b9484cSchristos   if (exponent + fmt->exp_bias - 1 > 0)
67298b9484cSchristos     put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start,
67398b9484cSchristos 	       fmt->exp_len, exponent + fmt->exp_bias - 1);
67498b9484cSchristos   else
67598b9484cSchristos     {
67698b9484cSchristos       /* Handle a denormalized number.  FIXME: What should we do for
67798b9484cSchristos 	 non-IEEE formats?  */
67898b9484cSchristos       put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start,
67998b9484cSchristos 		 fmt->exp_len, 0);
68098b9484cSchristos       mant = ldexp (mant, exponent + fmt->exp_bias - 1);
68198b9484cSchristos     }
68298b9484cSchristos 
68398b9484cSchristos   mant_bits_left = fmt->man_len;
68498b9484cSchristos   mant_off = fmt->man_start;
68598b9484cSchristos   while (mant_bits_left > 0)
68698b9484cSchristos     {
68798b9484cSchristos       unsigned long mant_long;
68898b9484cSchristos       mant_bits = mant_bits_left < 32 ? mant_bits_left : 32;
68998b9484cSchristos 
69098b9484cSchristos       mant *= 4294967296.0;
69198b9484cSchristos       mant_long = (unsigned long)mant;
69298b9484cSchristos       mant -= mant_long;
69398b9484cSchristos 
69498b9484cSchristos       /* If the integer bit is implicit, and we are not creating a
69598b9484cSchristos 	 denormalized number, then we need to discard it.  */
69698b9484cSchristos       if ((unsigned int) mant_bits_left == fmt->man_len
69798b9484cSchristos 	  && fmt->intbit == floatformat_intbit_no
69898b9484cSchristos 	  && exponent + fmt->exp_bias - 1 > 0)
69998b9484cSchristos 	{
70098b9484cSchristos 	  mant_long &= 0x7fffffff;
70198b9484cSchristos 	  mant_bits -= 1;
70298b9484cSchristos 	}
70398b9484cSchristos       else if (mant_bits < 32)
70498b9484cSchristos 	{
70598b9484cSchristos 	  /* The bits we want are in the most significant MANT_BITS bits of
70698b9484cSchristos 	     mant_long.  Move them to the least significant.  */
70798b9484cSchristos 	  mant_long >>= 32 - mant_bits;
70898b9484cSchristos 	}
70998b9484cSchristos 
71098b9484cSchristos       put_field (uto, fmt->byteorder, fmt->totalsize,
71198b9484cSchristos 		 mant_off, mant_bits, mant_long);
71298b9484cSchristos       mant_off += mant_bits;
71398b9484cSchristos       mant_bits_left -= mant_bits;
71498b9484cSchristos     }
71598b9484cSchristos }
71698b9484cSchristos 
71798b9484cSchristos /* Return non-zero iff the data at FROM is a valid number in format FMT.  */
71898b9484cSchristos 
71998b9484cSchristos int
72098b9484cSchristos floatformat_is_valid (const struct floatformat *fmt, const void *from)
72198b9484cSchristos {
72298b9484cSchristos   return fmt->is_valid (fmt, from);
72398b9484cSchristos }
72498b9484cSchristos 
72598b9484cSchristos 
72698b9484cSchristos #ifdef IEEE_DEBUG
72798b9484cSchristos 
72898b9484cSchristos #include <stdio.h>
72998b9484cSchristos 
73098b9484cSchristos /* This is to be run on a host which uses IEEE floating point.  */
73198b9484cSchristos 
73298b9484cSchristos void
73398b9484cSchristos ieee_test (double n)
73498b9484cSchristos {
73598b9484cSchristos   double result;
73698b9484cSchristos 
73798b9484cSchristos   floatformat_to_double (&floatformat_ieee_double_little, &n, &result);
73898b9484cSchristos   if ((n != result && (! isnan (n) || ! isnan (result)))
73998b9484cSchristos       || (n < 0 && result >= 0)
74098b9484cSchristos       || (n >= 0 && result < 0))
74198b9484cSchristos     printf ("Differ(to): %.20g -> %.20g\n", n, result);
74298b9484cSchristos 
74398b9484cSchristos   floatformat_from_double (&floatformat_ieee_double_little, &n, &result);
74498b9484cSchristos   if ((n != result && (! isnan (n) || ! isnan (result)))
74598b9484cSchristos       || (n < 0 && result >= 0)
74698b9484cSchristos       || (n >= 0 && result < 0))
74798b9484cSchristos     printf ("Differ(from): %.20g -> %.20g\n", n, result);
74898b9484cSchristos 
74998b9484cSchristos #if 0
75098b9484cSchristos   {
75198b9484cSchristos     char exten[16];
75298b9484cSchristos 
75398b9484cSchristos     floatformat_from_double (&floatformat_m68881_ext, &n, exten);
75498b9484cSchristos     floatformat_to_double (&floatformat_m68881_ext, exten, &result);
75598b9484cSchristos     if (n != result)
75698b9484cSchristos       printf ("Differ(to+from): %.20g -> %.20g\n", n, result);
75798b9484cSchristos   }
75898b9484cSchristos #endif
75998b9484cSchristos 
76098b9484cSchristos #if IEEE_DEBUG > 1
76198b9484cSchristos   /* This is to be run on a host which uses 68881 format.  */
76298b9484cSchristos   {
76398b9484cSchristos     long double ex = *(long double *)exten;
76498b9484cSchristos     if (ex != n)
76598b9484cSchristos       printf ("Differ(from vs. extended): %.20g\n", n);
76698b9484cSchristos   }
76798b9484cSchristos #endif
76898b9484cSchristos }
76998b9484cSchristos 
77098b9484cSchristos int
77198b9484cSchristos main (void)
77298b9484cSchristos {
77398b9484cSchristos   ieee_test (0.0);
77498b9484cSchristos   ieee_test (0.5);
775a2e2270fSchristos   ieee_test (1.1);
77698b9484cSchristos   ieee_test (256.0);
77798b9484cSchristos   ieee_test (0.12345);
77898b9484cSchristos   ieee_test (234235.78907234);
77998b9484cSchristos   ieee_test (-512.0);
78098b9484cSchristos   ieee_test (-0.004321);
78198b9484cSchristos   ieee_test (1.2E-70);
78298b9484cSchristos   ieee_test (1.2E-316);
78398b9484cSchristos   ieee_test (4.9406564584124654E-324);
78498b9484cSchristos   ieee_test (- 4.9406564584124654E-324);
78598b9484cSchristos   ieee_test (- 0.0);
78698b9484cSchristos   ieee_test (- INFINITY);
78798b9484cSchristos   ieee_test (- NAN);
78898b9484cSchristos   ieee_test (INFINITY);
78998b9484cSchristos   ieee_test (NAN);
79098b9484cSchristos   return 0;
79198b9484cSchristos }
79298b9484cSchristos #endif
793