/* Floating point routines for GDB, the GNU debugger.
- Copyright (C) 1986, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996,
- 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2007, 2008, 2009
- Free Software Foundation, Inc.
+ Copyright (C) 1986-2015 Free Software Foundation, Inc.
This file is part of GDB.
#include "defs.h"
#include "doublest.h"
#include "floatformat.h"
-#include "gdb_assert.h"
-#include "gdb_string.h"
#include "gdbtypes.h"
#include <math.h> /* ldexp */
{
/* 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
- with what happens if bit 0 doesn't start on a byte boundary.
+ with what happens if bit 0 doesn't start on a byte boundary.
I.e, we need to properly handle the case where total_len is
not evenly divisible by 8. So we compute ``excess'' which
represents the number of bits from the end of our starting
- byte needed to get to bit 0. */
+ byte needed to get to bit 0. */
int excess = FLOATFORMAT_CHAR_BIT - (total_len % FLOATFORMAT_CHAR_BIT);
+
cur_byte = (total_len / FLOATFORMAT_CHAR_BIT)
- ((start + len + excess) / FLOATFORMAT_CHAR_BIT);
cur_bitshift = ((start + len + excess) % FLOATFORMAT_CHAR_BIT)
}
}
if (len < sizeof(result) * FLOATFORMAT_CHAR_BIT)
- /* Mask out bits which are not part of the field */
+ /* Mask out bits which are not part of the field. */
result &= ((1UL << len) - 1);
return result;
}
unsigned long mant;
unsigned int mant_bits, mant_off;
int mant_bits_left;
- int special_exponent; /* It's a NaN, denorm or zero */
+ int special_exponent; /* It's a NaN, denorm or zero. */
enum floatformat_byteorders order;
unsigned char newfrom[FLOATFORMAT_LARGEST_BYTES];
enum float_kind kind;
if (kind == float_infinite || kind == float_nan)
{
double dto;
- floatformat_to_double (fmt, from, &dto);
+
+ floatformat_to_double (fmt->split_half ? fmt->split_half : fmt,
+ from, &dto);
*to = (DOUBLEST) dto;
return;
}
if (fmt->split_half)
{
DOUBLEST dtop, dbot;
+
floatformat_to_doublest (fmt->split_half, ufrom, &dtop);
/* Preserve the sign of 0, which is the sign of the top
half. */
special_exponent = exponent == 0 || exponent == fmt->exp_nan;
- /* Don't bias NaNs. Use minimum exponent for denorms. For simplicity,
- we don't check for zero as the exponent doesn't matter. Note the cast
- to int; exp_bias is unsigned, so it's important to make sure the
- operation is done in signed arithmetic. */
+ /* Don't bias NaNs. Use minimum exponent for denorms. For
+ simplicity, we don't check for zero as the exponent doesn't matter.
+ Note the cast to int; exp_bias is unsigned, so it's important to
+ make sure the operation is done in signed arithmetic. */
if (!special_exponent)
exponent -= fmt->exp_bias;
else if (exponent == 0)
exponent = 1 - fmt->exp_bias;
/* Build the result algebraically. Might go infinite, underflow, etc;
- who cares. */
+ who cares. */
/* If this format uses a hidden bit, explicitly add it in now. Otherwise,
increment the exponent by one to account for the integer bit. */
*to = dto;
}
\f
-static void put_field (unsigned char *, enum floatformat_byteorders,
- unsigned int,
- unsigned int, unsigned int, unsigned long);
-
/* Set 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 void
if (order == floatformat_little)
{
int excess = FLOATFORMAT_CHAR_BIT - (total_len % FLOATFORMAT_CHAR_BIT);
+
cur_byte = (total_len / FLOATFORMAT_CHAR_BIT)
- ((start + len + excess) / FLOATFORMAT_CHAR_BIT);
cur_bitshift = ((start + len + excess) % FLOATFORMAT_CHAR_BIT)
}
}
-#ifdef HAVE_LONG_DOUBLE
-/* Return the fractional part of VALUE, and put the exponent of VALUE in *EPTR.
- The range of the returned value is >= 0.5 and < 1.0. This is equivalent to
- frexp, but operates on the long double data type. */
-
-static long double ldfrexp (long double value, int *eptr);
-
-static long double
-ldfrexp (long double value, int *eptr)
-{
- long double tmp;
- int exp;
-
- /* Unfortunately, there are no portable functions for extracting the exponent
- of a long double, so we have to do it iteratively by multiplying or dividing
- by two until the fraction is between 0.5 and 1.0. */
-
- if (value < 0.0l)
- value = -value;
-
- tmp = 1.0l;
- exp = 0;
-
- if (value >= tmp) /* Value >= 1.0 */
- while (value >= tmp)
- {
- tmp *= 2.0l;
- exp++;
- }
- else if (value != 0.0l) /* Value < 1.0 and > 0.0 */
- {
- while (value < tmp)
- {
- tmp /= 2.0l;
- exp--;
- }
- tmp *= 2.0l;
- exp++;
- }
-
- *eptr = exp;
- return value / tmp;
-}
-#endif /* HAVE_LONG_DOUBLE */
-
-
/* The converse: convert the DOUBLEST *FROM to an extended float and
store where TO points. Neither FROM nor TO have any alignment
restrictions. */
static void
-convert_doublest_to_floatformat (CONST struct floatformat *fmt,
+convert_doublest_to_floatformat (const struct floatformat *fmt,
const DOUBLEST *from, void *to)
{
DOUBLEST dfrom;
the result of converting to double. */
static volatile double dtop, dbot;
DOUBLEST dtopnv, dbotnv;
+
dtop = (double) dfrom;
/* If the rounded top half is Inf, the bottom must be 0 not NaN
or Inf. */
/* From is NaN */
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 */
+ /* Be sure it's not infinity, but NaN value is irrel. */
put_field (uto, order, fmt->totalsize, fmt->man_start,
- 32, 1);
+ fmt->man_len, 1);
goto finalize_byteorder;
}
dfrom = -dfrom;
}
- if (dfrom + dfrom == dfrom && dfrom != 0.0) /* Result is Infinity */
+ if (dfrom + dfrom == dfrom && dfrom != 0.0) /* Result is Infinity. */
{
/* Infinity exponent is same as NaN's. */
put_field (uto, order, fmt->totalsize, fmt->exp_start,
}
#ifdef HAVE_LONG_DOUBLE
- mant = ldfrexp (dfrom, &exponent);
+ mant = frexpl (dfrom, &exponent);
#else
mant = frexp (dfrom, &exponent);
#endif
+ if (exponent + fmt->exp_bias <= 0)
+ {
+ /* The value is too small to be expressed in the destination
+ type (not enough bits in the exponent. Treat as 0. */
+ put_field (uto, order, fmt->totalsize, fmt->exp_start,
+ fmt->exp_len, 0);
+ put_field (uto, order, fmt->totalsize, fmt->man_start,
+ fmt->man_len, 0);
+ goto finalize_byteorder;
+ }
+
+ if (exponent + fmt->exp_bias >= (1 << fmt->exp_len))
+ {
+ /* The value is too large to fit into the destination.
+ Treat as infinity. */
+ put_field (uto, order, fmt->totalsize, fmt->exp_start,
+ fmt->exp_len, fmt->exp_nan);
+ put_field (uto, order, fmt->totalsize, fmt->man_start,
+ fmt->man_len, 0);
+ goto finalize_byteorder;
+ }
+
put_field (uto, order, fmt->totalsize, fmt->exp_start, fmt->exp_len,
exponent + fmt->exp_bias - 1);
while (mant_bits_left > 0)
{
unsigned long mant_long;
+
mant_bits = mant_bits_left < 32 ? mant_bits_left : 32;
mant *= 4294967296.0;
gdb_assert (fmt->totalsize
<= FLOATFORMAT_LARGEST_BYTES * FLOATFORMAT_CHAR_BIT);
+ /* An IBM long double (a two element array of double) always takes the
+ sign of the first double. */
+ if (fmt->split_half)
+ fmt = fmt->split_half;
+
order = floatformat_normalize_byteorder (fmt, uval, newfrom);
if (order != fmt->byteorder)
gdb_assert (fmt->totalsize
<= FLOATFORMAT_LARGEST_BYTES * FLOATFORMAT_CHAR_BIT);
+ /* An IBM long double (a two element array of double) can be classified
+ by looking at the first double. inf and nan are specified as
+ ignoring the second double. zero and subnormal will always have
+ the second double 0.0 if the long double is correctly rounded. */
+ if (fmt->split_half)
+ fmt = fmt->split_half;
+
order = floatformat_normalize_byteorder (fmt, uval, newfrom);
if (order != fmt->byteorder)
gdb_assert (fmt->totalsize
<= FLOATFORMAT_LARGEST_BYTES * FLOATFORMAT_CHAR_BIT);
+ /* For IBM long double (a two element array of double), return the
+ mantissa of the first double. The problem with returning the
+ actual mantissa from both doubles is that there can be an
+ arbitrary number of implied 0's or 1's between the mantissas
+ of the first and second double. In any case, this function
+ is only used for dumping out nans, and a nan is specified to
+ ignore the value in the second double. */
+ if (fmt->split_half)
+ fmt = fmt->split_half;
+
order = floatformat_normalize_byteorder (fmt, uval, newfrom);
if (order != fmt->byteorder)
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;
+static const struct floatformat *host_long_double_format
+ = GDB_HOST_LONG_DOUBLE_FORMAT;
void
floatformat_to_doublest (const struct floatformat *fmt,
if (fmt == host_float_format)
{
float val;
+
memcpy (&val, in, sizeof (val));
*out = val;
}
else if (fmt == host_double_format)
{
double val;
+
memcpy (&val, in, sizeof (val));
*out = val;
}
else if (fmt == host_long_double_format)
{
long double val;
+
memcpy (&val, in, sizeof (val));
*out = val;
}
if (fmt == host_float_format)
{
float val = *in;
+
memcpy (out, &val, sizeof (val));
}
else if (fmt == host_double_format)
{
double val = *in;
+
memcpy (out, &val, sizeof (val));
}
else if (fmt == host_long_double_format)
{
long double val = *in;
+
memcpy (out, &val, sizeof (val));
}
else
floatformat_from_length (struct gdbarch *gdbarch, int len)
{
const struct floatformat *format;
- if (len * TARGET_CHAR_BIT == gdbarch_float_bit (gdbarch))
+
+ if (len * TARGET_CHAR_BIT == gdbarch_half_bit (gdbarch))
+ format = gdbarch_half_format (gdbarch)
+ [gdbarch_byte_order (gdbarch)];
+ else if (len * TARGET_CHAR_BIT == gdbarch_float_bit (gdbarch))
format = gdbarch_float_format (gdbarch)
[gdbarch_byte_order (gdbarch)];
else if (len * TARGET_CHAR_BIT == gdbarch_double_bit (gdbarch))
[gdbarch_byte_order (gdbarch)];
/* 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.
+ both in processor and in memory.
The code below accepts the real bit size. */
else if ((gdbarch_long_double_format (gdbarch) != NULL)
&& (len * TARGET_CHAR_BIT
floatformat_from_type (const struct type *type)
{
struct gdbarch *gdbarch = get_type_arch (type);
+
gdb_assert (TYPE_CODE (type) == TYPE_CODE_FLT);
if (TYPE_FLOATFORMAT (type) != NULL)
return TYPE_FLOATFORMAT (type)[gdbarch_byte_order (gdbarch)];
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;
-}