/* Floating point routines for GDB, the GNU debugger.
Copyright 1986, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995,
- 1996, 1997, 1998, 1999, 2000, 2001, 2003 Free Software Foundation,
- Inc.
+ 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005 Free Software
+ Foundation, Inc.
This file is part of GDB.
a system header, what we do if not, etc. */
#define FLOATFORMAT_CHAR_BIT 8
-static unsigned long get_field (unsigned char *,
- enum floatformat_byteorders,
- unsigned int, unsigned int, unsigned int);
+/* The number of bytes that the largest floating-point type that we
+ can convert to doublest will need. */
+#define FLOATFORMAT_LARGEST_BYTES 16
/* Extract a field which starts at START and is LEN bytes long. DATA and
TOTAL_LEN are the thing we are extracting it from, in byteorder ORDER. */
static unsigned long
-get_field (unsigned char *data, enum floatformat_byteorders order,
+get_field (const bfd_byte *data, enum floatformat_byteorders order,
unsigned int total_len, unsigned int start, unsigned int len)
{
unsigned long result;
unsigned int cur_byte;
int cur_bitshift;
+ /* Caller must byte-swap words before calling this routine. */
+ gdb_assert (order == floatformat_little || order == floatformat_big);
+
/* Start at the least significant part of the field. */
- if (order == floatformat_little || order == floatformat_littlebyte_bigword)
+ if (order == floatformat_little)
{
/* We start counting from the other end (i.e, from the high bytes
rather than the low bytes). As such, we need to be concerned
else
result = 0;
cur_bitshift += FLOATFORMAT_CHAR_BIT;
- if (order == floatformat_little || order == floatformat_littlebyte_bigword)
+ if (order == floatformat_little)
++cur_byte;
else
--cur_byte;
{
result |= (unsigned long)*(data + cur_byte) << cur_bitshift;
cur_bitshift += FLOATFORMAT_CHAR_BIT;
- if (order == floatformat_little || order == floatformat_littlebyte_bigword)
- ++cur_byte;
- else
- --cur_byte;
+ switch (order)
+ {
+ case floatformat_little:
+ ++cur_byte;
+ break;
+ case floatformat_big:
+ --cur_byte;
+ break;
+ }
}
if (len < sizeof(result) * FLOATFORMAT_CHAR_BIT)
/* Mask out bits which are not part of the field */
return result;
}
+/* Normalize the byte order of FROM into TO. If no normalization is needed
+ then FMT->byteorder is returned and TO is not changed; otherwise the format
+ of the normalized form in TO is returned. */
+static enum floatformat_byteorders
+floatformat_normalize_byteorder (const struct floatformat *fmt,
+ const void *from, void *to)
+{
+ const unsigned char *swapin;
+ unsigned char *swapout;
+ int words;
+
+ if (fmt->byteorder == floatformat_little
+ || fmt->byteorder == floatformat_big)
+ return fmt->byteorder;
+
+ gdb_assert (fmt->byteorder == floatformat_littlebyte_bigword);
+
+ words = fmt->totalsize / FLOATFORMAT_CHAR_BIT;
+ words >>= 2;
+
+ swapout = (unsigned char *)to;
+ swapin = (const unsigned char *)from;
+
+ while (words-- > 0)
+ {
+ *swapout++ = swapin[3];
+ *swapout++ = swapin[2];
+ *swapout++ = swapin[1];
+ *swapout++ = swapin[0];
+ swapin += 4;
+ }
+ return floatformat_big;
+}
+
/* Convert from FMT to a DOUBLEST.
FROM is the address of the extended float.
Store the DOUBLEST in *TO. */
unsigned int mant_bits, mant_off;
int mant_bits_left;
int special_exponent; /* It's a NaN, denorm or zero */
+ enum floatformat_byteorders order;
+ unsigned char newfrom[FLOATFORMAT_LARGEST_BYTES];
+
+ gdb_assert (fmt->totalsize
+ <= FLOATFORMAT_LARGEST_BYTES * FLOATFORMAT_CHAR_BIT);
- /* If the mantissa bits are not contiguous from one end of the
- mantissa to the other, we need to make a private copy of the
- source bytes that is in the right order since the unpacking
- algorithm assumes that the bits are contiguous.
-
- Swap the bytes individually rather than accessing them through
- "long *" since we have no guarantee that they start on a long
- alignment, and also sizeof(long) for the host could be different
- than sizeof(long) for the target. FIXME: Assumes sizeof(long)
- for the target is 4. */
-
- if (fmt->byteorder == floatformat_littlebyte_bigword)
- {
- static unsigned char *newfrom;
- unsigned char *swapin, *swapout;
- int longswaps;
-
- longswaps = fmt->totalsize / FLOATFORMAT_CHAR_BIT;
- longswaps >>= 3;
+ order = floatformat_normalize_byteorder (fmt, ufrom, newfrom);
- if (newfrom == NULL)
- {
- newfrom = (unsigned char *) xmalloc (fmt->totalsize);
- }
- swapout = newfrom;
- swapin = ufrom;
- ufrom = newfrom;
- while (longswaps-- > 0)
- {
- /* This is ugly, but efficient */
- *swapout++ = swapin[4];
- *swapout++ = swapin[5];
- *swapout++ = swapin[6];
- *swapout++ = swapin[7];
- *swapout++ = swapin[0];
- *swapout++ = swapin[1];
- *swapout++ = swapin[2];
- *swapout++ = swapin[3];
- swapin += 8;
- }
- }
+ if (order != fmt->byteorder)
+ ufrom = newfrom;
- exponent = get_field (ufrom, fmt->byteorder, fmt->totalsize,
- fmt->exp_start, fmt->exp_len);
+ exponent = get_field (ufrom, order, fmt->totalsize, fmt->exp_start,
+ fmt->exp_len);
/* Note that if exponent indicates a NaN, we can't really do anything useful
(not knowing if the host has NaN's, or how to build one). So it will
end up as an infinity or something close; that is OK. */
if (!special_exponent)
exponent -= fmt->exp_bias;
else if (exponent == 0)
- exponent = 1 - (int) fmt->exp_bias;
+ exponent = 1 - fmt->exp_bias;
/* Build the result algebraically. Might go infinite, underflow, etc;
who cares. */
{
mant_bits = min (mant_bits_left, 32);
- mant = get_field (ufrom, fmt->byteorder, fmt->totalsize,
- mant_off, mant_bits);
+ mant = get_field (ufrom, order, fmt->totalsize, mant_off, mant_bits);
dto += ldexp ((double) mant, exponent - mant_bits);
exponent -= mant_bits;
}
/* Negate it if negative. */
- if (get_field (ufrom, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1))
+ if (get_field (ufrom, order, fmt->totalsize, fmt->sign_start, 1))
dto = -dto;
*to = dto;
}
unsigned int cur_byte;
int cur_bitshift;
+ /* Caller must byte-swap words before calling this routine. */
+ gdb_assert (order == floatformat_little || order == floatformat_big);
+
/* Start at the least significant part of the field. */
- if (order == floatformat_little || order == floatformat_littlebyte_bigword)
+ if (order == floatformat_little)
{
int excess = FLOATFORMAT_CHAR_BIT - (total_len % FLOATFORMAT_CHAR_BIT);
cur_byte = (total_len / FLOATFORMAT_CHAR_BIT)
(stuff_to_put & ((1 << FLOATFORMAT_CHAR_BIT) - 1)) << (-cur_bitshift);
}
cur_bitshift += FLOATFORMAT_CHAR_BIT;
- if (order == floatformat_little || order == floatformat_littlebyte_bigword)
+ if (order == floatformat_little)
++cur_byte;
else
--cur_byte;
*(data + cur_byte) = ((stuff_to_put >> cur_bitshift)
& ((1 << FLOATFORMAT_CHAR_BIT) - 1));
cur_bitshift += FLOATFORMAT_CHAR_BIT;
- if (order == floatformat_little || order == floatformat_littlebyte_bigword)
+ if (order == floatformat_little)
++cur_byte;
else
--cur_byte;
unsigned int mant_bits, mant_off;
int mant_bits_left;
unsigned char *uto = (unsigned char *) to;
+ enum floatformat_byteorders order = fmt->byteorder;
+
+ if (order == floatformat_littlebyte_bigword)
+ order = floatformat_big;
memcpy (&dfrom, from, sizeof (dfrom));
memset (uto, 0, (fmt->totalsize + FLOATFORMAT_CHAR_BIT - 1)
if (dfrom != dfrom) /* Result is NaN */
{
/* From is NaN */
- put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start,
+ put_field (uto, order, fmt->totalsize, fmt->exp_start,
fmt->exp_len, fmt->exp_nan);
/* Be sure it's not infinity, but NaN value is irrel */
- put_field (uto, fmt->byteorder, fmt->totalsize, fmt->man_start,
+ put_field (uto, order, fmt->totalsize, fmt->man_start,
32, 1);
- return;
+ goto finalize_byteorder;
}
/* If negative, set the sign bit. */
if (dfrom < 0)
{
- put_field (uto, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1, 1);
+ put_field (uto, order, fmt->totalsize, fmt->sign_start, 1, 1);
dfrom = -dfrom;
}
if (dfrom + dfrom == dfrom && dfrom != 0.0) /* Result is Infinity */
{
/* Infinity exponent is same as NaN's. */
- put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start,
+ put_field (uto, order, fmt->totalsize, fmt->exp_start,
fmt->exp_len, fmt->exp_nan);
/* Infinity mantissa is all zeroes. */
- put_field (uto, fmt->byteorder, fmt->totalsize, fmt->man_start,
+ put_field (uto, order, fmt->totalsize, fmt->man_start,
fmt->man_len, 0);
- return;
+ goto finalize_byteorder;
}
#ifdef HAVE_LONG_DOUBLE
mant = frexp (dfrom, &exponent);
#endif
- put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start, fmt->exp_len,
+ put_field (uto, order, fmt->totalsize, fmt->exp_start, fmt->exp_len,
exponent + fmt->exp_bias - 1);
mant_bits_left = fmt->man_len;
{
mant_long <<= 1;
mant_long &= 0xffffffffL;
- mant_bits -= 1;
+ /* If we are processing the top 32 mantissa bits of a doublest
+ so as to convert to a float value with implied integer bit,
+ we will only be putting 31 of those 32 bits into the
+ final value due to the discarding of the top bit. In the
+ case of a small float value where the number of mantissa
+ bits is less than 32, discarding the top bit does not alter
+ the number of bits we will be adding to the result. */
+ if (mant_bits == 32)
+ mant_bits -= 1;
}
if (mant_bits < 32)
mant_long >>= 32 - mant_bits;
}
- put_field (uto, fmt->byteorder, fmt->totalsize,
+ put_field (uto, order, fmt->totalsize,
mant_off, mant_bits, mant_long);
mant_off += mant_bits;
mant_bits_left -= mant_bits;
}
- if (fmt->byteorder == floatformat_littlebyte_bigword)
+
+ finalize_byteorder:
+ /* Do we need to byte-swap the words in the result? */
+ if (order != fmt->byteorder)
{
- int count;
- unsigned char *swaplow = uto;
- unsigned char *swaphigh = uto + 4;
+ int words;
+ unsigned char *curword = uto;
unsigned char tmp;
- for (count = 0; count < 4; count++)
+ words = fmt->totalsize / FLOATFORMAT_CHAR_BIT;
+ words >>= 2;
+ while (words-- > 0)
{
- tmp = *swaplow;
- *swaplow++ = *swaphigh;
- *swaphigh++ = tmp;
+ tmp = curword[0];
+ curword[0] = curword[3];
+ curword[3] = tmp;
+ tmp = curword[1];
+ curword[1] = curword[2];
+ curword[2] = tmp;
+ curword += 4;
}
}
}
format is described by FMT) is negative. */
int
-floatformat_is_negative (const struct floatformat *fmt, char *val)
+floatformat_is_negative (const struct floatformat *fmt,
+ const bfd_byte *uval)
{
- unsigned char *uval = (unsigned char *) val;
+ enum floatformat_byteorders order;
+ unsigned char newfrom[FLOATFORMAT_LARGEST_BYTES];
+
gdb_assert (fmt != NULL);
- return get_field (uval, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1);
+ gdb_assert (fmt->totalsize
+ <= FLOATFORMAT_LARGEST_BYTES * FLOATFORMAT_CHAR_BIT);
+
+ order = floatformat_normalize_byteorder (fmt, uval, newfrom);
+
+ if (order != fmt->byteorder)
+ uval = newfrom;
+
+ return get_field (uval, order, fmt->totalsize, fmt->sign_start, 1);
}
/* Check if VAL is "not a number" (NaN) for FMT. */
int
-floatformat_is_nan (const struct floatformat *fmt, char *val)
+floatformat_is_nan (const struct floatformat *fmt,
+ const bfd_byte *uval)
{
- unsigned char *uval = (unsigned char *) val;
long exponent;
unsigned long mant;
unsigned int mant_bits, mant_off;
int mant_bits_left;
-
+ enum floatformat_byteorders order;
+ unsigned char newfrom[FLOATFORMAT_LARGEST_BYTES];
+
gdb_assert (fmt != NULL);
+ gdb_assert (fmt->totalsize
+ <= FLOATFORMAT_LARGEST_BYTES * FLOATFORMAT_CHAR_BIT);
+
+ order = floatformat_normalize_byteorder (fmt, uval, newfrom);
+
+ if (order != fmt->byteorder)
+ uval = newfrom;
if (! fmt->exp_nan)
return 0;
- exponent = get_field (uval, fmt->byteorder, fmt->totalsize,
- fmt->exp_start, fmt->exp_len);
+ exponent = get_field (uval, order, fmt->totalsize, fmt->exp_start,
+ fmt->exp_len);
if (exponent != fmt->exp_nan)
return 0;
{
mant_bits = min (mant_bits_left, 32);
- mant = get_field (uval, fmt->byteorder, fmt->totalsize,
- mant_off, mant_bits);
+ mant = get_field (uval, order, fmt->totalsize, mant_off, mant_bits);
/* If there is an explicit integer bit, mask it off. */
if (mant_off == fmt->man_start
point number whose format is described by FMT) into a hexadecimal
and store it in a static string. Return a pointer to that string. */
-char *
-floatformat_mantissa (const struct floatformat *fmt, char *val)
+const char *
+floatformat_mantissa (const struct floatformat *fmt,
+ const bfd_byte *val)
{
unsigned char *uval = (unsigned char *) val;
unsigned long mant;
int mant_bits_left;
static char res[50];
char buf[9];
+ enum floatformat_byteorders order;
+ unsigned char newfrom[FLOATFORMAT_LARGEST_BYTES];
+
+ gdb_assert (fmt != NULL);
+ gdb_assert (fmt->totalsize
+ <= FLOATFORMAT_LARGEST_BYTES * FLOATFORMAT_CHAR_BIT);
+
+ order = floatformat_normalize_byteorder (fmt, uval, newfrom);
+
+ if (order != fmt->byteorder)
+ uval = newfrom;
+
+ if (! fmt->exp_nan)
+ return 0;
/* Make sure we have enough room to store the mantissa. */
- gdb_assert (fmt != NULL);
gdb_assert (sizeof res > ((fmt->man_len + 7) / 8) * 2);
mant_off = fmt->man_start;
mant_bits_left = fmt->man_len;
mant_bits = (mant_bits_left % 32) > 0 ? mant_bits_left % 32 : 32;
- mant = get_field (uval, fmt->byteorder, fmt->totalsize,
- mant_off, mant_bits);
+ mant = get_field (uval, order, fmt->totalsize, mant_off, mant_bits);
sprintf (res, "%lx", mant);
while (mant_bits_left > 0)
{
- mant = get_field (uval, fmt->byteorder, fmt->totalsize,
- mant_off, 32);
+ mant = get_field (uval, order, fmt->totalsize, mant_off, 32);
sprintf (buf, "%08lx", mant);
strcat (res, buf);
increase precision as necessary. Otherwise, we call the conversion
routine and let it do the dirty work. */
-#ifndef HOST_FLOAT_FORMAT
-#define HOST_FLOAT_FORMAT 0
-#endif
-#ifndef HOST_DOUBLE_FORMAT
-#define HOST_DOUBLE_FORMAT 0
-#endif
-#ifndef HOST_LONG_DOUBLE_FORMAT
-#define HOST_LONG_DOUBLE_FORMAT 0
-#endif
-
-static const struct floatformat *host_float_format = HOST_FLOAT_FORMAT;
-static const struct floatformat *host_double_format = HOST_DOUBLE_FORMAT;
-static const struct floatformat *host_long_double_format = HOST_LONG_DOUBLE_FORMAT;
+static const struct floatformat *host_float_format = GDB_HOST_FLOAT_FORMAT;
+static const struct floatformat *host_double_format = GDB_HOST_DOUBLE_FORMAT;
+static const struct floatformat *host_long_double_format = GDB_HOST_LONG_DOUBLE_FORMAT;
void
floatformat_to_doublest (const struct floatformat *fmt,
\f
/* Return a floating-point format for a floating-point variable of
- length LEN. Return NULL, if no suitable floating-point format
- could be found.
+ length LEN. If no suitable floating-point format is found, an
+ error is thrown.
We need this functionality since information about the
floating-point format of a type is not always available to GDB; the
target-dependent code, the format of floating-point types is known,
but not passed on by GDB. This should be fixed. */
-const struct floatformat *
+static const struct floatformat *
floatformat_from_length (int len)
{
+ const struct floatformat *format;
if (len * TARGET_CHAR_BIT == TARGET_FLOAT_BIT)
- return TARGET_FLOAT_FORMAT;
+ format = TARGET_FLOAT_FORMAT;
else if (len * TARGET_CHAR_BIT == TARGET_DOUBLE_BIT)
- return TARGET_DOUBLE_FORMAT;
+ format = TARGET_DOUBLE_FORMAT;
else if (len * TARGET_CHAR_BIT == TARGET_LONG_DOUBLE_BIT)
- return TARGET_LONG_DOUBLE_FORMAT;
+ format = TARGET_LONG_DOUBLE_FORMAT;
/* On i386 the 'long double' type takes 96 bits,
while the real number of used bits is only 80,
both in processor and in memory.
else if ((TARGET_LONG_DOUBLE_FORMAT != NULL)
&& (len * TARGET_CHAR_BIT ==
TARGET_LONG_DOUBLE_FORMAT->totalsize))
- return TARGET_LONG_DOUBLE_FORMAT;
-
- return NULL;
+ format = TARGET_LONG_DOUBLE_FORMAT;
+ else
+ format = NULL;
+ if (format == NULL)
+ error (_("Unrecognized %d-bit floating-point type."),
+ len * TARGET_CHAR_BIT);
+ return format;
}
const struct floatformat *
const struct floatformat *fmt = floatformat_from_length (len);
DOUBLEST val;
- if (fmt == NULL)
- {
- warning ("Can't extract a floating-point number of %d bytes.", len);
- return NAN;
- }
-
floatformat_to_doublest (fmt, addr, &val);
return val;
}
{
const struct floatformat *fmt = floatformat_from_length (len);
- if (fmt == NULL)
- {
- warning ("Can't store a floating-point number of %d bytes.", len);
- memset (addr, 0, len);
- return;
- }
-
floatformat_from_doublest (fmt, &val, addr);
}
assumption might be wrong on targets that support
floating-point types that only differ in endianness for
example. So we warn instead, and zero out the target buffer. */
- warning ("Can't convert floating-point number to desired type.");
+ warning (_("Can't convert floating-point number to desired type."));
memset (to, 0, TYPE_LENGTH (to_type));
}
else if (from_fmt == to_fmt)
floatformat_from_doublest (to_fmt, &d, to);
}
}
+
+const struct floatformat *floatformat_ieee_single[BFD_ENDIAN_UNKNOWN];
+const struct floatformat *floatformat_ieee_double[BFD_ENDIAN_UNKNOWN];
+const struct floatformat *floatformat_ieee_quad[BFD_ENDIAN_UNKNOWN];
+const struct floatformat *floatformat_arm_ext[BFD_ENDIAN_UNKNOWN];
+const struct floatformat *floatformat_ia64_spill[BFD_ENDIAN_UNKNOWN];
+
+extern void _initialize_doublest (void);
+
+extern void
+_initialize_doublest (void)
+{
+ floatformat_ieee_single[BFD_ENDIAN_LITTLE] = &floatformat_ieee_single_little;
+ floatformat_ieee_single[BFD_ENDIAN_BIG] = &floatformat_ieee_single_big;
+ floatformat_ieee_double[BFD_ENDIAN_LITTLE] = &floatformat_ieee_double_little;
+ floatformat_ieee_double[BFD_ENDIAN_BIG] = &floatformat_ieee_double_big;
+ floatformat_arm_ext[BFD_ENDIAN_LITTLE] = &floatformat_arm_ext_littlebyte_bigword;
+ floatformat_arm_ext[BFD_ENDIAN_BIG] = &floatformat_arm_ext_big;
+ floatformat_ia64_spill[BFD_ENDIAN_LITTLE] = &floatformat_ia64_spill_little;
+ floatformat_ia64_spill[BFD_ENDIAN_BIG] = &floatformat_ia64_spill_big;
+ floatformat_ieee_quad[BFD_ENDIAN_LITTLE] = &floatformat_ia64_quad_little;
+ floatformat_ieee_quad[BFD_ENDIAN_BIG] = &floatformat_ia64_quad_big;
+}