133965Sjdp/* IEEE floating point support routines, for GDB, the GNU Debugger. 2218822Sdim Copyright 1991, 1994, 1999, 2000, 2003, 2005, 2006 3218822Sdim Free Software Foundation, Inc. 433965Sjdp 533965SjdpThis file is part of GDB. 633965Sjdp 733965SjdpThis program is free software; you can redistribute it and/or modify 833965Sjdpit under the terms of the GNU General Public License as published by 933965Sjdpthe Free Software Foundation; either version 2 of the License, or 1033965Sjdp(at your option) any later version. 1133965Sjdp 1233965SjdpThis program is distributed in the hope that it will be useful, 1333965Sjdpbut WITHOUT ANY WARRANTY; without even the implied warranty of 1433965SjdpMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1533965SjdpGNU General Public License for more details. 1633965Sjdp 1733965SjdpYou should have received a copy of the GNU General Public License 1833965Sjdpalong with this program; if not, write to the Free Software 19218822SdimFoundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ 2033965Sjdp 21130561Sobrien/* This is needed to pick up the NAN macro on some systems. */ 22130561Sobrien#define _GNU_SOURCE 23130561Sobrien 24130561Sobrien#ifdef HAVE_CONFIG_H 25130561Sobrien#include "config.h" 26130561Sobrien#endif 27130561Sobrien 28130561Sobrien#include <math.h> 29130561Sobrien 30130561Sobrien#ifdef HAVE_STRING_H 31130561Sobrien#include <string.h> 32130561Sobrien#endif 33130561Sobrien 34218822Sdim/* On some platforms, <float.h> provides DBL_QNAN. */ 35218822Sdim#ifdef STDC_HEADERS 36218822Sdim#include <float.h> 37218822Sdim#endif 38218822Sdim 39130561Sobrien#include "ansidecl.h" 40130561Sobrien#include "libiberty.h" 4133965Sjdp#include "floatformat.h" 42130561Sobrien 43130561Sobrien#ifndef INFINITY 44130561Sobrien#ifdef HUGE_VAL 45130561Sobrien#define INFINITY HUGE_VAL 4633965Sjdp#else 47130561Sobrien#define INFINITY (1.0 / 0.0) 4833965Sjdp#endif 49130561Sobrien#endif 5033965Sjdp 51130561Sobrien#ifndef NAN 52218822Sdim#ifdef DBL_QNAN 53218822Sdim#define NAN DBL_QNAN 54218822Sdim#else 55130561Sobrien#define NAN (0.0 / 0.0) 56130561Sobrien#endif 57218822Sdim#endif 58130561Sobrien 59218822Sdimstatic unsigned long get_field (const unsigned char *, 60218822Sdim enum floatformat_byteorders, 61218822Sdim unsigned int, 62218822Sdim unsigned int, 63218822Sdim unsigned int); 64218822Sdimstatic int floatformat_always_valid (const struct floatformat *fmt, 65218822Sdim const void *from); 66130561Sobrien 67130561Sobrienstatic int 68218822Sdimfloatformat_always_valid (const struct floatformat *fmt ATTRIBUTE_UNUSED, 69218822Sdim const void *from ATTRIBUTE_UNUSED) 70130561Sobrien{ 71130561Sobrien return 1; 72130561Sobrien} 73130561Sobrien 7433965Sjdp/* The odds that CHAR_BIT will be anything but 8 are low enough that I'm not 7533965Sjdp going to bother with trying to muck around with whether it is defined in 7633965Sjdp a system header, what we do if not, etc. */ 7733965Sjdp#define FLOATFORMAT_CHAR_BIT 8 7833965Sjdp 7933965Sjdp/* floatformats for IEEE single and double, big and little endian. */ 8033965Sjdpconst struct floatformat floatformat_ieee_single_big = 8133965Sjdp{ 8277298Sobrien floatformat_big, 32, 0, 1, 8, 127, 255, 9, 23, 8377298Sobrien floatformat_intbit_no, 84130561Sobrien "floatformat_ieee_single_big", 85130561Sobrien floatformat_always_valid 8633965Sjdp}; 8733965Sjdpconst struct floatformat floatformat_ieee_single_little = 8833965Sjdp{ 8977298Sobrien floatformat_little, 32, 0, 1, 8, 127, 255, 9, 23, 9077298Sobrien floatformat_intbit_no, 91130561Sobrien "floatformat_ieee_single_little", 92130561Sobrien floatformat_always_valid 9333965Sjdp}; 9433965Sjdpconst struct floatformat floatformat_ieee_double_big = 9533965Sjdp{ 9677298Sobrien floatformat_big, 64, 0, 1, 11, 1023, 2047, 12, 52, 9777298Sobrien floatformat_intbit_no, 98130561Sobrien "floatformat_ieee_double_big", 99130561Sobrien floatformat_always_valid 10033965Sjdp}; 10133965Sjdpconst struct floatformat floatformat_ieee_double_little = 10233965Sjdp{ 10377298Sobrien floatformat_little, 64, 0, 1, 11, 1023, 2047, 12, 52, 10477298Sobrien floatformat_intbit_no, 105130561Sobrien "floatformat_ieee_double_little", 106130561Sobrien floatformat_always_valid 10733965Sjdp}; 10833965Sjdp 10938889Sjdp/* floatformat for IEEE double, little endian byte order, with big endian word 11038889Sjdp ordering, as on the ARM. */ 11138889Sjdp 11238889Sjdpconst struct floatformat floatformat_ieee_double_littlebyte_bigword = 11338889Sjdp{ 11477298Sobrien floatformat_littlebyte_bigword, 64, 0, 1, 11, 1023, 2047, 12, 52, 11577298Sobrien floatformat_intbit_no, 116130561Sobrien "floatformat_ieee_double_littlebyte_bigword", 117130561Sobrien floatformat_always_valid 11838889Sjdp}; 11938889Sjdp 120218822Sdim/* floatformat for VAX. Not quite IEEE, but close enough. */ 121130561Sobrien 122218822Sdimconst struct floatformat floatformat_vax_f = 123218822Sdim{ 124218822Sdim floatformat_vax, 32, 0, 1, 8, 129, 0, 9, 23, 125218822Sdim floatformat_intbit_no, 126218822Sdim "floatformat_vax_f", 127218822Sdim floatformat_always_valid 128218822Sdim}; 129218822Sdimconst struct floatformat floatformat_vax_d = 130218822Sdim{ 131218822Sdim floatformat_vax, 64, 0, 1, 8, 129, 0, 9, 55, 132218822Sdim floatformat_intbit_no, 133218822Sdim "floatformat_vax_d", 134218822Sdim floatformat_always_valid 135218822Sdim}; 136218822Sdimconst struct floatformat floatformat_vax_g = 137218822Sdim{ 138218822Sdim floatformat_vax, 64, 0, 1, 11, 1025, 0, 12, 52, 139218822Sdim floatformat_intbit_no, 140218822Sdim "floatformat_vax_g", 141218822Sdim floatformat_always_valid 142218822Sdim}; 143218822Sdim 144218822Sdimstatic int floatformat_i387_ext_is_valid (const struct floatformat *fmt, 145218822Sdim const void *from); 146218822Sdim 147130561Sobrienstatic int 148218822Sdimfloatformat_i387_ext_is_valid (const struct floatformat *fmt, const void *from) 149130561Sobrien{ 150130561Sobrien /* In the i387 double-extended format, if the exponent is all ones, 151130561Sobrien then the integer bit must be set. If the exponent is neither 0 152130561Sobrien nor ~0, the intbit must also be set. Only if the exponent is 153130561Sobrien zero can it be zero, and then it must be zero. */ 154130561Sobrien unsigned long exponent, int_bit; 155130561Sobrien const unsigned char *ufrom = (const unsigned char *) from; 156218822Sdim 157130561Sobrien exponent = get_field (ufrom, fmt->byteorder, fmt->totalsize, 158130561Sobrien fmt->exp_start, fmt->exp_len); 159130561Sobrien int_bit = get_field (ufrom, fmt->byteorder, fmt->totalsize, 160130561Sobrien fmt->man_start, 1); 161218822Sdim 162130561Sobrien if ((exponent == 0) != (int_bit == 0)) 163130561Sobrien return 0; 164130561Sobrien else 165130561Sobrien return 1; 166130561Sobrien} 167130561Sobrien 16833965Sjdpconst struct floatformat floatformat_i387_ext = 16933965Sjdp{ 17033965Sjdp floatformat_little, 80, 0, 1, 15, 0x3fff, 0x7fff, 16, 64, 17177298Sobrien floatformat_intbit_yes, 172130561Sobrien "floatformat_i387_ext", 173130561Sobrien floatformat_i387_ext_is_valid 17433965Sjdp}; 17533965Sjdpconst struct floatformat floatformat_m68881_ext = 17633965Sjdp{ 17733965Sjdp /* Note that the bits from 16 to 31 are unused. */ 17877298Sobrien floatformat_big, 96, 0, 1, 15, 0x3fff, 0x7fff, 32, 64, 17977298Sobrien floatformat_intbit_yes, 180130561Sobrien "floatformat_m68881_ext", 181130561Sobrien floatformat_always_valid 18233965Sjdp}; 18333965Sjdpconst struct floatformat floatformat_i960_ext = 18433965Sjdp{ 18533965Sjdp /* Note that the bits from 0 to 15 are unused. */ 18633965Sjdp floatformat_little, 96, 16, 17, 15, 0x3fff, 0x7fff, 32, 64, 18777298Sobrien floatformat_intbit_yes, 188130561Sobrien "floatformat_i960_ext", 189130561Sobrien floatformat_always_valid 19033965Sjdp}; 19133965Sjdpconst struct floatformat floatformat_m88110_ext = 19233965Sjdp{ 19389857Sobrien floatformat_big, 80, 0, 1, 15, 0x3fff, 0x7fff, 16, 64, 19489857Sobrien floatformat_intbit_yes, 195130561Sobrien "floatformat_m88110_ext", 196130561Sobrien floatformat_always_valid 19789857Sobrien}; 19889857Sobrienconst struct floatformat floatformat_m88110_harris_ext = 19989857Sobrien{ 20033965Sjdp /* Harris uses raw format 128 bytes long, but the number is just an ieee 20133965Sjdp double, and the last 64 bits are wasted. */ 20233965Sjdp floatformat_big,128, 0, 1, 11, 0x3ff, 0x7ff, 12, 52, 20377298Sobrien floatformat_intbit_no, 204130561Sobrien "floatformat_m88110_ext_harris", 205130561Sobrien floatformat_always_valid 20633965Sjdp}; 20789857Sobrienconst struct floatformat floatformat_arm_ext_big = 20889857Sobrien{ 20989857Sobrien /* Bits 1 to 16 are unused. */ 21089857Sobrien floatformat_big, 96, 0, 17, 15, 0x3fff, 0x7fff, 32, 64, 21189857Sobrien floatformat_intbit_yes, 212130561Sobrien "floatformat_arm_ext_big", 213130561Sobrien floatformat_always_valid 21489857Sobrien}; 21589857Sobrienconst struct floatformat floatformat_arm_ext_littlebyte_bigword = 21689857Sobrien{ 21789857Sobrien /* Bits 1 to 16 are unused. */ 21889857Sobrien floatformat_littlebyte_bigword, 96, 0, 17, 15, 0x3fff, 0x7fff, 32, 64, 21989857Sobrien floatformat_intbit_yes, 220130561Sobrien "floatformat_arm_ext_littlebyte_bigword", 221130561Sobrien floatformat_always_valid 22289857Sobrien}; 22389857Sobrienconst struct floatformat floatformat_ia64_spill_big = 22489857Sobrien{ 22589857Sobrien floatformat_big, 128, 0, 1, 17, 65535, 0x1ffff, 18, 64, 22689857Sobrien floatformat_intbit_yes, 227130561Sobrien "floatformat_ia64_spill_big", 228130561Sobrien floatformat_always_valid 22989857Sobrien}; 23089857Sobrienconst struct floatformat floatformat_ia64_spill_little = 23189857Sobrien{ 23289857Sobrien floatformat_little, 128, 0, 1, 17, 65535, 0x1ffff, 18, 64, 23389857Sobrien floatformat_intbit_yes, 234130561Sobrien "floatformat_ia64_spill_little", 235130561Sobrien floatformat_always_valid 23689857Sobrien}; 23789857Sobrienconst struct floatformat floatformat_ia64_quad_big = 23889857Sobrien{ 23989857Sobrien floatformat_big, 128, 0, 1, 15, 16383, 0x7fff, 16, 112, 24089857Sobrien floatformat_intbit_no, 241130561Sobrien "floatformat_ia64_quad_big", 242130561Sobrien floatformat_always_valid 24389857Sobrien}; 24489857Sobrienconst struct floatformat floatformat_ia64_quad_little = 24589857Sobrien{ 24689857Sobrien floatformat_little, 128, 0, 1, 15, 16383, 0x7fff, 16, 112, 24789857Sobrien floatformat_intbit_no, 248130561Sobrien "floatformat_ia64_quad_little", 249130561Sobrien floatformat_always_valid 25089857Sobrien}; 25133965Sjdp 252218822Sdim 253218822Sdim#ifndef min 254218822Sdim#define min(a, b) ((a) < (b) ? (a) : (b)) 255218822Sdim#endif 256218822Sdim 257130561Sobrien/* Extract a field which starts at START and is LEN bits long. DATA and 25833965Sjdp TOTAL_LEN are the thing we are extracting it from, in byteorder ORDER. */ 25933965Sjdpstatic unsigned long 260218822Sdimget_field (const unsigned char *data, enum floatformat_byteorders order, 261218822Sdim unsigned int total_len, unsigned int start, unsigned int len) 26233965Sjdp{ 263218822Sdim unsigned long result = 0; 26433965Sjdp unsigned int cur_byte; 265218822Sdim int lo_bit, hi_bit, cur_bitshift = 0; 266218822Sdim int nextbyte = (order == floatformat_little) ? 1 : -1; 26733965Sjdp 268218822Sdim /* Start is in big-endian bit order! Fix that first. */ 269218822Sdim start = total_len - (start + len); 270218822Sdim 27133965Sjdp /* Start at the least significant part of the field. */ 27233965Sjdp if (order == floatformat_little) 273218822Sdim cur_byte = start / FLOATFORMAT_CHAR_BIT; 27433965Sjdp else 275218822Sdim cur_byte = (total_len - start - 1) / FLOATFORMAT_CHAR_BIT; 27633965Sjdp 277218822Sdim lo_bit = start % FLOATFORMAT_CHAR_BIT; 278218822Sdim hi_bit = min (lo_bit + len, FLOATFORMAT_CHAR_BIT); 279218822Sdim 280218822Sdim do 28133965Sjdp { 282218822Sdim unsigned int shifted = *(data + cur_byte) >> lo_bit; 283218822Sdim unsigned int bits = hi_bit - lo_bit; 284218822Sdim unsigned int mask = (1 << bits) - 1; 285218822Sdim result |= (shifted & mask) << cur_bitshift; 286218822Sdim len -= bits; 287218822Sdim cur_bitshift += bits; 288218822Sdim cur_byte += nextbyte; 289218822Sdim lo_bit = 0; 290218822Sdim hi_bit = min (len, FLOATFORMAT_CHAR_BIT); 29133965Sjdp } 292218822Sdim while (len != 0); 293218822Sdim 29433965Sjdp return result; 29533965Sjdp} 29633965Sjdp 29733965Sjdp/* Convert from FMT to a double. 29833965Sjdp FROM is the address of the extended float. 29933965Sjdp Store the double in *TO. */ 30033965Sjdp 30133965Sjdpvoid 302218822Sdimfloatformat_to_double (const struct floatformat *fmt, 303218822Sdim const void *from, double *to) 30433965Sjdp{ 305218822Sdim const unsigned char *ufrom = (const unsigned char *) from; 30633965Sjdp double dto; 30733965Sjdp long exponent; 30833965Sjdp unsigned long mant; 30933965Sjdp unsigned int mant_bits, mant_off; 31033965Sjdp int mant_bits_left; 31133965Sjdp int special_exponent; /* It's a NaN, denorm or zero */ 31233965Sjdp 31333965Sjdp exponent = get_field (ufrom, fmt->byteorder, fmt->totalsize, 31433965Sjdp fmt->exp_start, fmt->exp_len); 31533965Sjdp 316130561Sobrien /* If the exponent indicates a NaN, we don't have information to 317130561Sobrien decide what to do. So we handle it like IEEE, except that we 318130561Sobrien don't try to preserve the type of NaN. FIXME. */ 319130561Sobrien if ((unsigned long) exponent == fmt->exp_nan) 320130561Sobrien { 321130561Sobrien int nan; 322130561Sobrien 323130561Sobrien mant_off = fmt->man_start; 324130561Sobrien mant_bits_left = fmt->man_len; 325130561Sobrien nan = 0; 326130561Sobrien while (mant_bits_left > 0) 327130561Sobrien { 328130561Sobrien mant_bits = min (mant_bits_left, 32); 329130561Sobrien 330130561Sobrien if (get_field (ufrom, fmt->byteorder, fmt->totalsize, 331130561Sobrien mant_off, mant_bits) != 0) 332130561Sobrien { 333130561Sobrien /* This is a NaN. */ 334130561Sobrien nan = 1; 335130561Sobrien break; 336130561Sobrien } 337130561Sobrien 338130561Sobrien mant_off += mant_bits; 339130561Sobrien mant_bits_left -= mant_bits; 340130561Sobrien } 341130561Sobrien 342218822Sdim /* On certain systems (such as GNU/Linux), the use of the 343218822Sdim INFINITY macro below may generate a warning that can not be 344218822Sdim silenced due to a bug in GCC (PR preprocessor/11931). The 345218822Sdim preprocessor fails to recognise the __extension__ keyword in 346218822Sdim conjunction with the GNU/C99 extension for hexadecimal 347218822Sdim floating point constants and will issue a warning when 348218822Sdim compiling with -pedantic. */ 349130561Sobrien if (nan) 350130561Sobrien dto = NAN; 351130561Sobrien else 352130561Sobrien dto = INFINITY; 353130561Sobrien 354130561Sobrien if (get_field (ufrom, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1)) 355130561Sobrien dto = -dto; 356130561Sobrien 357130561Sobrien *to = dto; 358130561Sobrien 359130561Sobrien return; 360130561Sobrien } 361130561Sobrien 36233965Sjdp mant_bits_left = fmt->man_len; 36333965Sjdp mant_off = fmt->man_start; 36433965Sjdp dto = 0.0; 36533965Sjdp 36660484Sobrien special_exponent = exponent == 0 || (unsigned long) exponent == fmt->exp_nan; 36733965Sjdp 36833965Sjdp /* Don't bias zero's, denorms or NaNs. */ 36933965Sjdp if (!special_exponent) 37033965Sjdp exponent -= fmt->exp_bias; 37133965Sjdp 37233965Sjdp /* Build the result algebraically. Might go infinite, underflow, etc; 37333965Sjdp who cares. */ 37433965Sjdp 37533965Sjdp /* If this format uses a hidden bit, explicitly add it in now. Otherwise, 37633965Sjdp increment the exponent by one to account for the integer bit. */ 37733965Sjdp 37833965Sjdp if (!special_exponent) 37960484Sobrien { 38060484Sobrien if (fmt->intbit == floatformat_intbit_no) 38160484Sobrien dto = ldexp (1.0, exponent); 38260484Sobrien else 38360484Sobrien exponent++; 38460484Sobrien } 38533965Sjdp 38633965Sjdp while (mant_bits_left > 0) 38733965Sjdp { 38833965Sjdp mant_bits = min (mant_bits_left, 32); 38933965Sjdp 39033965Sjdp mant = get_field (ufrom, fmt->byteorder, fmt->totalsize, 39133965Sjdp mant_off, mant_bits); 39233965Sjdp 393130561Sobrien /* Handle denormalized numbers. FIXME: What should we do for 394130561Sobrien non-IEEE formats? */ 395218822Sdim if (special_exponent && exponent == 0 && mant != 0) 396130561Sobrien dto += ldexp ((double)mant, 397130561Sobrien (- fmt->exp_bias 398130561Sobrien - mant_bits 399130561Sobrien - (mant_off - fmt->man_start) 400130561Sobrien + 1)); 401130561Sobrien else 402130561Sobrien dto += ldexp ((double)mant, exponent - mant_bits); 403130561Sobrien if (exponent != 0) 404130561Sobrien exponent -= mant_bits; 40533965Sjdp mant_off += mant_bits; 40633965Sjdp mant_bits_left -= mant_bits; 40733965Sjdp } 40833965Sjdp 40933965Sjdp /* Negate it if negative. */ 41033965Sjdp if (get_field (ufrom, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1)) 41133965Sjdp dto = -dto; 41233965Sjdp *to = dto; 41333965Sjdp} 41433965Sjdp 415218822Sdimstatic void put_field (unsigned char *, enum floatformat_byteorders, 416218822Sdim unsigned int, 417218822Sdim unsigned int, 418218822Sdim unsigned int, 419218822Sdim unsigned long); 42033965Sjdp 421130561Sobrien/* Set a field which starts at START and is LEN bits long. DATA and 42233965Sjdp TOTAL_LEN are the thing we are extracting it from, in byteorder ORDER. */ 42333965Sjdpstatic void 424218822Sdimput_field (unsigned char *data, enum floatformat_byteorders order, 425218822Sdim unsigned int total_len, unsigned int start, unsigned int len, 426218822Sdim unsigned long stuff_to_put) 42733965Sjdp{ 42833965Sjdp unsigned int cur_byte; 429218822Sdim int lo_bit, hi_bit; 430218822Sdim int nextbyte = (order == floatformat_little) ? 1 : -1; 43133965Sjdp 432218822Sdim /* Start is in big-endian bit order! Fix that first. */ 433218822Sdim start = total_len - (start + len); 434218822Sdim 43533965Sjdp /* Start at the least significant part of the field. */ 43633965Sjdp if (order == floatformat_little) 437218822Sdim cur_byte = start / FLOATFORMAT_CHAR_BIT; 43833965Sjdp else 439218822Sdim cur_byte = (total_len - start - 1) / FLOATFORMAT_CHAR_BIT; 44033965Sjdp 441218822Sdim lo_bit = start % FLOATFORMAT_CHAR_BIT; 442218822Sdim hi_bit = min (lo_bit + len, FLOATFORMAT_CHAR_BIT); 443218822Sdim 444218822Sdim do 44533965Sjdp { 446218822Sdim unsigned char *byte_ptr = data + cur_byte; 447218822Sdim unsigned int bits = hi_bit - lo_bit; 448218822Sdim unsigned int mask = ((1 << bits) - 1) << lo_bit; 449218822Sdim *byte_ptr = (*byte_ptr & ~mask) | ((stuff_to_put << lo_bit) & mask); 450218822Sdim stuff_to_put >>= bits; 451218822Sdim len -= bits; 452218822Sdim cur_byte += nextbyte; 453218822Sdim lo_bit = 0; 454218822Sdim hi_bit = min (len, FLOATFORMAT_CHAR_BIT); 45533965Sjdp } 456218822Sdim while (len != 0); 45733965Sjdp} 45833965Sjdp 45933965Sjdp/* The converse: convert the double *FROM to an extended float 46033965Sjdp and store where TO points. Neither FROM nor TO have any alignment 46133965Sjdp restrictions. */ 46233965Sjdp 46333965Sjdpvoid 464218822Sdimfloatformat_from_double (const struct floatformat *fmt, 465218822Sdim const double *from, void *to) 46633965Sjdp{ 46733965Sjdp double dfrom; 46833965Sjdp int exponent; 46933965Sjdp double mant; 47033965Sjdp unsigned int mant_bits, mant_off; 47133965Sjdp int mant_bits_left; 472218822Sdim unsigned char *uto = (unsigned char *) to; 47333965Sjdp 474130561Sobrien dfrom = *from; 47533965Sjdp memset (uto, 0, fmt->totalsize / FLOATFORMAT_CHAR_BIT); 476130561Sobrien 477130561Sobrien /* If negative, set the sign bit. */ 478130561Sobrien if (dfrom < 0) 479130561Sobrien { 480130561Sobrien put_field (uto, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1, 1); 481130561Sobrien dfrom = -dfrom; 482130561Sobrien } 483130561Sobrien 48433965Sjdp if (dfrom == 0) 485130561Sobrien { 486130561Sobrien /* 0.0. */ 487130561Sobrien return; 488130561Sobrien } 489130561Sobrien 49033965Sjdp if (dfrom != dfrom) 49133965Sjdp { 492130561Sobrien /* NaN. */ 49333965Sjdp put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start, 49433965Sjdp fmt->exp_len, fmt->exp_nan); 495130561Sobrien /* Be sure it's not infinity, but NaN value is irrelevant. */ 49633965Sjdp put_field (uto, fmt->byteorder, fmt->totalsize, fmt->man_start, 49733965Sjdp 32, 1); 49833965Sjdp return; 49933965Sjdp } 50033965Sjdp 501130561Sobrien if (dfrom + dfrom == dfrom) 50233965Sjdp { 503130561Sobrien /* This can only happen for an infinite value (or zero, which we 504130561Sobrien already handled above). */ 505130561Sobrien put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start, 506130561Sobrien fmt->exp_len, fmt->exp_nan); 507130561Sobrien return; 50833965Sjdp } 50933965Sjdp 51033965Sjdp mant = frexp (dfrom, &exponent); 511130561Sobrien if (exponent + fmt->exp_bias - 1 > 0) 512130561Sobrien put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start, 513130561Sobrien fmt->exp_len, exponent + fmt->exp_bias - 1); 514130561Sobrien else 515130561Sobrien { 516130561Sobrien /* Handle a denormalized number. FIXME: What should we do for 517130561Sobrien non-IEEE formats? */ 518130561Sobrien put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start, 519130561Sobrien fmt->exp_len, 0); 520130561Sobrien mant = ldexp (mant, exponent + fmt->exp_bias - 1); 521130561Sobrien } 52233965Sjdp 52333965Sjdp mant_bits_left = fmt->man_len; 52433965Sjdp mant_off = fmt->man_start; 52533965Sjdp while (mant_bits_left > 0) 52633965Sjdp { 52733965Sjdp unsigned long mant_long; 52833965Sjdp mant_bits = mant_bits_left < 32 ? mant_bits_left : 32; 52933965Sjdp 53033965Sjdp mant *= 4294967296.0; 53133965Sjdp mant_long = (unsigned long)mant; 53233965Sjdp mant -= mant_long; 53333965Sjdp 534130561Sobrien /* If the integer bit is implicit, and we are not creating a 535130561Sobrien denormalized number, then we need to discard it. */ 53660484Sobrien if ((unsigned int) mant_bits_left == fmt->man_len 537130561Sobrien && fmt->intbit == floatformat_intbit_no 538130561Sobrien && exponent + fmt->exp_bias - 1 > 0) 53933965Sjdp { 54033965Sjdp mant_long &= 0x7fffffff; 54133965Sjdp mant_bits -= 1; 54233965Sjdp } 54333965Sjdp else if (mant_bits < 32) 54433965Sjdp { 54533965Sjdp /* The bits we want are in the most significant MANT_BITS bits of 54633965Sjdp mant_long. Move them to the least significant. */ 54733965Sjdp mant_long >>= 32 - mant_bits; 54833965Sjdp } 54933965Sjdp 55033965Sjdp put_field (uto, fmt->byteorder, fmt->totalsize, 55133965Sjdp mant_off, mant_bits, mant_long); 55233965Sjdp mant_off += mant_bits; 55333965Sjdp mant_bits_left -= mant_bits; 55433965Sjdp } 55533965Sjdp} 55633965Sjdp 557130561Sobrien/* Return non-zero iff the data at FROM is a valid number in format FMT. */ 55833965Sjdp 559130561Sobrienint 560218822Sdimfloatformat_is_valid (const struct floatformat *fmt, const void *from) 561130561Sobrien{ 562130561Sobrien return fmt->is_valid (fmt, from); 563130561Sobrien} 564130561Sobrien 565130561Sobrien 56633965Sjdp#ifdef IEEE_DEBUG 56733965Sjdp 568130561Sobrien#include <stdio.h> 569130561Sobrien 57033965Sjdp/* This is to be run on a host which uses IEEE floating point. */ 57133965Sjdp 57233965Sjdpvoid 573218822Sdimieee_test (double n) 57433965Sjdp{ 57533965Sjdp double result; 57633965Sjdp 577218822Sdim floatformat_to_double (&floatformat_ieee_double_little, &n, &result); 578130561Sobrien if ((n != result && (! isnan (n) || ! isnan (result))) 579130561Sobrien || (n < 0 && result >= 0) 580130561Sobrien || (n >= 0 && result < 0)) 58133965Sjdp printf ("Differ(to): %.20g -> %.20g\n", n, result); 582130561Sobrien 583218822Sdim floatformat_from_double (&floatformat_ieee_double_little, &n, &result); 584130561Sobrien if ((n != result && (! isnan (n) || ! isnan (result))) 585130561Sobrien || (n < 0 && result >= 0) 586130561Sobrien || (n >= 0 && result < 0)) 58733965Sjdp printf ("Differ(from): %.20g -> %.20g\n", n, result); 58833965Sjdp 589130561Sobrien#if 0 590130561Sobrien { 591130561Sobrien char exten[16]; 59233965Sjdp 593130561Sobrien floatformat_from_double (&floatformat_m68881_ext, &n, exten); 594130561Sobrien floatformat_to_double (&floatformat_m68881_ext, exten, &result); 595130561Sobrien if (n != result) 596130561Sobrien printf ("Differ(to+from): %.20g -> %.20g\n", n, result); 597130561Sobrien } 598130561Sobrien#endif 599130561Sobrien 60033965Sjdp#if IEEE_DEBUG > 1 60133965Sjdp /* This is to be run on a host which uses 68881 format. */ 60233965Sjdp { 60333965Sjdp long double ex = *(long double *)exten; 60433965Sjdp if (ex != n) 60533965Sjdp printf ("Differ(from vs. extended): %.20g\n", n); 60633965Sjdp } 60733965Sjdp#endif 60833965Sjdp} 60933965Sjdp 61033965Sjdpint 611218822Sdimmain (void) 61233965Sjdp{ 613130561Sobrien ieee_test (0.0); 61433965Sjdp ieee_test (0.5); 61533965Sjdp ieee_test (256.0); 61633965Sjdp ieee_test (0.12345); 61733965Sjdp ieee_test (234235.78907234); 61833965Sjdp ieee_test (-512.0); 61933965Sjdp ieee_test (-0.004321); 620130561Sobrien ieee_test (1.2E-70); 621130561Sobrien ieee_test (1.2E-316); 622130561Sobrien ieee_test (4.9406564584124654E-324); 623130561Sobrien ieee_test (- 4.9406564584124654E-324); 624130561Sobrien ieee_test (- 0.0); 625130561Sobrien ieee_test (- INFINITY); 626130561Sobrien ieee_test (- NAN); 627130561Sobrien ieee_test (INFINITY); 628130561Sobrien ieee_test (NAN); 62933965Sjdp return 0; 63033965Sjdp} 63133965Sjdp#endif 632