floatformat.c revision 89857
1/* IEEE floating point support routines, for GDB, the GNU Debugger. 2 Copyright (C) 1991, 1994, 1999, 2000 Free Software Foundation, Inc. 3 4This file is part of GDB. 5 6This program is free software; you can redistribute it and/or modify 7it under the terms of the GNU General Public License as published by 8the Free Software Foundation; either version 2 of the License, or 9(at your option) any later version. 10 11This program is distributed in the hope that it will be useful, 12but WITHOUT ANY WARRANTY; without even the implied warranty of 13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14GNU General Public License for more details. 15 16You should have received a copy of the GNU General Public License 17along with this program; if not, write to the Free Software 18Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ 19 20#include "floatformat.h" 21#include <math.h> /* ldexp */ 22#ifdef __STDC__ 23#include <stddef.h> 24extern void *memcpy (void *s1, const void *s2, size_t n); 25extern void *memset (void *s, int c, size_t n); 26#else 27extern char *memcpy (); 28extern char *memset (); 29#endif 30 31/* The odds that CHAR_BIT will be anything but 8 are low enough that I'm not 32 going to bother with trying to muck around with whether it is defined in 33 a system header, what we do if not, etc. */ 34#define FLOATFORMAT_CHAR_BIT 8 35 36/* floatformats for IEEE single and double, big and little endian. */ 37const struct floatformat floatformat_ieee_single_big = 38{ 39 floatformat_big, 32, 0, 1, 8, 127, 255, 9, 23, 40 floatformat_intbit_no, 41 "floatformat_ieee_single_big" 42}; 43const struct floatformat floatformat_ieee_single_little = 44{ 45 floatformat_little, 32, 0, 1, 8, 127, 255, 9, 23, 46 floatformat_intbit_no, 47 "floatformat_ieee_single_little" 48}; 49const struct floatformat floatformat_ieee_double_big = 50{ 51 floatformat_big, 64, 0, 1, 11, 1023, 2047, 12, 52, 52 floatformat_intbit_no, 53 "floatformat_ieee_double_big" 54}; 55const struct floatformat floatformat_ieee_double_little = 56{ 57 floatformat_little, 64, 0, 1, 11, 1023, 2047, 12, 52, 58 floatformat_intbit_no, 59 "floatformat_ieee_double_little" 60}; 61 62/* floatformat for IEEE double, little endian byte order, with big endian word 63 ordering, as on the ARM. */ 64 65const struct floatformat floatformat_ieee_double_littlebyte_bigword = 66{ 67 floatformat_littlebyte_bigword, 64, 0, 1, 11, 1023, 2047, 12, 52, 68 floatformat_intbit_no, 69 "floatformat_ieee_double_littlebyte_bigword" 70}; 71 72const struct floatformat floatformat_i387_ext = 73{ 74 floatformat_little, 80, 0, 1, 15, 0x3fff, 0x7fff, 16, 64, 75 floatformat_intbit_yes, 76 "floatformat_i387_ext" 77}; 78const struct floatformat floatformat_m68881_ext = 79{ 80 /* Note that the bits from 16 to 31 are unused. */ 81 floatformat_big, 96, 0, 1, 15, 0x3fff, 0x7fff, 32, 64, 82 floatformat_intbit_yes, 83 "floatformat_m68881_ext" 84}; 85const struct floatformat floatformat_i960_ext = 86{ 87 /* Note that the bits from 0 to 15 are unused. */ 88 floatformat_little, 96, 16, 17, 15, 0x3fff, 0x7fff, 32, 64, 89 floatformat_intbit_yes, 90 "floatformat_i960_ext" 91}; 92const struct floatformat floatformat_m88110_ext = 93{ 94 floatformat_big, 80, 0, 1, 15, 0x3fff, 0x7fff, 16, 64, 95 floatformat_intbit_yes, 96 "floatformat_m88110_ext" 97}; 98const struct floatformat floatformat_m88110_harris_ext = 99{ 100 /* Harris uses raw format 128 bytes long, but the number is just an ieee 101 double, and the last 64 bits are wasted. */ 102 floatformat_big,128, 0, 1, 11, 0x3ff, 0x7ff, 12, 52, 103 floatformat_intbit_no, 104 "floatformat_m88110_ext_harris" 105}; 106const struct floatformat floatformat_arm_ext = 107{ 108 /* Bits 1 to 16 are unused. */ 109 floatformat_big, 96, 0, 17, 15, 0x3fff, 0x7fff, 32, 64, 110 floatformat_intbit_yes, 111 "floatformat_arm_ext" 112}; 113const struct floatformat floatformat_arm_ext_big = 114{ 115 /* Bits 1 to 16 are unused. */ 116 floatformat_big, 96, 0, 17, 15, 0x3fff, 0x7fff, 32, 64, 117 floatformat_intbit_yes, 118 "floatformat_arm_ext_big" 119}; 120const struct floatformat floatformat_arm_ext_littlebyte_bigword = 121{ 122 /* Bits 1 to 16 are unused. */ 123 floatformat_littlebyte_bigword, 96, 0, 17, 15, 0x3fff, 0x7fff, 32, 64, 124 floatformat_intbit_yes, 125 "floatformat_arm_ext_littlebyte_bigword" 126}; 127const struct floatformat floatformat_ia64_spill_big = 128{ 129 floatformat_big, 128, 0, 1, 17, 65535, 0x1ffff, 18, 64, 130 floatformat_intbit_yes, 131 "floatformat_ia64_spill_big" 132}; 133const struct floatformat floatformat_ia64_spill_little = 134{ 135 floatformat_little, 128, 0, 1, 17, 65535, 0x1ffff, 18, 64, 136 floatformat_intbit_yes, 137 "floatformat_ia64_spill_little" 138}; 139const struct floatformat floatformat_ia64_quad_big = 140{ 141 floatformat_big, 128, 0, 1, 15, 16383, 0x7fff, 16, 112, 142 floatformat_intbit_no, 143 "floatformat_ia64_quad_big" 144}; 145const struct floatformat floatformat_ia64_quad_little = 146{ 147 floatformat_little, 128, 0, 1, 15, 16383, 0x7fff, 16, 112, 148 floatformat_intbit_no, 149 "floatformat_ia64_quad_little" 150}; 151 152static unsigned long get_field PARAMS ((unsigned char *, 153 enum floatformat_byteorders, 154 unsigned int, 155 unsigned int, 156 unsigned int)); 157 158/* Extract a field which starts at START and is LEN bytes long. DATA and 159 TOTAL_LEN are the thing we are extracting it from, in byteorder ORDER. */ 160static unsigned long 161get_field (data, order, total_len, start, len) 162 unsigned char *data; 163 enum floatformat_byteorders order; 164 unsigned int total_len; 165 unsigned int start; 166 unsigned int len; 167{ 168 unsigned long result; 169 unsigned int cur_byte; 170 int cur_bitshift; 171 172 /* Start at the least significant part of the field. */ 173 cur_byte = (start + len) / FLOATFORMAT_CHAR_BIT; 174 if (order == floatformat_little) 175 cur_byte = (total_len / FLOATFORMAT_CHAR_BIT) - cur_byte - 1; 176 cur_bitshift = 177 ((start + len) % FLOATFORMAT_CHAR_BIT) - FLOATFORMAT_CHAR_BIT; 178 result = *(data + cur_byte) >> (-cur_bitshift); 179 cur_bitshift += FLOATFORMAT_CHAR_BIT; 180 if (order == floatformat_little) 181 ++cur_byte; 182 else 183 --cur_byte; 184 185 /* Move towards the most significant part of the field. */ 186 while ((unsigned int) cur_bitshift < len) 187 { 188 if (len - cur_bitshift < FLOATFORMAT_CHAR_BIT) 189 /* This is the last byte; zero out the bits which are not part of 190 this field. */ 191 result |= 192 (*(data + cur_byte) & ((1 << (len - cur_bitshift)) - 1)) 193 << cur_bitshift; 194 else 195 result |= *(data + cur_byte) << cur_bitshift; 196 cur_bitshift += FLOATFORMAT_CHAR_BIT; 197 if (order == floatformat_little) 198 ++cur_byte; 199 else 200 --cur_byte; 201 } 202 return result; 203} 204 205#ifndef min 206#define min(a, b) ((a) < (b) ? (a) : (b)) 207#endif 208 209/* Convert from FMT to a double. 210 FROM is the address of the extended float. 211 Store the double in *TO. */ 212 213void 214floatformat_to_double (fmt, from, to) 215 const struct floatformat *fmt; 216 char *from; 217 double *to; 218{ 219 unsigned char *ufrom = (unsigned char *)from; 220 double dto; 221 long exponent; 222 unsigned long mant; 223 unsigned int mant_bits, mant_off; 224 int mant_bits_left; 225 int special_exponent; /* It's a NaN, denorm or zero */ 226 227 exponent = get_field (ufrom, fmt->byteorder, fmt->totalsize, 228 fmt->exp_start, fmt->exp_len); 229 /* Note that if exponent indicates a NaN, we can't really do anything useful 230 (not knowing if the host has NaN's, or how to build one). So it will 231 end up as an infinity or something close; that is OK. */ 232 233 mant_bits_left = fmt->man_len; 234 mant_off = fmt->man_start; 235 dto = 0.0; 236 237 special_exponent = exponent == 0 || (unsigned long) exponent == fmt->exp_nan; 238 239 /* Don't bias zero's, denorms or NaNs. */ 240 if (!special_exponent) 241 exponent -= fmt->exp_bias; 242 243 /* Build the result algebraically. Might go infinite, underflow, etc; 244 who cares. */ 245 246 /* If this format uses a hidden bit, explicitly add it in now. Otherwise, 247 increment the exponent by one to account for the integer bit. */ 248 249 if (!special_exponent) 250 { 251 if (fmt->intbit == floatformat_intbit_no) 252 dto = ldexp (1.0, exponent); 253 else 254 exponent++; 255 } 256 257 while (mant_bits_left > 0) 258 { 259 mant_bits = min (mant_bits_left, 32); 260 261 mant = get_field (ufrom, fmt->byteorder, fmt->totalsize, 262 mant_off, mant_bits); 263 264 dto += ldexp ((double)mant, exponent - mant_bits); 265 exponent -= mant_bits; 266 mant_off += mant_bits; 267 mant_bits_left -= mant_bits; 268 } 269 270 /* Negate it if negative. */ 271 if (get_field (ufrom, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1)) 272 dto = -dto; 273 *to = dto; 274} 275 276static void put_field PARAMS ((unsigned char *, enum floatformat_byteorders, 277 unsigned int, 278 unsigned int, 279 unsigned int, 280 unsigned long)); 281 282/* Set a field which starts at START and is LEN bytes long. DATA and 283 TOTAL_LEN are the thing we are extracting it from, in byteorder ORDER. */ 284static void 285put_field (data, order, total_len, start, len, stuff_to_put) 286 unsigned char *data; 287 enum floatformat_byteorders order; 288 unsigned int total_len; 289 unsigned int start; 290 unsigned int len; 291 unsigned long stuff_to_put; 292{ 293 unsigned int cur_byte; 294 int cur_bitshift; 295 296 /* Start at the least significant part of the field. */ 297 cur_byte = (start + len) / FLOATFORMAT_CHAR_BIT; 298 if (order == floatformat_little) 299 cur_byte = (total_len / FLOATFORMAT_CHAR_BIT) - cur_byte - 1; 300 cur_bitshift = 301 ((start + len) % FLOATFORMAT_CHAR_BIT) - FLOATFORMAT_CHAR_BIT; 302 *(data + cur_byte) &= 303 ~(((1 << ((start + len) % FLOATFORMAT_CHAR_BIT)) - 1) << (-cur_bitshift)); 304 *(data + cur_byte) |= 305 (stuff_to_put & ((1 << FLOATFORMAT_CHAR_BIT) - 1)) << (-cur_bitshift); 306 cur_bitshift += FLOATFORMAT_CHAR_BIT; 307 if (order == floatformat_little) 308 ++cur_byte; 309 else 310 --cur_byte; 311 312 /* Move towards the most significant part of the field. */ 313 while ((unsigned int) cur_bitshift < len) 314 { 315 if (len - cur_bitshift < FLOATFORMAT_CHAR_BIT) 316 { 317 /* This is the last byte. */ 318 *(data + cur_byte) &= 319 ~((1 << (len - cur_bitshift)) - 1); 320 *(data + cur_byte) |= (stuff_to_put >> cur_bitshift); 321 } 322 else 323 *(data + cur_byte) = ((stuff_to_put >> cur_bitshift) 324 & ((1 << FLOATFORMAT_CHAR_BIT) - 1)); 325 cur_bitshift += FLOATFORMAT_CHAR_BIT; 326 if (order == floatformat_little) 327 ++cur_byte; 328 else 329 --cur_byte; 330 } 331} 332 333/* The converse: convert the double *FROM to an extended float 334 and store where TO points. Neither FROM nor TO have any alignment 335 restrictions. */ 336 337void 338floatformat_from_double (fmt, from, to) 339 const struct floatformat *fmt; 340 double *from; 341 char *to; 342{ 343 double dfrom; 344 int exponent; 345 double mant; 346 unsigned int mant_bits, mant_off; 347 int mant_bits_left; 348 unsigned char *uto = (unsigned char *)to; 349 350 memcpy (&dfrom, from, sizeof (dfrom)); 351 memset (uto, 0, fmt->totalsize / FLOATFORMAT_CHAR_BIT); 352 if (dfrom == 0) 353 return; /* Result is zero */ 354 if (dfrom != dfrom) 355 { 356 /* From is NaN */ 357 put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start, 358 fmt->exp_len, fmt->exp_nan); 359 /* Be sure it's not infinity, but NaN value is irrel */ 360 put_field (uto, fmt->byteorder, fmt->totalsize, fmt->man_start, 361 32, 1); 362 return; 363 } 364 365 /* If negative, set the sign bit. */ 366 if (dfrom < 0) 367 { 368 put_field (uto, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1, 1); 369 dfrom = -dfrom; 370 } 371 372 /* How to tell an infinity from an ordinary number? FIXME-someday */ 373 374 mant = frexp (dfrom, &exponent); 375 put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start, fmt->exp_len, 376 exponent + fmt->exp_bias - 1); 377 378 mant_bits_left = fmt->man_len; 379 mant_off = fmt->man_start; 380 while (mant_bits_left > 0) 381 { 382 unsigned long mant_long; 383 mant_bits = mant_bits_left < 32 ? mant_bits_left : 32; 384 385 mant *= 4294967296.0; 386 mant_long = (unsigned long)mant; 387 mant -= mant_long; 388 389 /* If the integer bit is implicit, then we need to discard it. 390 If we are discarding a zero, we should be (but are not) creating 391 a denormalized number which means adjusting the exponent 392 (I think). */ 393 if ((unsigned int) mant_bits_left == fmt->man_len 394 && fmt->intbit == floatformat_intbit_no) 395 { 396 mant_long &= 0x7fffffff; 397 mant_bits -= 1; 398 } 399 else if (mant_bits < 32) 400 { 401 /* The bits we want are in the most significant MANT_BITS bits of 402 mant_long. Move them to the least significant. */ 403 mant_long >>= 32 - mant_bits; 404 } 405 406 put_field (uto, fmt->byteorder, fmt->totalsize, 407 mant_off, mant_bits, mant_long); 408 mant_off += mant_bits; 409 mant_bits_left -= mant_bits; 410 } 411} 412 413 414#ifdef IEEE_DEBUG 415 416/* This is to be run on a host which uses IEEE floating point. */ 417 418void 419ieee_test (n) 420 double n; 421{ 422 double result; 423 char exten[16]; 424 425 floatformat_to_double (&floatformat_ieee_double_big, &n, &result); 426 if (n != result) 427 printf ("Differ(to): %.20g -> %.20g\n", n, result); 428 floatformat_from_double (&floatformat_ieee_double_big, &n, &result); 429 if (n != result) 430 printf ("Differ(from): %.20g -> %.20g\n", n, result); 431 432 floatformat_from_double (&floatformat_m68881_ext, &n, exten); 433 floatformat_to_double (&floatformat_m68881_ext, exten, &result); 434 if (n != result) 435 printf ("Differ(to+from): %.20g -> %.20g\n", n, result); 436 437#if IEEE_DEBUG > 1 438 /* This is to be run on a host which uses 68881 format. */ 439 { 440 long double ex = *(long double *)exten; 441 if (ex != n) 442 printf ("Differ(from vs. extended): %.20g\n", n); 443 } 444#endif 445} 446 447int 448main () 449{ 450 ieee_test (0.5); 451 ieee_test (256.0); 452 ieee_test (0.12345); 453 ieee_test (234235.78907234); 454 ieee_test (-512.0); 455 ieee_test (-0.004321); 456 return 0; 457} 458#endif 459