Index: gdb/doublest.c |
diff --git a/gdb/doublest.c b/gdb/doublest.c |
index c8c9e05932c29de15524a5af8c704014d2a8f091..a4889c976cd78be19ad851eb9184f5556fa96263 100644 |
--- a/gdb/doublest.c |
+++ b/gdb/doublest.c |
@@ -1,7 +1,6 @@ |
/* Floating point routines for GDB, the GNU debugger. |
- Copyright (C) 1986, 1988-2001, 2003-2005, 2007-2012 Free Software |
- Foundation, Inc. |
+ Copyright (C) 1986-2013 Free Software Foundation, Inc. |
This file is part of GDB. |
@@ -28,7 +27,7 @@ |
#include "doublest.h" |
#include "floatformat.h" |
#include "gdb_assert.h" |
-#include "gdb_string.h" |
+#include <string.h> |
#include "gdbtypes.h" |
#include <math.h> /* ldexp */ |
@@ -191,7 +190,8 @@ convert_floatformat_to_doublest (const struct floatformat *fmt, |
{ |
double dto; |
- floatformat_to_double (fmt, from, &dto); |
+ floatformat_to_double (fmt->split_half ? fmt->split_half : fmt, |
+ from, &dto); |
*to = (DOUBLEST) dto; |
return; |
} |
@@ -337,53 +337,6 @@ put_field (unsigned char *data, enum floatformat_byteorders order, |
} |
} |
-#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. */ |
@@ -467,11 +420,33 @@ convert_doublest_to_floatformat (CONST struct floatformat *fmt, |
} |
#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); |
@@ -540,6 +515,11 @@ floatformat_is_negative (const struct floatformat *fmt, |
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) |
@@ -566,6 +546,13 @@ floatformat_classify (const struct floatformat *fmt, |
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) |
@@ -648,6 +635,16 @@ floatformat_mantissa (const struct floatformat *fmt, |
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) |
@@ -905,27 +902,3 @@ convert_typed_floating (const void *from, const struct type *from_type, |
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; |
-} |