198944Sobrien/* Floating point routines for GDB, the GNU debugger. 298944Sobrien 3130803Smarcel Copyright 1986, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 4130803Smarcel 1996, 1997, 1998, 1999, 2000, 2001, 2003 Free Software Foundation, 5130803Smarcel Inc. 6130803Smarcel 798944Sobrien This file is part of GDB. 898944Sobrien 998944Sobrien This program is free software; you can redistribute it and/or modify 1098944Sobrien it under the terms of the GNU General Public License as published by 1198944Sobrien the Free Software Foundation; either version 2 of the License, or 1298944Sobrien (at your option) any later version. 1398944Sobrien 1498944Sobrien This program is distributed in the hope that it will be useful, 1598944Sobrien but WITHOUT ANY WARRANTY; without even the implied warranty of 1698944Sobrien MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1798944Sobrien GNU General Public License for more details. 1898944Sobrien 1998944Sobrien You should have received a copy of the GNU General Public License 2098944Sobrien along with this program; if not, write to the Free Software 2198944Sobrien Foundation, Inc., 59 Temple Place - Suite 330, 2298944Sobrien Boston, MA 02111-1307, USA. */ 2398944Sobrien 2498944Sobrien/* Support for converting target fp numbers into host DOUBLEST format. */ 2598944Sobrien 2698944Sobrien/* XXX - This code should really be in libiberty/floatformat.c, 2798944Sobrien however configuration issues with libiberty made this very 2898944Sobrien difficult to do in the available time. */ 2998944Sobrien 3098944Sobrien#include "defs.h" 3198944Sobrien#include "doublest.h" 3298944Sobrien#include "floatformat.h" 3398944Sobrien#include "gdb_assert.h" 3498944Sobrien#include "gdb_string.h" 3598944Sobrien#include "gdbtypes.h" 3698944Sobrien#include <math.h> /* ldexp */ 3798944Sobrien 3898944Sobrien/* The odds that CHAR_BIT will be anything but 8 are low enough that I'm not 3998944Sobrien going to bother with trying to muck around with whether it is defined in 4098944Sobrien a system header, what we do if not, etc. */ 4198944Sobrien#define FLOATFORMAT_CHAR_BIT 8 4298944Sobrien 4398944Sobrienstatic unsigned long get_field (unsigned char *, 4498944Sobrien enum floatformat_byteorders, 4598944Sobrien unsigned int, unsigned int, unsigned int); 4698944Sobrien 4798944Sobrien/* Extract a field which starts at START and is LEN bytes long. DATA and 4898944Sobrien TOTAL_LEN are the thing we are extracting it from, in byteorder ORDER. */ 4998944Sobrienstatic unsigned long 5098944Sobrienget_field (unsigned char *data, enum floatformat_byteorders order, 5198944Sobrien unsigned int total_len, unsigned int start, unsigned int len) 5298944Sobrien{ 5398944Sobrien unsigned long result; 5498944Sobrien unsigned int cur_byte; 5598944Sobrien int cur_bitshift; 5698944Sobrien 5798944Sobrien /* Start at the least significant part of the field. */ 5898944Sobrien if (order == floatformat_little || order == floatformat_littlebyte_bigword) 5998944Sobrien { 6098944Sobrien /* We start counting from the other end (i.e, from the high bytes 6198944Sobrien rather than the low bytes). As such, we need to be concerned 6298944Sobrien with what happens if bit 0 doesn't start on a byte boundary. 6398944Sobrien I.e, we need to properly handle the case where total_len is 6498944Sobrien not evenly divisible by 8. So we compute ``excess'' which 6598944Sobrien represents the number of bits from the end of our starting 6698944Sobrien byte needed to get to bit 0. */ 6798944Sobrien int excess = FLOATFORMAT_CHAR_BIT - (total_len % FLOATFORMAT_CHAR_BIT); 6898944Sobrien cur_byte = (total_len / FLOATFORMAT_CHAR_BIT) 6998944Sobrien - ((start + len + excess) / FLOATFORMAT_CHAR_BIT); 7098944Sobrien cur_bitshift = ((start + len + excess) % FLOATFORMAT_CHAR_BIT) 7198944Sobrien - FLOATFORMAT_CHAR_BIT; 7298944Sobrien } 7398944Sobrien else 7498944Sobrien { 7598944Sobrien cur_byte = (start + len) / FLOATFORMAT_CHAR_BIT; 7698944Sobrien cur_bitshift = 7798944Sobrien ((start + len) % FLOATFORMAT_CHAR_BIT) - FLOATFORMAT_CHAR_BIT; 7898944Sobrien } 7998944Sobrien if (cur_bitshift > -FLOATFORMAT_CHAR_BIT) 8098944Sobrien result = *(data + cur_byte) >> (-cur_bitshift); 8198944Sobrien else 8298944Sobrien result = 0; 8398944Sobrien cur_bitshift += FLOATFORMAT_CHAR_BIT; 8498944Sobrien if (order == floatformat_little || order == floatformat_littlebyte_bigword) 8598944Sobrien ++cur_byte; 8698944Sobrien else 8798944Sobrien --cur_byte; 8898944Sobrien 8998944Sobrien /* Move towards the most significant part of the field. */ 9098944Sobrien while (cur_bitshift < len) 9198944Sobrien { 9298944Sobrien result |= (unsigned long)*(data + cur_byte) << cur_bitshift; 9398944Sobrien cur_bitshift += FLOATFORMAT_CHAR_BIT; 9498944Sobrien if (order == floatformat_little || order == floatformat_littlebyte_bigword) 9598944Sobrien ++cur_byte; 9698944Sobrien else 9798944Sobrien --cur_byte; 9898944Sobrien } 9998944Sobrien if (len < sizeof(result) * FLOATFORMAT_CHAR_BIT) 10098944Sobrien /* Mask out bits which are not part of the field */ 10198944Sobrien result &= ((1UL << len) - 1); 10298944Sobrien return result; 10398944Sobrien} 10498944Sobrien 10598944Sobrien/* Convert from FMT to a DOUBLEST. 10698944Sobrien FROM is the address of the extended float. 10798944Sobrien Store the DOUBLEST in *TO. */ 10898944Sobrien 10998944Sobrienstatic void 11098944Sobrienconvert_floatformat_to_doublest (const struct floatformat *fmt, 11198944Sobrien const void *from, 11298944Sobrien DOUBLEST *to) 11398944Sobrien{ 11498944Sobrien unsigned char *ufrom = (unsigned char *) from; 11598944Sobrien DOUBLEST dto; 11698944Sobrien long exponent; 11798944Sobrien unsigned long mant; 11898944Sobrien unsigned int mant_bits, mant_off; 11998944Sobrien int mant_bits_left; 12098944Sobrien int special_exponent; /* It's a NaN, denorm or zero */ 12198944Sobrien 12298944Sobrien /* If the mantissa bits are not contiguous from one end of the 12398944Sobrien mantissa to the other, we need to make a private copy of the 12498944Sobrien source bytes that is in the right order since the unpacking 12598944Sobrien algorithm assumes that the bits are contiguous. 12698944Sobrien 12798944Sobrien Swap the bytes individually rather than accessing them through 12898944Sobrien "long *" since we have no guarantee that they start on a long 12998944Sobrien alignment, and also sizeof(long) for the host could be different 13098944Sobrien than sizeof(long) for the target. FIXME: Assumes sizeof(long) 13198944Sobrien for the target is 4. */ 13298944Sobrien 13398944Sobrien if (fmt->byteorder == floatformat_littlebyte_bigword) 13498944Sobrien { 13598944Sobrien static unsigned char *newfrom; 13698944Sobrien unsigned char *swapin, *swapout; 13798944Sobrien int longswaps; 13898944Sobrien 13998944Sobrien longswaps = fmt->totalsize / FLOATFORMAT_CHAR_BIT; 14098944Sobrien longswaps >>= 3; 14198944Sobrien 14298944Sobrien if (newfrom == NULL) 14398944Sobrien { 14498944Sobrien newfrom = (unsigned char *) xmalloc (fmt->totalsize); 14598944Sobrien } 14698944Sobrien swapout = newfrom; 14798944Sobrien swapin = ufrom; 14898944Sobrien ufrom = newfrom; 14998944Sobrien while (longswaps-- > 0) 15098944Sobrien { 15198944Sobrien /* This is ugly, but efficient */ 15298944Sobrien *swapout++ = swapin[4]; 15398944Sobrien *swapout++ = swapin[5]; 15498944Sobrien *swapout++ = swapin[6]; 15598944Sobrien *swapout++ = swapin[7]; 15698944Sobrien *swapout++ = swapin[0]; 15798944Sobrien *swapout++ = swapin[1]; 15898944Sobrien *swapout++ = swapin[2]; 15998944Sobrien *swapout++ = swapin[3]; 16098944Sobrien swapin += 8; 16198944Sobrien } 16298944Sobrien } 16398944Sobrien 16498944Sobrien exponent = get_field (ufrom, fmt->byteorder, fmt->totalsize, 16598944Sobrien fmt->exp_start, fmt->exp_len); 16698944Sobrien /* Note that if exponent indicates a NaN, we can't really do anything useful 16798944Sobrien (not knowing if the host has NaN's, or how to build one). So it will 16898944Sobrien end up as an infinity or something close; that is OK. */ 16998944Sobrien 17098944Sobrien mant_bits_left = fmt->man_len; 17198944Sobrien mant_off = fmt->man_start; 17298944Sobrien dto = 0.0; 17398944Sobrien 17498944Sobrien special_exponent = exponent == 0 || exponent == fmt->exp_nan; 17598944Sobrien 176130803Smarcel /* Don't bias NaNs. Use minimum exponent for denorms. For simplicity, 177130803Smarcel we don't check for zero as the exponent doesn't matter. Note the cast 178130803Smarcel to int; exp_bias is unsigned, so it's important to make sure the 179130803Smarcel operation is done in signed arithmetic. */ 18098944Sobrien if (!special_exponent) 18198944Sobrien exponent -= fmt->exp_bias; 18298944Sobrien else if (exponent == 0) 18398944Sobrien exponent = 1 - fmt->exp_bias; 18498944Sobrien 18598944Sobrien /* Build the result algebraically. Might go infinite, underflow, etc; 18698944Sobrien who cares. */ 18798944Sobrien 18898944Sobrien/* If this format uses a hidden bit, explicitly add it in now. Otherwise, 18998944Sobrien increment the exponent by one to account for the integer bit. */ 19098944Sobrien 19198944Sobrien if (!special_exponent) 19298944Sobrien { 19398944Sobrien if (fmt->intbit == floatformat_intbit_no) 19498944Sobrien dto = ldexp (1.0, exponent); 19598944Sobrien else 19698944Sobrien exponent++; 19798944Sobrien } 19898944Sobrien 19998944Sobrien while (mant_bits_left > 0) 20098944Sobrien { 20198944Sobrien mant_bits = min (mant_bits_left, 32); 20298944Sobrien 20398944Sobrien mant = get_field (ufrom, fmt->byteorder, fmt->totalsize, 20498944Sobrien mant_off, mant_bits); 20598944Sobrien 20698944Sobrien dto += ldexp ((double) mant, exponent - mant_bits); 20798944Sobrien exponent -= mant_bits; 20898944Sobrien mant_off += mant_bits; 20998944Sobrien mant_bits_left -= mant_bits; 21098944Sobrien } 21198944Sobrien 21298944Sobrien /* Negate it if negative. */ 21398944Sobrien if (get_field (ufrom, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1)) 21498944Sobrien dto = -dto; 21598944Sobrien *to = dto; 21698944Sobrien} 21798944Sobrien 21898944Sobrienstatic void put_field (unsigned char *, enum floatformat_byteorders, 21998944Sobrien unsigned int, 22098944Sobrien unsigned int, unsigned int, unsigned long); 22198944Sobrien 22298944Sobrien/* Set a field which starts at START and is LEN bytes long. DATA and 22398944Sobrien TOTAL_LEN are the thing we are extracting it from, in byteorder ORDER. */ 22498944Sobrienstatic void 22598944Sobrienput_field (unsigned char *data, enum floatformat_byteorders order, 22698944Sobrien unsigned int total_len, unsigned int start, unsigned int len, 22798944Sobrien unsigned long stuff_to_put) 22898944Sobrien{ 22998944Sobrien unsigned int cur_byte; 23098944Sobrien int cur_bitshift; 23198944Sobrien 23298944Sobrien /* Start at the least significant part of the field. */ 23398944Sobrien if (order == floatformat_little || order == floatformat_littlebyte_bigword) 23498944Sobrien { 23598944Sobrien int excess = FLOATFORMAT_CHAR_BIT - (total_len % FLOATFORMAT_CHAR_BIT); 23698944Sobrien cur_byte = (total_len / FLOATFORMAT_CHAR_BIT) 23798944Sobrien - ((start + len + excess) / FLOATFORMAT_CHAR_BIT); 23898944Sobrien cur_bitshift = ((start + len + excess) % FLOATFORMAT_CHAR_BIT) 23998944Sobrien - FLOATFORMAT_CHAR_BIT; 24098944Sobrien } 24198944Sobrien else 24298944Sobrien { 24398944Sobrien cur_byte = (start + len) / FLOATFORMAT_CHAR_BIT; 24498944Sobrien cur_bitshift = 24598944Sobrien ((start + len) % FLOATFORMAT_CHAR_BIT) - FLOATFORMAT_CHAR_BIT; 24698944Sobrien } 24798944Sobrien if (cur_bitshift > -FLOATFORMAT_CHAR_BIT) 24898944Sobrien { 24998944Sobrien *(data + cur_byte) &= 25098944Sobrien ~(((1 << ((start + len) % FLOATFORMAT_CHAR_BIT)) - 1) 25198944Sobrien << (-cur_bitshift)); 25298944Sobrien *(data + cur_byte) |= 25398944Sobrien (stuff_to_put & ((1 << FLOATFORMAT_CHAR_BIT) - 1)) << (-cur_bitshift); 25498944Sobrien } 25598944Sobrien cur_bitshift += FLOATFORMAT_CHAR_BIT; 25698944Sobrien if (order == floatformat_little || order == floatformat_littlebyte_bigword) 25798944Sobrien ++cur_byte; 25898944Sobrien else 25998944Sobrien --cur_byte; 26098944Sobrien 26198944Sobrien /* Move towards the most significant part of the field. */ 26298944Sobrien while (cur_bitshift < len) 26398944Sobrien { 26498944Sobrien if (len - cur_bitshift < FLOATFORMAT_CHAR_BIT) 26598944Sobrien { 26698944Sobrien /* This is the last byte. */ 26798944Sobrien *(data + cur_byte) &= 26898944Sobrien ~((1 << (len - cur_bitshift)) - 1); 26998944Sobrien *(data + cur_byte) |= (stuff_to_put >> cur_bitshift); 27098944Sobrien } 27198944Sobrien else 27298944Sobrien *(data + cur_byte) = ((stuff_to_put >> cur_bitshift) 27398944Sobrien & ((1 << FLOATFORMAT_CHAR_BIT) - 1)); 27498944Sobrien cur_bitshift += FLOATFORMAT_CHAR_BIT; 27598944Sobrien if (order == floatformat_little || order == floatformat_littlebyte_bigword) 27698944Sobrien ++cur_byte; 27798944Sobrien else 27898944Sobrien --cur_byte; 27998944Sobrien } 28098944Sobrien} 28198944Sobrien 28298944Sobrien#ifdef HAVE_LONG_DOUBLE 28398944Sobrien/* Return the fractional part of VALUE, and put the exponent of VALUE in *EPTR. 28498944Sobrien The range of the returned value is >= 0.5 and < 1.0. This is equivalent to 28598944Sobrien frexp, but operates on the long double data type. */ 28698944Sobrien 28798944Sobrienstatic long double ldfrexp (long double value, int *eptr); 28898944Sobrien 28998944Sobrienstatic long double 29098944Sobrienldfrexp (long double value, int *eptr) 29198944Sobrien{ 29298944Sobrien long double tmp; 29398944Sobrien int exp; 29498944Sobrien 29598944Sobrien /* Unfortunately, there are no portable functions for extracting the exponent 29698944Sobrien of a long double, so we have to do it iteratively by multiplying or dividing 29798944Sobrien by two until the fraction is between 0.5 and 1.0. */ 29898944Sobrien 29998944Sobrien if (value < 0.0l) 30098944Sobrien value = -value; 30198944Sobrien 30298944Sobrien tmp = 1.0l; 30398944Sobrien exp = 0; 30498944Sobrien 30598944Sobrien if (value >= tmp) /* Value >= 1.0 */ 30698944Sobrien while (value >= tmp) 30798944Sobrien { 30898944Sobrien tmp *= 2.0l; 30998944Sobrien exp++; 31098944Sobrien } 31198944Sobrien else if (value != 0.0l) /* Value < 1.0 and > 0.0 */ 31298944Sobrien { 31398944Sobrien while (value < tmp) 31498944Sobrien { 31598944Sobrien tmp /= 2.0l; 31698944Sobrien exp--; 31798944Sobrien } 31898944Sobrien tmp *= 2.0l; 31998944Sobrien exp++; 32098944Sobrien } 32198944Sobrien 32298944Sobrien *eptr = exp; 32398944Sobrien return value / tmp; 32498944Sobrien} 32598944Sobrien#endif /* HAVE_LONG_DOUBLE */ 32698944Sobrien 32798944Sobrien 32898944Sobrien/* The converse: convert the DOUBLEST *FROM to an extended float 32998944Sobrien and store where TO points. Neither FROM nor TO have any alignment 33098944Sobrien restrictions. */ 33198944Sobrien 33298944Sobrienstatic void 33398944Sobrienconvert_doublest_to_floatformat (CONST struct floatformat *fmt, 33498944Sobrien const DOUBLEST *from, 33598944Sobrien void *to) 33698944Sobrien{ 33798944Sobrien DOUBLEST dfrom; 33898944Sobrien int exponent; 33998944Sobrien DOUBLEST mant; 34098944Sobrien unsigned int mant_bits, mant_off; 34198944Sobrien int mant_bits_left; 34298944Sobrien unsigned char *uto = (unsigned char *) to; 34398944Sobrien 34498944Sobrien memcpy (&dfrom, from, sizeof (dfrom)); 34598944Sobrien memset (uto, 0, (fmt->totalsize + FLOATFORMAT_CHAR_BIT - 1) 34698944Sobrien / FLOATFORMAT_CHAR_BIT); 34798944Sobrien if (dfrom == 0) 34898944Sobrien return; /* Result is zero */ 34998944Sobrien if (dfrom != dfrom) /* Result is NaN */ 35098944Sobrien { 35198944Sobrien /* From is NaN */ 35298944Sobrien put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start, 35398944Sobrien fmt->exp_len, fmt->exp_nan); 35498944Sobrien /* Be sure it's not infinity, but NaN value is irrel */ 35598944Sobrien put_field (uto, fmt->byteorder, fmt->totalsize, fmt->man_start, 35698944Sobrien 32, 1); 35798944Sobrien return; 35898944Sobrien } 35998944Sobrien 36098944Sobrien /* If negative, set the sign bit. */ 36198944Sobrien if (dfrom < 0) 36298944Sobrien { 36398944Sobrien put_field (uto, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1, 1); 36498944Sobrien dfrom = -dfrom; 36598944Sobrien } 36698944Sobrien 36798944Sobrien if (dfrom + dfrom == dfrom && dfrom != 0.0) /* Result is Infinity */ 36898944Sobrien { 36998944Sobrien /* Infinity exponent is same as NaN's. */ 37098944Sobrien put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start, 37198944Sobrien fmt->exp_len, fmt->exp_nan); 37298944Sobrien /* Infinity mantissa is all zeroes. */ 37398944Sobrien put_field (uto, fmt->byteorder, fmt->totalsize, fmt->man_start, 37498944Sobrien fmt->man_len, 0); 37598944Sobrien return; 37698944Sobrien } 37798944Sobrien 37898944Sobrien#ifdef HAVE_LONG_DOUBLE 37998944Sobrien mant = ldfrexp (dfrom, &exponent); 38098944Sobrien#else 38198944Sobrien mant = frexp (dfrom, &exponent); 38298944Sobrien#endif 38398944Sobrien 38498944Sobrien put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start, fmt->exp_len, 38598944Sobrien exponent + fmt->exp_bias - 1); 38698944Sobrien 38798944Sobrien mant_bits_left = fmt->man_len; 38898944Sobrien mant_off = fmt->man_start; 38998944Sobrien while (mant_bits_left > 0) 39098944Sobrien { 39198944Sobrien unsigned long mant_long; 39298944Sobrien mant_bits = mant_bits_left < 32 ? mant_bits_left : 32; 39398944Sobrien 39498944Sobrien mant *= 4294967296.0; 39598944Sobrien mant_long = ((unsigned long) mant) & 0xffffffffL; 39698944Sobrien mant -= mant_long; 39798944Sobrien 39898944Sobrien /* If the integer bit is implicit, then we need to discard it. 39998944Sobrien If we are discarding a zero, we should be (but are not) creating 40098944Sobrien a denormalized number which means adjusting the exponent 40198944Sobrien (I think). */ 40298944Sobrien if (mant_bits_left == fmt->man_len 40398944Sobrien && fmt->intbit == floatformat_intbit_no) 40498944Sobrien { 40598944Sobrien mant_long <<= 1; 40698944Sobrien mant_long &= 0xffffffffL; 407130803Smarcel /* If we are processing the top 32 mantissa bits of a doublest 408130803Smarcel so as to convert to a float value with implied integer bit, 409130803Smarcel we will only be putting 31 of those 32 bits into the 410130803Smarcel final value due to the discarding of the top bit. In the 411130803Smarcel case of a small float value where the number of mantissa 412130803Smarcel bits is less than 32, discarding the top bit does not alter 413130803Smarcel the number of bits we will be adding to the result. */ 414130803Smarcel if (mant_bits == 32) 415130803Smarcel mant_bits -= 1; 41698944Sobrien } 41798944Sobrien 41898944Sobrien if (mant_bits < 32) 41998944Sobrien { 42098944Sobrien /* The bits we want are in the most significant MANT_BITS bits of 42198944Sobrien mant_long. Move them to the least significant. */ 42298944Sobrien mant_long >>= 32 - mant_bits; 42398944Sobrien } 42498944Sobrien 42598944Sobrien put_field (uto, fmt->byteorder, fmt->totalsize, 42698944Sobrien mant_off, mant_bits, mant_long); 42798944Sobrien mant_off += mant_bits; 42898944Sobrien mant_bits_left -= mant_bits; 42998944Sobrien } 43098944Sobrien if (fmt->byteorder == floatformat_littlebyte_bigword) 43198944Sobrien { 43298944Sobrien int count; 43398944Sobrien unsigned char *swaplow = uto; 43498944Sobrien unsigned char *swaphigh = uto + 4; 43598944Sobrien unsigned char tmp; 43698944Sobrien 43798944Sobrien for (count = 0; count < 4; count++) 43898944Sobrien { 43998944Sobrien tmp = *swaplow; 44098944Sobrien *swaplow++ = *swaphigh; 44198944Sobrien *swaphigh++ = tmp; 44298944Sobrien } 44398944Sobrien } 44498944Sobrien} 44598944Sobrien 44698944Sobrien/* Check if VAL (which is assumed to be a floating point number whose 44798944Sobrien format is described by FMT) is negative. */ 44898944Sobrien 44998944Sobrienint 45098944Sobrienfloatformat_is_negative (const struct floatformat *fmt, char *val) 45198944Sobrien{ 45298944Sobrien unsigned char *uval = (unsigned char *) val; 45398944Sobrien gdb_assert (fmt != NULL); 45498944Sobrien return get_field (uval, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1); 45598944Sobrien} 45698944Sobrien 45798944Sobrien/* Check if VAL is "not a number" (NaN) for FMT. */ 45898944Sobrien 45998944Sobrienint 46098944Sobrienfloatformat_is_nan (const struct floatformat *fmt, char *val) 46198944Sobrien{ 46298944Sobrien unsigned char *uval = (unsigned char *) val; 46398944Sobrien long exponent; 46498944Sobrien unsigned long mant; 46598944Sobrien unsigned int mant_bits, mant_off; 46698944Sobrien int mant_bits_left; 46798944Sobrien 46898944Sobrien gdb_assert (fmt != NULL); 46998944Sobrien 47098944Sobrien if (! fmt->exp_nan) 47198944Sobrien return 0; 47298944Sobrien 47398944Sobrien exponent = get_field (uval, fmt->byteorder, fmt->totalsize, 47498944Sobrien fmt->exp_start, fmt->exp_len); 47598944Sobrien 47698944Sobrien if (exponent != fmt->exp_nan) 47798944Sobrien return 0; 47898944Sobrien 47998944Sobrien mant_bits_left = fmt->man_len; 48098944Sobrien mant_off = fmt->man_start; 48198944Sobrien 48298944Sobrien while (mant_bits_left > 0) 48398944Sobrien { 48498944Sobrien mant_bits = min (mant_bits_left, 32); 48598944Sobrien 48698944Sobrien mant = get_field (uval, fmt->byteorder, fmt->totalsize, 48798944Sobrien mant_off, mant_bits); 48898944Sobrien 48998944Sobrien /* If there is an explicit integer bit, mask it off. */ 49098944Sobrien if (mant_off == fmt->man_start 49198944Sobrien && fmt->intbit == floatformat_intbit_yes) 49298944Sobrien mant &= ~(1 << (mant_bits - 1)); 49398944Sobrien 49498944Sobrien if (mant) 49598944Sobrien return 1; 49698944Sobrien 49798944Sobrien mant_off += mant_bits; 49898944Sobrien mant_bits_left -= mant_bits; 49998944Sobrien } 50098944Sobrien 50198944Sobrien return 0; 50298944Sobrien} 50398944Sobrien 50498944Sobrien/* Convert the mantissa of VAL (which is assumed to be a floating 50598944Sobrien point number whose format is described by FMT) into a hexadecimal 50698944Sobrien and store it in a static string. Return a pointer to that string. */ 50798944Sobrien 50898944Sobrienchar * 50998944Sobrienfloatformat_mantissa (const struct floatformat *fmt, char *val) 51098944Sobrien{ 51198944Sobrien unsigned char *uval = (unsigned char *) val; 51298944Sobrien unsigned long mant; 51398944Sobrien unsigned int mant_bits, mant_off; 51498944Sobrien int mant_bits_left; 51598944Sobrien static char res[50]; 51698944Sobrien char buf[9]; 51798944Sobrien 51898944Sobrien /* Make sure we have enough room to store the mantissa. */ 51998944Sobrien gdb_assert (fmt != NULL); 52098944Sobrien gdb_assert (sizeof res > ((fmt->man_len + 7) / 8) * 2); 52198944Sobrien 52298944Sobrien mant_off = fmt->man_start; 52398944Sobrien mant_bits_left = fmt->man_len; 52498944Sobrien mant_bits = (mant_bits_left % 32) > 0 ? mant_bits_left % 32 : 32; 52598944Sobrien 52698944Sobrien mant = get_field (uval, fmt->byteorder, fmt->totalsize, 52798944Sobrien mant_off, mant_bits); 52898944Sobrien 52998944Sobrien sprintf (res, "%lx", mant); 53098944Sobrien 53198944Sobrien mant_off += mant_bits; 53298944Sobrien mant_bits_left -= mant_bits; 53398944Sobrien 53498944Sobrien while (mant_bits_left > 0) 53598944Sobrien { 53698944Sobrien mant = get_field (uval, fmt->byteorder, fmt->totalsize, 53798944Sobrien mant_off, 32); 53898944Sobrien 53998944Sobrien sprintf (buf, "%08lx", mant); 54098944Sobrien strcat (res, buf); 54198944Sobrien 54298944Sobrien mant_off += 32; 54398944Sobrien mant_bits_left -= 32; 54498944Sobrien } 54598944Sobrien 54698944Sobrien return res; 54798944Sobrien} 54898944Sobrien 54998944Sobrien 55098944Sobrien/* Convert TO/FROM target to the hosts DOUBLEST floating-point format. 55198944Sobrien 55298944Sobrien If the host and target formats agree, we just copy the raw data 55398944Sobrien into the appropriate type of variable and return, letting the host 55498944Sobrien increase precision as necessary. Otherwise, we call the conversion 55598944Sobrien routine and let it do the dirty work. */ 55698944Sobrien 55798944Sobrien#ifndef HOST_FLOAT_FORMAT 55898944Sobrien#define HOST_FLOAT_FORMAT 0 55998944Sobrien#endif 56098944Sobrien#ifndef HOST_DOUBLE_FORMAT 56198944Sobrien#define HOST_DOUBLE_FORMAT 0 56298944Sobrien#endif 56398944Sobrien#ifndef HOST_LONG_DOUBLE_FORMAT 56498944Sobrien#define HOST_LONG_DOUBLE_FORMAT 0 56598944Sobrien#endif 56698944Sobrien 56798944Sobrienstatic const struct floatformat *host_float_format = HOST_FLOAT_FORMAT; 56898944Sobrienstatic const struct floatformat *host_double_format = HOST_DOUBLE_FORMAT; 56998944Sobrienstatic const struct floatformat *host_long_double_format = HOST_LONG_DOUBLE_FORMAT; 57098944Sobrien 57198944Sobrienvoid 57298944Sobrienfloatformat_to_doublest (const struct floatformat *fmt, 57398944Sobrien const void *in, DOUBLEST *out) 57498944Sobrien{ 57598944Sobrien gdb_assert (fmt != NULL); 57698944Sobrien if (fmt == host_float_format) 57798944Sobrien { 57898944Sobrien float val; 57998944Sobrien memcpy (&val, in, sizeof (val)); 58098944Sobrien *out = val; 58198944Sobrien } 58298944Sobrien else if (fmt == host_double_format) 58398944Sobrien { 58498944Sobrien double val; 58598944Sobrien memcpy (&val, in, sizeof (val)); 58698944Sobrien *out = val; 58798944Sobrien } 58898944Sobrien else if (fmt == host_long_double_format) 58998944Sobrien { 59098944Sobrien long double val; 59198944Sobrien memcpy (&val, in, sizeof (val)); 59298944Sobrien *out = val; 59398944Sobrien } 59498944Sobrien else 59598944Sobrien convert_floatformat_to_doublest (fmt, in, out); 59698944Sobrien} 59798944Sobrien 59898944Sobrienvoid 59998944Sobrienfloatformat_from_doublest (const struct floatformat *fmt, 60098944Sobrien const DOUBLEST *in, void *out) 60198944Sobrien{ 60298944Sobrien gdb_assert (fmt != NULL); 60398944Sobrien if (fmt == host_float_format) 60498944Sobrien { 60598944Sobrien float val = *in; 60698944Sobrien memcpy (out, &val, sizeof (val)); 60798944Sobrien } 60898944Sobrien else if (fmt == host_double_format) 60998944Sobrien { 61098944Sobrien double val = *in; 61198944Sobrien memcpy (out, &val, sizeof (val)); 61298944Sobrien } 61398944Sobrien else if (fmt == host_long_double_format) 61498944Sobrien { 61598944Sobrien long double val = *in; 61698944Sobrien memcpy (out, &val, sizeof (val)); 61798944Sobrien } 61898944Sobrien else 61998944Sobrien convert_doublest_to_floatformat (fmt, in, out); 62098944Sobrien} 62198944Sobrien 62298944Sobrien 62398944Sobrien/* Return a floating-point format for a floating-point variable of 62498944Sobrien length LEN. Return NULL, if no suitable floating-point format 62598944Sobrien could be found. 62698944Sobrien 62798944Sobrien We need this functionality since information about the 62898944Sobrien floating-point format of a type is not always available to GDB; the 62998944Sobrien debug information typically only tells us the size of a 63098944Sobrien floating-point type. 63198944Sobrien 63298944Sobrien FIXME: kettenis/2001-10-28: In many places, particularly in 63398944Sobrien target-dependent code, the format of floating-point types is known, 63498944Sobrien but not passed on by GDB. This should be fixed. */ 63598944Sobrien 636130803Smarcelstatic const struct floatformat * 63798944Sobrienfloatformat_from_length (int len) 63898944Sobrien{ 63998944Sobrien if (len * TARGET_CHAR_BIT == TARGET_FLOAT_BIT) 64098944Sobrien return TARGET_FLOAT_FORMAT; 64198944Sobrien else if (len * TARGET_CHAR_BIT == TARGET_DOUBLE_BIT) 64298944Sobrien return TARGET_DOUBLE_FORMAT; 64398944Sobrien else if (len * TARGET_CHAR_BIT == TARGET_LONG_DOUBLE_BIT) 64498944Sobrien return TARGET_LONG_DOUBLE_FORMAT; 645130803Smarcel /* On i386 the 'long double' type takes 96 bits, 646130803Smarcel while the real number of used bits is only 80, 647130803Smarcel both in processor and in memory. 648130803Smarcel The code below accepts the real bit size. */ 649130803Smarcel else if ((TARGET_LONG_DOUBLE_FORMAT != NULL) 650130803Smarcel && (len * TARGET_CHAR_BIT == 651130803Smarcel TARGET_LONG_DOUBLE_FORMAT->totalsize)) 652130803Smarcel return TARGET_LONG_DOUBLE_FORMAT; 65398944Sobrien 65498944Sobrien return NULL; 65598944Sobrien} 65698944Sobrien 65798944Sobrienconst struct floatformat * 65898944Sobrienfloatformat_from_type (const struct type *type) 65998944Sobrien{ 66098944Sobrien gdb_assert (TYPE_CODE (type) == TYPE_CODE_FLT); 66198944Sobrien if (TYPE_FLOATFORMAT (type) != NULL) 66298944Sobrien return TYPE_FLOATFORMAT (type); 66398944Sobrien else 66498944Sobrien return floatformat_from_length (TYPE_LENGTH (type)); 66598944Sobrien} 66698944Sobrien 66798944Sobrien/* If the host doesn't define NAN, use zero instead. */ 66898944Sobrien#ifndef NAN 66998944Sobrien#define NAN 0.0 67098944Sobrien#endif 67198944Sobrien 67298944Sobrien/* Extract a floating-point number of length LEN from a target-order 67398944Sobrien byte-stream at ADDR. Returns the value as type DOUBLEST. */ 67498944Sobrien 675130803Smarcelstatic DOUBLEST 676130803Smarcelextract_floating_by_length (const void *addr, int len) 67798944Sobrien{ 67898944Sobrien const struct floatformat *fmt = floatformat_from_length (len); 67998944Sobrien DOUBLEST val; 68098944Sobrien 68198944Sobrien if (fmt == NULL) 68298944Sobrien { 683130803Smarcel warning ("Can't extract a floating-point number of %d bytes.", len); 68498944Sobrien return NAN; 68598944Sobrien } 68698944Sobrien 68798944Sobrien floatformat_to_doublest (fmt, addr, &val); 68898944Sobrien return val; 68998944Sobrien} 69098944Sobrien 691130803SmarcelDOUBLEST 692130803Smarceldeprecated_extract_floating (const void *addr, int len) 693130803Smarcel{ 694130803Smarcel return extract_floating_by_length (addr, len); 695130803Smarcel} 696130803Smarcel 69798944Sobrien/* Store VAL as a floating-point number of length LEN to a 69898944Sobrien target-order byte-stream at ADDR. */ 69998944Sobrien 700130803Smarcelstatic void 701130803Smarcelstore_floating_by_length (void *addr, int len, DOUBLEST val) 70298944Sobrien{ 70398944Sobrien const struct floatformat *fmt = floatformat_from_length (len); 70498944Sobrien 70598944Sobrien if (fmt == NULL) 70698944Sobrien { 70798944Sobrien warning ("Can't store a floating-point number of %d bytes.", len); 70898944Sobrien memset (addr, 0, len); 709130803Smarcel return; 71098944Sobrien } 71198944Sobrien 71298944Sobrien floatformat_from_doublest (fmt, &val, addr); 71398944Sobrien} 71498944Sobrien 715130803Smarcelvoid 716130803Smarceldeprecated_store_floating (void *addr, int len, DOUBLEST val) 717130803Smarcel{ 718130803Smarcel store_floating_by_length (addr, len, val); 719130803Smarcel} 720130803Smarcel 72198944Sobrien/* Extract a floating-point number of type TYPE from a target-order 72298944Sobrien byte-stream at ADDR. Returns the value as type DOUBLEST. */ 72398944Sobrien 72498944SobrienDOUBLEST 72598944Sobrienextract_typed_floating (const void *addr, const struct type *type) 72698944Sobrien{ 72798944Sobrien DOUBLEST retval; 72898944Sobrien 72998944Sobrien gdb_assert (TYPE_CODE (type) == TYPE_CODE_FLT); 73098944Sobrien 73198944Sobrien if (TYPE_FLOATFORMAT (type) == NULL) 732130803Smarcel /* Not all code remembers to set the FLOATFORMAT (language 733130803Smarcel specific code? stabs?) so handle that here as a special case. */ 734130803Smarcel return extract_floating_by_length (addr, TYPE_LENGTH (type)); 73598944Sobrien 73698944Sobrien floatformat_to_doublest (TYPE_FLOATFORMAT (type), addr, &retval); 73798944Sobrien return retval; 73898944Sobrien} 73998944Sobrien 74098944Sobrien/* Store VAL as a floating-point number of type TYPE to a target-order 74198944Sobrien byte-stream at ADDR. */ 74298944Sobrien 74398944Sobrienvoid 74498944Sobrienstore_typed_floating (void *addr, const struct type *type, DOUBLEST val) 74598944Sobrien{ 74698944Sobrien gdb_assert (TYPE_CODE (type) == TYPE_CODE_FLT); 74798944Sobrien 74898944Sobrien /* FIXME: kettenis/2001-10-28: It is debatable whether we should 74998944Sobrien zero out any remaining bytes in the target buffer when TYPE is 75098944Sobrien longer than the actual underlying floating-point format. Perhaps 75198944Sobrien we should store a fixed bitpattern in those remaining bytes, 75298944Sobrien instead of zero, or perhaps we shouldn't touch those remaining 75398944Sobrien bytes at all. 75498944Sobrien 75598944Sobrien NOTE: cagney/2001-10-28: With the way things currently work, it 75698944Sobrien isn't a good idea to leave the end bits undefined. This is 75798944Sobrien because GDB writes out the entire sizeof(<floating>) bits of the 75898944Sobrien floating-point type even though the value might only be stored 75998944Sobrien in, and the target processor may only refer to, the first N < 76098944Sobrien TYPE_LENGTH (type) bits. If the end of the buffer wasn't 76198944Sobrien initialized, GDB would write undefined data to the target. An 76298944Sobrien errant program, refering to that undefined data, would then 76398944Sobrien become non-deterministic. 76498944Sobrien 76598944Sobrien See also the function convert_typed_floating below. */ 76698944Sobrien memset (addr, 0, TYPE_LENGTH (type)); 76798944Sobrien 76898944Sobrien if (TYPE_FLOATFORMAT (type) == NULL) 769130803Smarcel /* Not all code remembers to set the FLOATFORMAT (language 770130803Smarcel specific code? stabs?) so handle that here as a special case. */ 771130803Smarcel store_floating_by_length (addr, TYPE_LENGTH (type), val); 77298944Sobrien else 77398944Sobrien floatformat_from_doublest (TYPE_FLOATFORMAT (type), &val, addr); 77498944Sobrien} 77598944Sobrien 77698944Sobrien/* Convert a floating-point number of type FROM_TYPE from a 77798944Sobrien target-order byte-stream at FROM to a floating-point number of type 77898944Sobrien TO_TYPE, and store it to a target-order byte-stream at TO. */ 77998944Sobrien 78098944Sobrienvoid 78198944Sobrienconvert_typed_floating (const void *from, const struct type *from_type, 78298944Sobrien void *to, const struct type *to_type) 78398944Sobrien{ 78498944Sobrien const struct floatformat *from_fmt = floatformat_from_type (from_type); 78598944Sobrien const struct floatformat *to_fmt = floatformat_from_type (to_type); 78698944Sobrien 78798944Sobrien gdb_assert (TYPE_CODE (from_type) == TYPE_CODE_FLT); 78898944Sobrien gdb_assert (TYPE_CODE (to_type) == TYPE_CODE_FLT); 78998944Sobrien 79098944Sobrien if (from_fmt == NULL || to_fmt == NULL) 79198944Sobrien { 79298944Sobrien /* If we don't know the floating-point format of FROM_TYPE or 79398944Sobrien TO_TYPE, there's not much we can do. We might make the 79498944Sobrien assumption that if the length of FROM_TYPE and TO_TYPE match, 79598944Sobrien their floating-point format would match too, but that 79698944Sobrien assumption might be wrong on targets that support 79798944Sobrien floating-point types that only differ in endianness for 79898944Sobrien example. So we warn instead, and zero out the target buffer. */ 79998944Sobrien warning ("Can't convert floating-point number to desired type."); 80098944Sobrien memset (to, 0, TYPE_LENGTH (to_type)); 80198944Sobrien } 80298944Sobrien else if (from_fmt == to_fmt) 80398944Sobrien { 80498944Sobrien /* We're in business. The floating-point format of FROM_TYPE 80598944Sobrien and TO_TYPE match. However, even though the floating-point 80698944Sobrien format matches, the length of the type might still be 80798944Sobrien different. Make sure we don't overrun any buffers. See 80898944Sobrien comment in store_typed_floating for a discussion about 80998944Sobrien zeroing out remaining bytes in the target buffer. */ 81098944Sobrien memset (to, 0, TYPE_LENGTH (to_type)); 81198944Sobrien memcpy (to, from, min (TYPE_LENGTH (from_type), TYPE_LENGTH (to_type))); 81298944Sobrien } 81398944Sobrien else 81498944Sobrien { 81598944Sobrien /* The floating-point types don't match. The best we can do 81698944Sobrien (aport from simulating the target FPU) is converting to the 81798944Sobrien widest floating-point type supported by the host, and then 81898944Sobrien again to the desired type. */ 81998944Sobrien DOUBLEST d; 82098944Sobrien 82198944Sobrien floatformat_to_doublest (from_fmt, from, &d); 82298944Sobrien floatformat_from_doublest (to_fmt, &d, to); 82398944Sobrien } 82498944Sobrien} 825