Search
lxdream.org :: lxdream/src/xlat/disasm/floatformat.c :: diff
lxdream 0.9.1
released Jun 29
Download Now
filename src/xlat/disasm/floatformat.c
changeset 1265:7c6c5d26fd2e
author nkeynes
date Tue Mar 06 12:42:33 2012 +1000 (8 years ago)
permissions -rw-r--r--
last change Merge ARM disassembler from binutils 2.22
file annotate diff log raw
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/src/xlat/disasm/floatformat.c Tue Mar 06 12:42:33 2012 +1000
1.3 @@ -0,0 +1,771 @@
1.4 +/* IEEE floating point support routines, for GDB, the GNU Debugger.
1.5 + Copyright 1991, 1994, 1999, 2000, 2003, 2005, 2006, 2010
1.6 + Free Software Foundation, Inc.
1.7 +
1.8 +This file is part of GDB.
1.9 +
1.10 +This program is free software; you can redistribute it and/or modify
1.11 +it under the terms of the GNU General Public License as published by
1.12 +the Free Software Foundation; either version 2 of the License, or
1.13 +(at your option) any later version.
1.14 +
1.15 +This program is distributed in the hope that it will be useful,
1.16 +but WITHOUT ANY WARRANTY; without even the implied warranty of
1.17 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1.18 +GNU General Public License for more details.
1.19 +
1.20 +You should have received a copy of the GNU General Public License
1.21 +along with this program; if not, write to the Free Software
1.22 +Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
1.23 +
1.24 +#ifdef HAVE_CONFIG_H
1.25 +#include "config.h"
1.26 +#endif
1.27 +
1.28 +#include <math.h>
1.29 +
1.30 +#ifdef HAVE_STRING_H
1.31 +#include <string.h>
1.32 +#endif
1.33 +
1.34 +/* On some platforms, <float.h> provides DBL_QNAN. */
1.35 +#ifdef STDC_HEADERS
1.36 +#include <float.h>
1.37 +#endif
1.38 +
1.39 +#include "ansidecl.h"
1.40 +#include "floatformat.h"
1.41 +
1.42 +#ifndef INFINITY
1.43 +#ifdef HUGE_VAL
1.44 +#define INFINITY HUGE_VAL
1.45 +#else
1.46 +#define INFINITY (1.0 / 0.0)
1.47 +#endif
1.48 +#endif
1.49 +
1.50 +#ifndef NAN
1.51 +#ifdef DBL_QNAN
1.52 +#define NAN DBL_QNAN
1.53 +#else
1.54 +#define NAN (0.0 / 0.0)
1.55 +#endif
1.56 +#endif
1.57 +
1.58 +static int mant_bits_set (const struct floatformat *, const unsigned char *);
1.59 +static unsigned long get_field (const unsigned char *,
1.60 + enum floatformat_byteorders,
1.61 + unsigned int,
1.62 + unsigned int,
1.63 + unsigned int);
1.64 +static int floatformat_always_valid (const struct floatformat *fmt,
1.65 + const void *from);
1.66 +
1.67 +static int
1.68 +floatformat_always_valid (const struct floatformat *fmt ATTRIBUTE_UNUSED,
1.69 + const void *from ATTRIBUTE_UNUSED)
1.70 +{
1.71 + return 1;
1.72 +}
1.73 +
1.74 +/* The odds that CHAR_BIT will be anything but 8 are low enough that I'm not
1.75 + going to bother with trying to muck around with whether it is defined in
1.76 + a system header, what we do if not, etc. */
1.77 +#define FLOATFORMAT_CHAR_BIT 8
1.78 +
1.79 +/* floatformats for IEEE half, single and double, big and little endian. */
1.80 +const struct floatformat floatformat_ieee_half_big =
1.81 +{
1.82 + floatformat_big, 16, 0, 1, 5, 15, 31, 6, 10,
1.83 + floatformat_intbit_no,
1.84 + "floatformat_ieee_half_big",
1.85 + floatformat_always_valid,
1.86 + NULL
1.87 +};
1.88 +const struct floatformat floatformat_ieee_half_little =
1.89 +{
1.90 + floatformat_little, 16, 0, 1, 5, 15, 31, 6, 10,
1.91 + floatformat_intbit_no,
1.92 + "floatformat_ieee_half_little",
1.93 + floatformat_always_valid,
1.94 + NULL
1.95 +};
1.96 +const struct floatformat floatformat_ieee_single_big =
1.97 +{
1.98 + floatformat_big, 32, 0, 1, 8, 127, 255, 9, 23,
1.99 + floatformat_intbit_no,
1.100 + "floatformat_ieee_single_big",
1.101 + floatformat_always_valid,
1.102 + NULL
1.103 +};
1.104 +const struct floatformat floatformat_ieee_single_little =
1.105 +{
1.106 + floatformat_little, 32, 0, 1, 8, 127, 255, 9, 23,
1.107 + floatformat_intbit_no,
1.108 + "floatformat_ieee_single_little",
1.109 + floatformat_always_valid,
1.110 + NULL
1.111 +};
1.112 +const struct floatformat floatformat_ieee_double_big =
1.113 +{
1.114 + floatformat_big, 64, 0, 1, 11, 1023, 2047, 12, 52,
1.115 + floatformat_intbit_no,
1.116 + "floatformat_ieee_double_big",
1.117 + floatformat_always_valid,
1.118 + NULL
1.119 +};
1.120 +const struct floatformat floatformat_ieee_double_little =
1.121 +{
1.122 + floatformat_little, 64, 0, 1, 11, 1023, 2047, 12, 52,
1.123 + floatformat_intbit_no,
1.124 + "floatformat_ieee_double_little",
1.125 + floatformat_always_valid,
1.126 + NULL
1.127 +};
1.128 +
1.129 +/* floatformat for IEEE double, little endian byte order, with big endian word
1.130 + ordering, as on the ARM. */
1.131 +
1.132 +const struct floatformat floatformat_ieee_double_littlebyte_bigword =
1.133 +{
1.134 + floatformat_littlebyte_bigword, 64, 0, 1, 11, 1023, 2047, 12, 52,
1.135 + floatformat_intbit_no,
1.136 + "floatformat_ieee_double_littlebyte_bigword",
1.137 + floatformat_always_valid,
1.138 + NULL
1.139 +};
1.140 +
1.141 +/* floatformat for VAX. Not quite IEEE, but close enough. */
1.142 +
1.143 +const struct floatformat floatformat_vax_f =
1.144 +{
1.145 + floatformat_vax, 32, 0, 1, 8, 129, 0, 9, 23,
1.146 + floatformat_intbit_no,
1.147 + "floatformat_vax_f",
1.148 + floatformat_always_valid,
1.149 + NULL
1.150 +};
1.151 +const struct floatformat floatformat_vax_d =
1.152 +{
1.153 + floatformat_vax, 64, 0, 1, 8, 129, 0, 9, 55,
1.154 + floatformat_intbit_no,
1.155 + "floatformat_vax_d",
1.156 + floatformat_always_valid,
1.157 + NULL
1.158 +};
1.159 +const struct floatformat floatformat_vax_g =
1.160 +{
1.161 + floatformat_vax, 64, 0, 1, 11, 1025, 0, 12, 52,
1.162 + floatformat_intbit_no,
1.163 + "floatformat_vax_g",
1.164 + floatformat_always_valid,
1.165 + NULL
1.166 +};
1.167 +
1.168 +static int floatformat_i387_ext_is_valid (const struct floatformat *fmt,
1.169 + const void *from);
1.170 +
1.171 +static int
1.172 +floatformat_i387_ext_is_valid (const struct floatformat *fmt, const void *from)
1.173 +{
1.174 + /* In the i387 double-extended format, if the exponent is all ones,
1.175 + then the integer bit must be set. If the exponent is neither 0
1.176 + nor ~0, the intbit must also be set. Only if the exponent is
1.177 + zero can it be zero, and then it must be zero. */
1.178 + unsigned long exponent, int_bit;
1.179 + const unsigned char *ufrom = (const unsigned char *) from;
1.180 +
1.181 + exponent = get_field (ufrom, fmt->byteorder, fmt->totalsize,
1.182 + fmt->exp_start, fmt->exp_len);
1.183 + int_bit = get_field (ufrom, fmt->byteorder, fmt->totalsize,
1.184 + fmt->man_start, 1);
1.185 +
1.186 + if ((exponent == 0) != (int_bit == 0))
1.187 + return 0;
1.188 + else
1.189 + return 1;
1.190 +}
1.191 +
1.192 +const struct floatformat floatformat_i387_ext =
1.193 +{
1.194 + floatformat_little, 80, 0, 1, 15, 0x3fff, 0x7fff, 16, 64,
1.195 + floatformat_intbit_yes,
1.196 + "floatformat_i387_ext",
1.197 + floatformat_i387_ext_is_valid,
1.198 + NULL
1.199 +};
1.200 +const struct floatformat floatformat_m68881_ext =
1.201 +{
1.202 + /* Note that the bits from 16 to 31 are unused. */
1.203 + floatformat_big, 96, 0, 1, 15, 0x3fff, 0x7fff, 32, 64,
1.204 + floatformat_intbit_yes,
1.205 + "floatformat_m68881_ext",
1.206 + floatformat_always_valid,
1.207 + NULL
1.208 +};
1.209 +const struct floatformat floatformat_i960_ext =
1.210 +{
1.211 + /* Note that the bits from 0 to 15 are unused. */
1.212 + floatformat_little, 96, 16, 17, 15, 0x3fff, 0x7fff, 32, 64,
1.213 + floatformat_intbit_yes,
1.214 + "floatformat_i960_ext",
1.215 + floatformat_always_valid,
1.216 + NULL
1.217 +};
1.218 +const struct floatformat floatformat_m88110_ext =
1.219 +{
1.220 + floatformat_big, 80, 0, 1, 15, 0x3fff, 0x7fff, 16, 64,
1.221 + floatformat_intbit_yes,
1.222 + "floatformat_m88110_ext",
1.223 + floatformat_always_valid,
1.224 + NULL
1.225 +};
1.226 +const struct floatformat floatformat_m88110_harris_ext =
1.227 +{
1.228 + /* Harris uses raw format 128 bytes long, but the number is just an ieee
1.229 + double, and the last 64 bits are wasted. */
1.230 + floatformat_big,128, 0, 1, 11, 0x3ff, 0x7ff, 12, 52,
1.231 + floatformat_intbit_no,
1.232 + "floatformat_m88110_ext_harris",
1.233 + floatformat_always_valid,
1.234 + NULL
1.235 +};
1.236 +const struct floatformat floatformat_arm_ext_big =
1.237 +{
1.238 + /* Bits 1 to 16 are unused. */
1.239 + floatformat_big, 96, 0, 17, 15, 0x3fff, 0x7fff, 32, 64,
1.240 + floatformat_intbit_yes,
1.241 + "floatformat_arm_ext_big",
1.242 + floatformat_always_valid,
1.243 + NULL
1.244 +};
1.245 +const struct floatformat floatformat_arm_ext_littlebyte_bigword =
1.246 +{
1.247 + /* Bits 1 to 16 are unused. */
1.248 + floatformat_littlebyte_bigword, 96, 0, 17, 15, 0x3fff, 0x7fff, 32, 64,
1.249 + floatformat_intbit_yes,
1.250 + "floatformat_arm_ext_littlebyte_bigword",
1.251 + floatformat_always_valid,
1.252 + NULL
1.253 +};
1.254 +const struct floatformat floatformat_ia64_spill_big =
1.255 +{
1.256 + floatformat_big, 128, 0, 1, 17, 65535, 0x1ffff, 18, 64,
1.257 + floatformat_intbit_yes,
1.258 + "floatformat_ia64_spill_big",
1.259 + floatformat_always_valid,
1.260 + NULL
1.261 +};
1.262 +const struct floatformat floatformat_ia64_spill_little =
1.263 +{
1.264 + floatformat_little, 128, 0, 1, 17, 65535, 0x1ffff, 18, 64,
1.265 + floatformat_intbit_yes,
1.266 + "floatformat_ia64_spill_little",
1.267 + floatformat_always_valid,
1.268 + NULL
1.269 +};
1.270 +const struct floatformat floatformat_ia64_quad_big =
1.271 +{
1.272 + floatformat_big, 128, 0, 1, 15, 16383, 0x7fff, 16, 112,
1.273 + floatformat_intbit_no,
1.274 + "floatformat_ia64_quad_big",
1.275 + floatformat_always_valid,
1.276 + NULL
1.277 +};
1.278 +const struct floatformat floatformat_ia64_quad_little =
1.279 +{
1.280 + floatformat_little, 128, 0, 1, 15, 16383, 0x7fff, 16, 112,
1.281 + floatformat_intbit_no,
1.282 + "floatformat_ia64_quad_little",
1.283 + floatformat_always_valid,
1.284 + NULL
1.285 +};
1.286 +
1.287 +static int
1.288 +floatformat_ibm_long_double_is_valid (const struct floatformat *fmt,
1.289 + const void *from)
1.290 +{
1.291 + const unsigned char *ufrom = (const unsigned char *) from;
1.292 + const struct floatformat *hfmt = fmt->split_half;
1.293 + long top_exp, bot_exp;
1.294 + int top_nan = 0;
1.295 +
1.296 + top_exp = get_field (ufrom, hfmt->byteorder, hfmt->totalsize,
1.297 + hfmt->exp_start, hfmt->exp_len);
1.298 + bot_exp = get_field (ufrom + 8, hfmt->byteorder, hfmt->totalsize,
1.299 + hfmt->exp_start, hfmt->exp_len);
1.300 +
1.301 + if ((unsigned long) top_exp == hfmt->exp_nan)
1.302 + top_nan = mant_bits_set (hfmt, ufrom);
1.303 +
1.304 + /* A NaN is valid with any low part. */
1.305 + if (top_nan)
1.306 + return 1;
1.307 +
1.308 + /* An infinity, zero or denormal requires low part 0 (positive or
1.309 + negative). */
1.310 + if ((unsigned long) top_exp == hfmt->exp_nan || top_exp == 0)
1.311 + {
1.312 + if (bot_exp != 0)
1.313 + return 0;
1.314 +
1.315 + return !mant_bits_set (hfmt, ufrom + 8);
1.316 + }
1.317 +
1.318 + /* The top part is now a finite normal value. The long double value
1.319 + is the sum of the two parts, and the top part must equal the
1.320 + result of rounding the long double value to nearest double. Thus
1.321 + the bottom part must be <= 0.5ulp of the top part in absolute
1.322 + value, and if it is < 0.5ulp then the long double is definitely
1.323 + valid. */
1.324 + if (bot_exp < top_exp - 53)
1.325 + return 1;
1.326 + if (bot_exp > top_exp - 53 && bot_exp != 0)
1.327 + return 0;
1.328 + if (bot_exp == 0)
1.329 + {
1.330 + /* The bottom part is 0 or denormal. Determine which, and if
1.331 + denormal the first two set bits. */
1.332 + int first_bit = -1, second_bit = -1, cur_bit;
1.333 + for (cur_bit = 0; (unsigned int) cur_bit < hfmt->man_len; cur_bit++)
1.334 + if (get_field (ufrom + 8, hfmt->byteorder, hfmt->totalsize,
1.335 + hfmt->man_start + cur_bit, 1))
1.336 + {
1.337 + if (first_bit == -1)
1.338 + first_bit = cur_bit;
1.339 + else
1.340 + {
1.341 + second_bit = cur_bit;
1.342 + break;
1.343 + }
1.344 + }
1.345 + /* Bottom part 0 is OK. */
1.346 + if (first_bit == -1)
1.347 + return 1;
1.348 + /* The real exponent of the bottom part is -first_bit. */
1.349 + if (-first_bit < top_exp - 53)
1.350 + return 1;
1.351 + if (-first_bit > top_exp - 53)
1.352 + return 0;
1.353 + /* The bottom part is at least 0.5ulp of the top part. For this
1.354 + to be OK, the bottom part must be exactly 0.5ulp (i.e. no
1.355 + more bits set) and the top part must have last bit 0. */
1.356 + if (second_bit != -1)
1.357 + return 0;
1.358 + return !get_field (ufrom, hfmt->byteorder, hfmt->totalsize,
1.359 + hfmt->man_start + hfmt->man_len - 1, 1);
1.360 + }
1.361 + else
1.362 + {
1.363 + /* The bottom part is at least 0.5ulp of the top part. For this
1.364 + to be OK, it must be exactly 0.5ulp (i.e. no explicit bits
1.365 + set) and the top part must have last bit 0. */
1.366 + if (get_field (ufrom, hfmt->byteorder, hfmt->totalsize,
1.367 + hfmt->man_start + hfmt->man_len - 1, 1))
1.368 + return 0;
1.369 + return !mant_bits_set (hfmt, ufrom + 8);
1.370 + }
1.371 +}
1.372 +
1.373 +const struct floatformat floatformat_ibm_long_double =
1.374 +{
1.375 + floatformat_big, 128, 0, 1, 11, 1023, 2047, 12, 52,
1.376 + floatformat_intbit_no,
1.377 + "floatformat_ibm_long_double",
1.378 + floatformat_ibm_long_double_is_valid,
1.379 + &floatformat_ieee_double_big
1.380 +};
1.381 +
1.382 +
1.383 +#ifndef min
1.384 +#define min(a, b) ((a) < (b) ? (a) : (b))
1.385 +#endif
1.386 +
1.387 +/* Return 1 if any bits are explicitly set in the mantissa of UFROM,
1.388 + format FMT, 0 otherwise. */
1.389 +static int
1.390 +mant_bits_set (const struct floatformat *fmt, const unsigned char *ufrom)
1.391 +{
1.392 + unsigned int mant_bits, mant_off;
1.393 + int mant_bits_left;
1.394 +
1.395 + mant_off = fmt->man_start;
1.396 + mant_bits_left = fmt->man_len;
1.397 + while (mant_bits_left > 0)
1.398 + {
1.399 + mant_bits = min (mant_bits_left, 32);
1.400 +
1.401 + if (get_field (ufrom, fmt->byteorder, fmt->totalsize,
1.402 + mant_off, mant_bits) != 0)
1.403 + return 1;
1.404 +
1.405 + mant_off += mant_bits;
1.406 + mant_bits_left -= mant_bits;
1.407 + }
1.408 + return 0;
1.409 +}
1.410 +
1.411 +/* Extract a field which starts at START and is LEN bits long. DATA and
1.412 + TOTAL_LEN are the thing we are extracting it from, in byteorder ORDER. */
1.413 +static unsigned long
1.414 +get_field (const unsigned char *data, enum floatformat_byteorders order,
1.415 + unsigned int total_len, unsigned int start, unsigned int len)
1.416 +{
1.417 + unsigned long result = 0;
1.418 + unsigned int cur_byte;
1.419 + int lo_bit, hi_bit, cur_bitshift = 0;
1.420 + int nextbyte = (order == floatformat_little) ? 1 : -1;
1.421 +
1.422 + /* Start is in big-endian bit order! Fix that first. */
1.423 + start = total_len - (start + len);
1.424 +
1.425 + /* Start at the least significant part of the field. */
1.426 + if (order == floatformat_little)
1.427 + cur_byte = start / FLOATFORMAT_CHAR_BIT;
1.428 + else
1.429 + cur_byte = (total_len - start - 1) / FLOATFORMAT_CHAR_BIT;
1.430 +
1.431 + lo_bit = start % FLOATFORMAT_CHAR_BIT;
1.432 + hi_bit = min (lo_bit + len, FLOATFORMAT_CHAR_BIT);
1.433 +
1.434 + do
1.435 + {
1.436 + unsigned int shifted = *(data + cur_byte) >> lo_bit;
1.437 + unsigned int bits = hi_bit - lo_bit;
1.438 + unsigned int mask = (1 << bits) - 1;
1.439 + result |= (shifted & mask) << cur_bitshift;
1.440 + len -= bits;
1.441 + cur_bitshift += bits;
1.442 + cur_byte += nextbyte;
1.443 + lo_bit = 0;
1.444 + hi_bit = min (len, FLOATFORMAT_CHAR_BIT);
1.445 + }
1.446 + while (len != 0);
1.447 +
1.448 + return result;
1.449 +}
1.450 +
1.451 +/* Convert from FMT to a double.
1.452 + FROM is the address of the extended float.
1.453 + Store the double in *TO. */
1.454 +
1.455 +void
1.456 +floatformat_to_double (const struct floatformat *fmt,
1.457 + const void *from, double *to)
1.458 +{
1.459 + const unsigned char *ufrom = (const unsigned char *) from;
1.460 + double dto;
1.461 + long exponent;
1.462 + unsigned long mant;
1.463 + unsigned int mant_bits, mant_off;
1.464 + int mant_bits_left;
1.465 + int special_exponent; /* It's a NaN, denorm or zero */
1.466 +
1.467 + /* Split values are not handled specially, since the top half has
1.468 + the correctly rounded double value (in the only supported case of
1.469 + split values). */
1.470 +
1.471 + exponent = get_field (ufrom, fmt->byteorder, fmt->totalsize,
1.472 + fmt->exp_start, fmt->exp_len);
1.473 +
1.474 + /* If the exponent indicates a NaN, we don't have information to
1.475 + decide what to do. So we handle it like IEEE, except that we
1.476 + don't try to preserve the type of NaN. FIXME. */
1.477 + if ((unsigned long) exponent == fmt->exp_nan)
1.478 + {
1.479 + int nan = mant_bits_set (fmt, ufrom);
1.480 +
1.481 + /* On certain systems (such as GNU/Linux), the use of the
1.482 + INFINITY macro below may generate a warning that can not be
1.483 + silenced due to a bug in GCC (PR preprocessor/11931). The
1.484 + preprocessor fails to recognise the __extension__ keyword in
1.485 + conjunction with the GNU/C99 extension for hexadecimal
1.486 + floating point constants and will issue a warning when
1.487 + compiling with -pedantic. */
1.488 + if (nan)
1.489 + dto = NAN;
1.490 + else
1.491 + dto = INFINITY;
1.492 +
1.493 + if (get_field (ufrom, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1))
1.494 + dto = -dto;
1.495 +
1.496 + *to = dto;
1.497 +
1.498 + return;
1.499 + }
1.500 +
1.501 + mant_bits_left = fmt->man_len;
1.502 + mant_off = fmt->man_start;
1.503 + dto = 0.0;
1.504 +
1.505 + special_exponent = exponent == 0 || (unsigned long) exponent == fmt->exp_nan;
1.506 +
1.507 + /* Don't bias zero's, denorms or NaNs. */
1.508 + if (!special_exponent)
1.509 + exponent -= fmt->exp_bias;
1.510 +
1.511 + /* Build the result algebraically. Might go infinite, underflow, etc;
1.512 + who cares. */
1.513 +
1.514 + /* If this format uses a hidden bit, explicitly add it in now. Otherwise,
1.515 + increment the exponent by one to account for the integer bit. */
1.516 +
1.517 + if (!special_exponent)
1.518 + {
1.519 + if (fmt->intbit == floatformat_intbit_no)
1.520 + dto = ldexp (1.0, exponent);
1.521 + else
1.522 + exponent++;
1.523 + }
1.524 +
1.525 + while (mant_bits_left > 0)
1.526 + {
1.527 + mant_bits = min (mant_bits_left, 32);
1.528 +
1.529 + mant = get_field (ufrom, fmt->byteorder, fmt->totalsize,
1.530 + mant_off, mant_bits);
1.531 +
1.532 + /* Handle denormalized numbers. FIXME: What should we do for
1.533 + non-IEEE formats? */
1.534 + if (special_exponent && exponent == 0 && mant != 0)
1.535 + dto += ldexp ((double)mant,
1.536 + (- fmt->exp_bias
1.537 + - mant_bits
1.538 + - (mant_off - fmt->man_start)
1.539 + + 1));
1.540 + else
1.541 + dto += ldexp ((double)mant, exponent - mant_bits);
1.542 + if (exponent != 0)
1.543 + exponent -= mant_bits;
1.544 + mant_off += mant_bits;
1.545 + mant_bits_left -= mant_bits;
1.546 + }
1.547 +
1.548 + /* Negate it if negative. */
1.549 + if (get_field (ufrom, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1))
1.550 + dto = -dto;
1.551 + *to = dto;
1.552 +}
1.553 +
1.554 +static void put_field (unsigned char *, enum floatformat_byteorders,
1.555 + unsigned int,
1.556 + unsigned int,
1.557 + unsigned int,
1.558 + unsigned long);
1.559 +
1.560 +/* Set a field which starts at START and is LEN bits long. DATA and
1.561 + TOTAL_LEN are the thing we are extracting it from, in byteorder ORDER. */
1.562 +static void
1.563 +put_field (unsigned char *data, enum floatformat_byteorders order,
1.564 + unsigned int total_len, unsigned int start, unsigned int len,
1.565 + unsigned long stuff_to_put)
1.566 +{
1.567 + unsigned int cur_byte;
1.568 + int lo_bit, hi_bit;
1.569 + int nextbyte = (order == floatformat_little) ? 1 : -1;
1.570 +
1.571 + /* Start is in big-endian bit order! Fix that first. */
1.572 + start = total_len - (start + len);
1.573 +
1.574 + /* Start at the least significant part of the field. */
1.575 + if (order == floatformat_little)
1.576 + cur_byte = start / FLOATFORMAT_CHAR_BIT;
1.577 + else
1.578 + cur_byte = (total_len - start - 1) / FLOATFORMAT_CHAR_BIT;
1.579 +
1.580 + lo_bit = start % FLOATFORMAT_CHAR_BIT;
1.581 + hi_bit = min (lo_bit + len, FLOATFORMAT_CHAR_BIT);
1.582 +
1.583 + do
1.584 + {
1.585 + unsigned char *byte_ptr = data + cur_byte;
1.586 + unsigned int bits = hi_bit - lo_bit;
1.587 + unsigned int mask = ((1 << bits) - 1) << lo_bit;
1.588 + *byte_ptr = (*byte_ptr & ~mask) | ((stuff_to_put << lo_bit) & mask);
1.589 + stuff_to_put >>= bits;
1.590 + len -= bits;
1.591 + cur_byte += nextbyte;
1.592 + lo_bit = 0;
1.593 + hi_bit = min (len, FLOATFORMAT_CHAR_BIT);
1.594 + }
1.595 + while (len != 0);
1.596 +}
1.597 +
1.598 +/* The converse: convert the double *FROM to an extended float
1.599 + and store where TO points. Neither FROM nor TO have any alignment
1.600 + restrictions. */
1.601 +
1.602 +void
1.603 +floatformat_from_double (const struct floatformat *fmt,
1.604 + const double *from, void *to)
1.605 +{
1.606 + double dfrom;
1.607 + int exponent;
1.608 + double mant;
1.609 + unsigned int mant_bits, mant_off;
1.610 + int mant_bits_left;
1.611 + unsigned char *uto = (unsigned char *) to;
1.612 +
1.613 + dfrom = *from;
1.614 + memset (uto, 0, fmt->totalsize / FLOATFORMAT_CHAR_BIT);
1.615 +
1.616 + /* Split values are not handled specially, since a bottom half of
1.617 + zero is correct for any value representable as double (in the
1.618 + only supported case of split values). */
1.619 +
1.620 + /* If negative, set the sign bit. */
1.621 + if (dfrom < 0)
1.622 + {
1.623 + put_field (uto, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1, 1);
1.624 + dfrom = -dfrom;
1.625 + }
1.626 +
1.627 + if (dfrom == 0)
1.628 + {
1.629 + /* 0.0. */
1.630 + return;
1.631 + }
1.632 +
1.633 + if (dfrom != dfrom)
1.634 + {
1.635 + /* NaN. */
1.636 + put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start,
1.637 + fmt->exp_len, fmt->exp_nan);
1.638 + /* Be sure it's not infinity, but NaN value is irrelevant. */
1.639 + put_field (uto, fmt->byteorder, fmt->totalsize, fmt->man_start,
1.640 + 32, 1);
1.641 + return;
1.642 + }
1.643 +
1.644 + if (dfrom + dfrom == dfrom)
1.645 + {
1.646 + /* This can only happen for an infinite value (or zero, which we
1.647 + already handled above). */
1.648 + put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start,
1.649 + fmt->exp_len, fmt->exp_nan);
1.650 + return;
1.651 + }
1.652 +
1.653 + mant = frexp (dfrom, &exponent);
1.654 + if (exponent + fmt->exp_bias - 1 > 0)
1.655 + put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start,
1.656 + fmt->exp_len, exponent + fmt->exp_bias - 1);
1.657 + else
1.658 + {
1.659 + /* Handle a denormalized number. FIXME: What should we do for
1.660 + non-IEEE formats? */
1.661 + put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start,
1.662 + fmt->exp_len, 0);
1.663 + mant = ldexp (mant, exponent + fmt->exp_bias - 1);
1.664 + }
1.665 +
1.666 + mant_bits_left = fmt->man_len;
1.667 + mant_off = fmt->man_start;
1.668 + while (mant_bits_left > 0)
1.669 + {
1.670 + unsigned long mant_long;
1.671 + mant_bits = mant_bits_left < 32 ? mant_bits_left : 32;
1.672 +
1.673 + mant *= 4294967296.0;
1.674 + mant_long = (unsigned long)mant;
1.675 + mant -= mant_long;
1.676 +
1.677 + /* If the integer bit is implicit, and we are not creating a
1.678 + denormalized number, then we need to discard it. */
1.679 + if ((unsigned int) mant_bits_left == fmt->man_len
1.680 + && fmt->intbit == floatformat_intbit_no
1.681 + && exponent + fmt->exp_bias - 1 > 0)
1.682 + {
1.683 + mant_long &= 0x7fffffff;
1.684 + mant_bits -= 1;
1.685 + }
1.686 + else if (mant_bits < 32)
1.687 + {
1.688 + /* The bits we want are in the most significant MANT_BITS bits of
1.689 + mant_long. Move them to the least significant. */
1.690 + mant_long >>= 32 - mant_bits;
1.691 + }
1.692 +
1.693 + put_field (uto, fmt->byteorder, fmt->totalsize,
1.694 + mant_off, mant_bits, mant_long);
1.695 + mant_off += mant_bits;
1.696 + mant_bits_left -= mant_bits;
1.697 + }
1.698 +}
1.699 +
1.700 +/* Return non-zero iff the data at FROM is a valid number in format FMT. */
1.701 +
1.702 +int
1.703 +floatformat_is_valid (const struct floatformat *fmt, const void *from)
1.704 +{
1.705 + return fmt->is_valid (fmt, from);
1.706 +}
1.707 +
1.708 +
1.709 +#ifdef IEEE_DEBUG
1.710 +
1.711 +#include <stdio.h>
1.712 +
1.713 +/* This is to be run on a host which uses IEEE floating point. */
1.714 +
1.715 +void
1.716 +ieee_test (double n)
1.717 +{
1.718 + double result;
1.719 +
1.720 + floatformat_to_double (&floatformat_ieee_double_little, &n, &result);
1.721 + if ((n != result && (! isnan (n) || ! isnan (result)))
1.722 + || (n < 0 && result >= 0)
1.723 + || (n >= 0 && result < 0))
1.724 + printf ("Differ(to): %.20g -> %.20g\n", n, result);
1.725 +
1.726 + floatformat_from_double (&floatformat_ieee_double_little, &n, &result);
1.727 + if ((n != result && (! isnan (n) || ! isnan (result)))
1.728 + || (n < 0 && result >= 0)
1.729 + || (n >= 0 && result < 0))
1.730 + printf ("Differ(from): %.20g -> %.20g\n", n, result);
1.731 +
1.732 +#if 0
1.733 + {
1.734 + char exten[16];
1.735 +
1.736 + floatformat_from_double (&floatformat_m68881_ext, &n, exten);
1.737 + floatformat_to_double (&floatformat_m68881_ext, exten, &result);
1.738 + if (n != result)
1.739 + printf ("Differ(to+from): %.20g -> %.20g\n", n, result);
1.740 + }
1.741 +#endif
1.742 +
1.743 +#if IEEE_DEBUG > 1
1.744 + /* This is to be run on a host which uses 68881 format. */
1.745 + {
1.746 + long double ex = *(long double *)exten;
1.747 + if (ex != n)
1.748 + printf ("Differ(from vs. extended): %.20g\n", n);
1.749 + }
1.750 +#endif
1.751 +}
1.752 +
1.753 +int
1.754 +main (void)
1.755 +{
1.756 + ieee_test (0.0);
1.757 + ieee_test (0.5);
1.758 + ieee_test (256.0);
1.759 + ieee_test (0.12345);
1.760 + ieee_test (234235.78907234);
1.761 + ieee_test (-512.0);
1.762 + ieee_test (-0.004321);
1.763 + ieee_test (1.2E-70);
1.764 + ieee_test (1.2E-316);
1.765 + ieee_test (4.9406564584124654E-324);
1.766 + ieee_test (- 4.9406564584124654E-324);
1.767 + ieee_test (- 0.0);
1.768 + ieee_test (- INFINITY);
1.769 + ieee_test (- NAN);
1.770 + ieee_test (INFINITY);
1.771 + ieee_test (NAN);
1.772 + return 0;
1.773 +}
1.774 +#endif
.