2007-11-07  Joseph Myers  <joseph@codesourcery.com>
	    Daniel Jacobowitz  <dan@codesourcery.com>

	* floatformat.h (struct floatformat): Add split_half field.
	(floatformat_ibm_long_double): New.

libiberty:
2007-11-07  Joseph Myers  <joseph@codesourcery.com>
	    Daniel Jacobowitz  <dan@codesourcery.com>

	* floatformat.c (mant_bits_set): New.
	(floatformat_to_double): Use it.  Note no special handling of
	split formats.
	(floatformat_from_double): Note no special handing of split
	formats.
	(floatformat_ibm_long_double_is_valid,
	floatformat_ibm_long_double): New.
	(floatformat_ieee_single_big, floatformat_ieee_single_little,
	floatformat_ieee_double_big, floatformat_ieee_double_little,
	floatformat_ieee_double_littlebyte_bigword, floatformat_vax_f,
	floatformat_vax_d, floatformat_vax_g, floatformat_i387_ext,
	floatformat_m68881_ext, floatformat_i960_ext,
	floatformat_m88110_ext, floatformat_m88110_harris_ext,
	floatformat_arm_ext_big, floatformat_arm_ext_littlebyte_bigword,
	floatformat_ia64_spill_big, floatformat_ia64_spill_little,
	floatformat_ia64_quad_big, floatformat_ia64_quad_little): Update
	for addition of split_half field.

gdb:
2007-11-07  Joseph Myers  <joseph@codesourcery.com>
	    Daniel Jacobowitz  <dan@codesourcery.com>

	* gdbtypes.c (floatformats_ibm_long_double): New.
	* gdbtypes.h (floatformats_ibm_long_double): Declare.
	* ia64-tdep.c (floatformat_ia64_ext): Update for addition of
	split_half field.
	* mips-tdep.c (n32n64_floatformat_always_valid,
	floatformat_n32n64_long_double_big, floatformats_n32n64_long):
	Remove.
	(mips_gdbarch_init): Use floatformats_ibm_long_double instead of
	floatformats_n32n64_long.
	* ppc-linux-tdep.c (ppc_linux_init_abi): Use 128-bit IBM long
	double.
	* doublest.c (convert_floatformat_to_doublest,
	convert_doublest_to_floatformat): Handle split floating-point
	formats.
	* ppc-sysv-tdep.c (ppc_sysv_abi_push_dummy_call): Handle IBM long
	double arguments.
	(ppc64_sysv_abi_push_dummy_call): Likewise.
	(do_ppc_sysv_return_value): Handle IBM long double return.
This commit is contained in:
Joseph Myers 2007-11-08 00:08:48 +00:00
parent 5d324c3ec4
commit b14d30e141
12 changed files with 435 additions and 90 deletions

View File

@ -1,3 +1,25 @@
2007-11-07 Joseph Myers <joseph@codesourcery.com>
Daniel Jacobowitz <dan@codesourcery.com>
* gdbtypes.c (floatformats_ibm_long_double): New.
* gdbtypes.h (floatformats_ibm_long_double): Declare.
* ia64-tdep.c (floatformat_ia64_ext): Update for addition of
split_half field.
* mips-tdep.c (n32n64_floatformat_always_valid,
floatformat_n32n64_long_double_big, floatformats_n32n64_long):
Remove.
(mips_gdbarch_init): Use floatformats_ibm_long_double instead of
floatformats_n32n64_long.
* ppc-linux-tdep.c (ppc_linux_init_abi): Use 128-bit IBM long
double.
* doublest.c (convert_floatformat_to_doublest,
convert_doublest_to_floatformat): Handle split floating-point
formats.
* ppc-sysv-tdep.c (ppc_sysv_abi_push_dummy_call): Handle IBM long
double arguments.
(ppc64_sysv_abi_push_dummy_call): Likewise.
(do_ppc_sysv_return_value): Handle IBM long double return.
2007-11-07 Vladimir Prus <vladimir@codesourcery.com>
Fix crash when a variable object being deleted

View File

@ -200,6 +200,24 @@ convert_floatformat_to_doublest (const struct floatformat *fmt,
if (order != fmt->byteorder)
ufrom = newfrom;
if (fmt->split_half)
{
double dtop, dbot;
floatformat_to_double (fmt->split_half, ufrom, &dtop);
/* Preserve the sign of 0, which is the sign of the top
half. */
if (dtop == 0.0)
{
*to = (DOUBLEST) dtop;
return;
}
floatformat_to_double (fmt->split_half,
ufrom + fmt->totalsize / FLOATFORMAT_CHAR_BIT / 2,
&dbot);
*to = (DOUBLEST) dtop + (DOUBLEST) dbot;
return;
}
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
@ -392,6 +410,30 @@ convert_doublest_to_floatformat (CONST struct floatformat *fmt,
memcpy (&dfrom, from, sizeof (dfrom));
memset (uto, 0, (fmt->totalsize + FLOATFORMAT_CHAR_BIT - 1)
/ FLOATFORMAT_CHAR_BIT);
if (fmt->split_half)
{
/* Use static volatile to ensure that any excess precision is
removed via storing in memory, and so the top half really is
the result of converting to double. */
static volatile double dtop, dbot;
double dtopnv, dbotnv;
dtop = (double) dfrom;
/* If the rounded top half is Inf, the bottom must be 0 not NaN
or Inf. */
if (dtop + dtop == dtop && dtop != 0.0)
dbot = 0.0;
else
dbot = (double) (dfrom - (DOUBLEST) dtop);
dtopnv = dtop;
dbotnv = dbot;
floatformat_from_double (fmt->split_half, &dtopnv, uto);
floatformat_from_double (fmt->split_half, &dbotnv,
(uto
+ fmt->totalsize / FLOATFORMAT_CHAR_BIT / 2));
return;
}
if (dfrom == 0)
return; /* Result is zero */
if (dfrom != dfrom) /* Result is NaN */

View File

@ -95,6 +95,10 @@ const struct floatformat *floatformats_vax_d[BFD_ENDIAN_UNKNOWN] = {
&floatformat_vax_d,
&floatformat_vax_d
};
const struct floatformat *floatformats_ibm_long_double[BFD_ENDIAN_UNKNOWN] = {
&floatformat_ibm_long_double,
&floatformat_ibm_long_double
};
struct type *builtin_type_ieee_single;
struct type *builtin_type_ieee_double;

View File

@ -1099,6 +1099,7 @@ extern const struct floatformat *floatformats_ia64_spill[BFD_ENDIAN_UNKNOWN];
extern const struct floatformat *floatformats_ia64_quad[BFD_ENDIAN_UNKNOWN];
extern const struct floatformat *floatformats_vax_f[BFD_ENDIAN_UNKNOWN];
extern const struct floatformat *floatformats_vax_d[BFD_ENDIAN_UNKNOWN];
extern const struct floatformat *floatformats_ibm_long_double[BFD_ENDIAN_UNKNOWN];
extern struct type *builtin_type_ieee_single;
extern struct type *builtin_type_ieee_double;

View File

@ -329,7 +329,7 @@ floatformat_valid (const struct floatformat *fmt, const void *from)
const struct floatformat floatformat_ia64_ext =
{
floatformat_little, 82, 0, 1, 17, 65535, 0x1ffff, 18, 64,
floatformat_intbit_yes, "floatformat_ia64_ext", floatformat_valid
floatformat_intbit_yes, "floatformat_ia64_ext", floatformat_valid, NULL
};
const struct floatformat *floatformats_ia64_ext[2] =

View File

@ -199,38 +199,6 @@ struct gdbarch_tdep
int register_size;
};
static int
n32n64_floatformat_always_valid (const struct floatformat *fmt,
const void *from)
{
return 1;
}
/* FIXME: brobecker/2004-08-08: Long Double values are 128 bit long.
They are implemented as a pair of 64bit doubles where the high
part holds the result of the operation rounded to double, and
the low double holds the difference between the exact result and
the rounded result. So "high" + "low" contains the result with
added precision. Unfortunately, the floatformat structure used
by GDB is not powerful enough to describe this format. As a temporary
measure, we define a 128bit floatformat that only uses the high part.
We lose a bit of precision but that's probably the best we can do
for now with the current infrastructure. */
static const struct floatformat floatformat_n32n64_long_double_big =
{
floatformat_big, 128, 0, 1, 11, 1023, 2047, 12, 52,
floatformat_intbit_no,
"floatformat_n32n64_long_double_big",
n32n64_floatformat_always_valid
};
static const struct floatformat *floatformats_n32n64_long[BFD_ENDIAN_UNKNOWN] =
{
&floatformat_n32n64_long_double_big,
&floatformat_n32n64_long_double_big
};
const struct mips_regnum *
mips_regnum (struct gdbarch *gdbarch)
{
@ -5585,7 +5553,7 @@ mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
set_gdbarch_ptr_bit (gdbarch, 32);
set_gdbarch_long_long_bit (gdbarch, 64);
set_gdbarch_long_double_bit (gdbarch, 128);
set_gdbarch_long_double_format (gdbarch, floatformats_n32n64_long);
set_gdbarch_long_double_format (gdbarch, floatformats_ibm_long_double);
break;
case MIPS_ABI_N64:
set_gdbarch_push_dummy_call (gdbarch, mips_n32n64_push_dummy_call);
@ -5597,7 +5565,7 @@ mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
set_gdbarch_ptr_bit (gdbarch, 64);
set_gdbarch_long_long_bit (gdbarch, 64);
set_gdbarch_long_double_bit (gdbarch, 128);
set_gdbarch_long_double_format (gdbarch, floatformats_n32n64_long);
set_gdbarch_long_double_format (gdbarch, floatformats_ibm_long_double);
break;
default:
internal_error (__FILE__, __LINE__, _("unknown ABI in switch"));

View File

@ -896,15 +896,13 @@ ppc_linux_init_abi (struct gdbarch_info info,
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
/* NOTE: jimb/2004-03-26: The System V ABI PowerPC Processor
Supplement says that long doubles are sixteen bytes long.
However, as one of the known warts of its ABI, PPC GNU/Linux uses
eight-byte long doubles. GCC only recently got 128-bit long
double support on PPC, so it may be changing soon. The
Linux[sic] Standards Base says that programs that use 'long
double' on PPC GNU/Linux are non-conformant. */
/* NOTE: cagney/2005-01-25: True for both 32- and 64-bit. */
set_gdbarch_long_double_bit (gdbarch, 8 * TARGET_CHAR_BIT);
/* PPC GNU/Linux uses either 64-bit or 128-bit long doubles; where
128-bit, they are IBM long double, not IEEE quad long double as
in the System V ABI PowerPC Processor Supplement. We can safely
let them default to 128-bit, since the debug info will give the
size of type actually used in each case. */
set_gdbarch_long_double_bit (gdbarch, 16 * TARGET_CHAR_BIT);
set_gdbarch_long_double_format (gdbarch, floatformats_ibm_long_double);
/* Handle PPC GNU/Linux 64-bit function pointers (which are really
function descriptors) and 32-bit secure PLT entries. */

View File

@ -53,6 +53,8 @@ ppc_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
int argspace = 0; /* 0 is an initial wrong guess. */
int write_pass;
gdb_assert (tdep->wordsize == 4);
regcache_cooked_read_unsigned (regcache,
gdbarch_sp_regnum (current_gdbarch),
&saved_sp);
@ -141,6 +143,35 @@ ppc_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
argoffset += 8;
}
}
else if (TYPE_CODE (type) == TYPE_CODE_FLT
&& len == 16
&& !tdep->soft_float
&& (gdbarch_long_double_format (current_gdbarch)
== floatformats_ibm_long_double))
{
/* IBM long double passed in two FP registers if
available, otherwise 8-byte aligned stack. */
if (freg <= 7)
{
if (write_pass)
{
regcache_cooked_write (regcache,
tdep->ppc_fp0_regnum + freg,
val);
regcache_cooked_write (regcache,
tdep->ppc_fp0_regnum + freg + 1,
val + 8);
}
freg += 2;
}
else
{
argoffset = align_up (argoffset, 8);
if (write_pass)
write_memory (sp + argoffset, val, len);
argoffset += 16;
}
}
else if (len == 8
&& (TYPE_CODE (type) == TYPE_CODE_INT /* long long */
|| TYPE_CODE (type) == TYPE_CODE_FLT)) /* double */
@ -159,13 +190,6 @@ ppc_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
write_memory (sp + argoffset, val, len);
argoffset += 8;
}
else if (tdep->wordsize == 8)
{
if (write_pass)
regcache_cooked_write (regcache,
tdep->ppc_gp0_regnum + greg, val);
greg += 1;
}
else
{
/* Must start on an odd register - r3/r4 etc. */
@ -183,6 +207,41 @@ ppc_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
greg += 2;
}
}
else if (len == 16 && TYPE_CODE (type) == TYPE_CODE_FLT
&& (gdbarch_long_double_format (current_gdbarch)
== floatformats_ibm_long_double))
{
/* Soft-float IBM long double passed in four consecutive
registers, or on the stack. The registers are not
necessarily odd/even pairs. */
if (greg > 7)
{
greg = 11;
argoffset = align_up (argoffset, 8);
if (write_pass)
write_memory (sp + argoffset, val, len);
argoffset += 16;
}
else
{
if (write_pass)
{
regcache_cooked_write (regcache,
tdep->ppc_gp0_regnum + greg + 0,
val + 0);
regcache_cooked_write (regcache,
tdep->ppc_gp0_regnum + greg + 1,
val + 4);
regcache_cooked_write (regcache,
tdep->ppc_gp0_regnum + greg + 2,
val + 8);
regcache_cooked_write (regcache,
tdep->ppc_gp0_regnum + greg + 3,
val + 12);
}
greg += 4;
}
}
else if (len == 16
&& TYPE_CODE (type) == TYPE_CODE_ARRAY
&& TYPE_VECTOR (type)
@ -376,6 +435,55 @@ do_ppc_sysv_return_value (struct gdbarch *gdbarch, struct type *type,
}
return RETURN_VALUE_REGISTER_CONVENTION;
}
if (TYPE_CODE (type) == TYPE_CODE_FLT
&& TYPE_LENGTH (type) == 16
&& !tdep->soft_float
&& (gdbarch_long_double_format (current_gdbarch)
== floatformats_ibm_long_double))
{
/* IBM long double stored in f1 and f2. */
if (readbuf)
{
regcache_cooked_read (regcache, tdep->ppc_fp0_regnum + 1, readbuf);
regcache_cooked_read (regcache, tdep->ppc_fp0_regnum + 2,
readbuf + 8);
}
if (writebuf)
{
regcache_cooked_write (regcache, tdep->ppc_fp0_regnum + 1, writebuf);
regcache_cooked_write (regcache, tdep->ppc_fp0_regnum + 2,
writebuf + 8);
}
return RETURN_VALUE_REGISTER_CONVENTION;
}
if (TYPE_CODE (type) == TYPE_CODE_FLT
&& TYPE_LENGTH (type) == 16
&& (gdbarch_long_double_format (current_gdbarch)
== floatformats_ibm_long_double))
{
/* Soft-float IBM long double stored in r3, r4, r5, r6. */
if (readbuf)
{
regcache_cooked_read (regcache, tdep->ppc_gp0_regnum + 3, readbuf);
regcache_cooked_read (regcache, tdep->ppc_gp0_regnum + 4,
readbuf + 4);
regcache_cooked_read (regcache, tdep->ppc_gp0_regnum + 5,
readbuf + 8);
regcache_cooked_read (regcache, tdep->ppc_gp0_regnum + 6,
readbuf + 12);
}
if (writebuf)
{
regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + 3, writebuf);
regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + 4,
writebuf + 4);
regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + 5,
writebuf + 8);
regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + 6,
writebuf + 12);
}
return RETURN_VALUE_REGISTER_CONVENTION;
}
if ((TYPE_CODE (type) == TYPE_CODE_INT && TYPE_LENGTH (type) == 8)
|| (TYPE_CODE (type) == TYPE_CODE_FLT && TYPE_LENGTH (type) == 8))
{
@ -768,6 +876,41 @@ ppc64_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
greg++;
gparam = align_up (gparam + TYPE_LENGTH (type), tdep->wordsize);
}
else if (TYPE_CODE (type) == TYPE_CODE_FLT
&& TYPE_LENGTH (type) == 16
&& (gdbarch_long_double_format (current_gdbarch)
== floatformats_ibm_long_double))
{
/* IBM long double stored in two doublewords of the
parameter save area and corresponding registers. */
if (write_pass)
{
if (!tdep->soft_float && freg <= 13)
{
regcache_cooked_write (regcache,
tdep->ppc_fp0_regnum + freg,
val);
if (freg <= 12)
regcache_cooked_write (regcache,
tdep->ppc_fp0_regnum + freg + 1,
val + 8);
}
if (greg <= 10)
{
regcache_cooked_write (regcache,
tdep->ppc_gp0_regnum + greg,
val);
if (greg <= 9)
regcache_cooked_write (regcache,
tdep->ppc_gp0_regnum + greg + 1,
val + 8);
}
write_memory (gparam, val, TYPE_LENGTH (type));
}
freg += 2;
greg += 2;
gparam = align_up (gparam + TYPE_LENGTH (type), tdep->wordsize);
}
else if (TYPE_LENGTH (type) == 16 && TYPE_VECTOR (type)
&& TYPE_CODE (type) == TYPE_CODE_ARRAY
&& tdep->ppc_vr0_regnum >= 0)

View File

@ -1,3 +1,9 @@
2007-11-07 Joseph Myers <joseph@codesourcery.com>
Daniel Jacobowitz <dan@codesourcery.com>
* floatformat.h (struct floatformat): Add split_half field.
(floatformat_ibm_long_double): New.
2007-11-05 Danny Smith <dannysmith@users.sourceforge.net>
* coff/pe.h (COFF_ENCODE_ALIGNMENT) Define.

View File

@ -85,6 +85,13 @@ struct floatformat
/* Validator method. */
int (*is_valid) (const struct floatformat *fmt, const void *from);
/* Is the format actually the sum of two smaller floating point
formats (IBM long double, as described in
gcc/config/rs6000/darwin-ldouble-format)? If so, this is the
smaller format in question, and the fields sign_start through
intbit describe the first half. If not, this is NULL. */
const struct floatformat *split_half;
};
/* floatformats for IEEE single and double, big and little endian. */
@ -118,6 +125,8 @@ extern const struct floatformat floatformat_ia64_spill_big;
extern const struct floatformat floatformat_ia64_spill_little;
extern const struct floatformat floatformat_ia64_quad_big;
extern const struct floatformat floatformat_ia64_quad_little;
/* IBM long double (double+double). */
extern const struct floatformat floatformat_ibm_long_double;
/* Convert from FMT to a double.
FROM is the address of the extended float.

View File

@ -1,3 +1,24 @@
2007-11-07 Joseph Myers <joseph@codesourcery.com>
Daniel Jacobowitz <dan@codesourcery.com>
* floatformat.c (mant_bits_set): New.
(floatformat_to_double): Use it. Note no special handling of
split formats.
(floatformat_from_double): Note no special handing of split
formats.
(floatformat_ibm_long_double_is_valid,
floatformat_ibm_long_double): New.
(floatformat_ieee_single_big, floatformat_ieee_single_little,
floatformat_ieee_double_big, floatformat_ieee_double_little,
floatformat_ieee_double_littlebyte_bigword, floatformat_vax_f,
floatformat_vax_d, floatformat_vax_g, floatformat_i387_ext,
floatformat_m68881_ext, floatformat_i960_ext,
floatformat_m88110_ext, floatformat_m88110_harris_ext,
floatformat_arm_ext_big, floatformat_arm_ext_littlebyte_bigword,
floatformat_ia64_spill_big, floatformat_ia64_spill_little,
floatformat_ia64_quad_big, floatformat_ia64_quad_little): Update
for addition of split_half field.
2007-09-06 Tom Tromey <tromey@redhat.com>
* pexecute.txh (pex_free): Document process killing.

View File

@ -56,6 +56,7 @@ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
#endif
#endif
static int mant_bits_set (const struct floatformat *, const unsigned char *);
static unsigned long get_field (const unsigned char *,
enum floatformat_byteorders,
unsigned int,
@ -82,28 +83,32 @@ const struct floatformat floatformat_ieee_single_big =
floatformat_big, 32, 0, 1, 8, 127, 255, 9, 23,
floatformat_intbit_no,
"floatformat_ieee_single_big",
floatformat_always_valid
floatformat_always_valid,
NULL
};
const struct floatformat floatformat_ieee_single_little =
{
floatformat_little, 32, 0, 1, 8, 127, 255, 9, 23,
floatformat_intbit_no,
"floatformat_ieee_single_little",
floatformat_always_valid
floatformat_always_valid,
NULL
};
const struct floatformat floatformat_ieee_double_big =
{
floatformat_big, 64, 0, 1, 11, 1023, 2047, 12, 52,
floatformat_intbit_no,
"floatformat_ieee_double_big",
floatformat_always_valid
floatformat_always_valid,
NULL
};
const struct floatformat floatformat_ieee_double_little =
{
floatformat_little, 64, 0, 1, 11, 1023, 2047, 12, 52,
floatformat_intbit_no,
"floatformat_ieee_double_little",
floatformat_always_valid
floatformat_always_valid,
NULL
};
/* floatformat for IEEE double, little endian byte order, with big endian word
@ -114,7 +119,8 @@ const struct floatformat floatformat_ieee_double_littlebyte_bigword =
floatformat_littlebyte_bigword, 64, 0, 1, 11, 1023, 2047, 12, 52,
floatformat_intbit_no,
"floatformat_ieee_double_littlebyte_bigword",
floatformat_always_valid
floatformat_always_valid,
NULL
};
/* floatformat for VAX. Not quite IEEE, but close enough. */
@ -124,21 +130,24 @@ const struct floatformat floatformat_vax_f =
floatformat_vax, 32, 0, 1, 8, 129, 0, 9, 23,
floatformat_intbit_no,
"floatformat_vax_f",
floatformat_always_valid
floatformat_always_valid,
NULL
};
const struct floatformat floatformat_vax_d =
{
floatformat_vax, 64, 0, 1, 8, 129, 0, 9, 55,
floatformat_intbit_no,
"floatformat_vax_d",
floatformat_always_valid
floatformat_always_valid,
NULL
};
const struct floatformat floatformat_vax_g =
{
floatformat_vax, 64, 0, 1, 11, 1025, 0, 12, 52,
floatformat_intbit_no,
"floatformat_vax_g",
floatformat_always_valid
floatformat_always_valid,
NULL
};
static int floatformat_i387_ext_is_valid (const struct floatformat *fmt,
@ -170,7 +179,8 @@ const struct floatformat floatformat_i387_ext =
floatformat_little, 80, 0, 1, 15, 0x3fff, 0x7fff, 16, 64,
floatformat_intbit_yes,
"floatformat_i387_ext",
floatformat_i387_ext_is_valid
floatformat_i387_ext_is_valid,
NULL
};
const struct floatformat floatformat_m68881_ext =
{
@ -178,7 +188,8 @@ const struct floatformat floatformat_m68881_ext =
floatformat_big, 96, 0, 1, 15, 0x3fff, 0x7fff, 32, 64,
floatformat_intbit_yes,
"floatformat_m68881_ext",
floatformat_always_valid
floatformat_always_valid,
NULL
};
const struct floatformat floatformat_i960_ext =
{
@ -186,14 +197,16 @@ const struct floatformat floatformat_i960_ext =
floatformat_little, 96, 16, 17, 15, 0x3fff, 0x7fff, 32, 64,
floatformat_intbit_yes,
"floatformat_i960_ext",
floatformat_always_valid
floatformat_always_valid,
NULL
};
const struct floatformat floatformat_m88110_ext =
{
floatformat_big, 80, 0, 1, 15, 0x3fff, 0x7fff, 16, 64,
floatformat_intbit_yes,
"floatformat_m88110_ext",
floatformat_always_valid
floatformat_always_valid,
NULL
};
const struct floatformat floatformat_m88110_harris_ext =
{
@ -202,7 +215,8 @@ const struct floatformat floatformat_m88110_harris_ext =
floatformat_big,128, 0, 1, 11, 0x3ff, 0x7ff, 12, 52,
floatformat_intbit_no,
"floatformat_m88110_ext_harris",
floatformat_always_valid
floatformat_always_valid,
NULL
};
const struct floatformat floatformat_arm_ext_big =
{
@ -210,7 +224,8 @@ const struct floatformat floatformat_arm_ext_big =
floatformat_big, 96, 0, 17, 15, 0x3fff, 0x7fff, 32, 64,
floatformat_intbit_yes,
"floatformat_arm_ext_big",
floatformat_always_valid
floatformat_always_valid,
NULL
};
const struct floatformat floatformat_arm_ext_littlebyte_bigword =
{
@ -218,35 +233,138 @@ const struct floatformat floatformat_arm_ext_littlebyte_bigword =
floatformat_littlebyte_bigword, 96, 0, 17, 15, 0x3fff, 0x7fff, 32, 64,
floatformat_intbit_yes,
"floatformat_arm_ext_littlebyte_bigword",
floatformat_always_valid
floatformat_always_valid,
NULL
};
const struct floatformat floatformat_ia64_spill_big =
{
floatformat_big, 128, 0, 1, 17, 65535, 0x1ffff, 18, 64,
floatformat_intbit_yes,
"floatformat_ia64_spill_big",
floatformat_always_valid
floatformat_always_valid,
NULL
};
const struct floatformat floatformat_ia64_spill_little =
{
floatformat_little, 128, 0, 1, 17, 65535, 0x1ffff, 18, 64,
floatformat_intbit_yes,
"floatformat_ia64_spill_little",
floatformat_always_valid
floatformat_always_valid,
NULL
};
const struct floatformat floatformat_ia64_quad_big =
{
floatformat_big, 128, 0, 1, 15, 16383, 0x7fff, 16, 112,
floatformat_intbit_no,
"floatformat_ia64_quad_big",
floatformat_always_valid
floatformat_always_valid,
NULL
};
const struct floatformat floatformat_ia64_quad_little =
{
floatformat_little, 128, 0, 1, 15, 16383, 0x7fff, 16, 112,
floatformat_intbit_no,
"floatformat_ia64_quad_little",
floatformat_always_valid
floatformat_always_valid,
NULL
};
static int
floatformat_ibm_long_double_is_valid (const struct floatformat *fmt,
const void *from)
{
const unsigned char *ufrom = (const unsigned char *) from;
const struct floatformat *hfmt = fmt->split_half;
long top_exp, bot_exp;
int top_nan = 0;
top_exp = get_field (ufrom, hfmt->byteorder, hfmt->totalsize,
hfmt->exp_start, hfmt->exp_len);
bot_exp = get_field (ufrom + 8, hfmt->byteorder, hfmt->totalsize,
hfmt->exp_start, hfmt->exp_len);
if (top_exp == hfmt->exp_nan)
top_nan = mant_bits_set (hfmt, ufrom);
/* A NaN is valid with any low part. */
if (top_nan)
return 1;
/* An infinity, zero or denormal requires low part 0 (positive or
negative). */
if (top_exp == hfmt->exp_nan || top_exp == 0)
{
unsigned int mant_bits, mant_off;
int mant_bits_left;
if (bot_exp != 0)
return 0;
return !mant_bits_set (hfmt, ufrom + 8);
}
/* The top part is now a finite normal value. The long double value
is the sum of the two parts, and the top part must equal the
result of rounding the long double value to nearest double. Thus
the bottom part must be <= 0.5ulp of the top part in absolute
value, and if it is < 0.5ulp then the long double is definitely
valid. */
if (bot_exp < top_exp - 53)
return 1;
if (bot_exp > top_exp - 53 && bot_exp != 0)
return 0;
if (bot_exp == 0)
{
/* The bottom part is 0 or denormal. Determine which, and if
denormal the first two set bits. */
int first_bit = -1, second_bit = -1, cur_bit;
for (cur_bit = 0; cur_bit < hfmt->man_len; cur_bit++)
if (get_field (ufrom + 8, hfmt->byteorder, hfmt->totalsize,
hfmt->man_start + cur_bit, 1))
{
if (first_bit == -1)
first_bit = cur_bit;
else
{
second_bit = cur_bit;
break;
}
}
/* Bottom part 0 is OK. */
if (first_bit == -1)
return 1;
/* The real exponent of the bottom part is -first_bit. */
if (-first_bit < top_exp - 53)
return 1;
if (-first_bit > top_exp - 53)
return 0;
/* The bottom part is at least 0.5ulp of the top part. For this
to be OK, the bottom part must be exactly 0.5ulp (i.e. no
more bits set) and the top part must have last bit 0. */
if (second_bit != -1)
return 0;
return !get_field (ufrom, hfmt->byteorder, hfmt->totalsize,
hfmt->man_start + hfmt->man_len - 1, 1);
}
else
{
/* The bottom part is at least 0.5ulp of the top part. For this
to be OK, it must be exactly 0.5ulp (i.e. no explicit bits
set) and the top part must have last bit 0. */
if (get_field (ufrom, hfmt->byteorder, hfmt->totalsize,
hfmt->man_start + hfmt->man_len - 1, 1))
return 0;
return !mant_bits_set (hfmt, ufrom + 8);
}
}
const struct floatformat floatformat_ibm_long_double =
{
floatformat_big, 128, 0, 1, 11, 1023, 2047, 12, 52,
floatformat_intbit_no,
"floatformat_ibm_long_double",
floatformat_always_valid,
&floatformat_ieee_double_big
};
@ -254,6 +372,30 @@ const struct floatformat floatformat_ia64_quad_little =
#define min(a, b) ((a) < (b) ? (a) : (b))
#endif
/* Return 1 if any bits are explicitly set in the mantissa of UFROM,
format FMT, 0 otherwise. */
static int
mant_bits_set (const struct floatformat *fmt, const unsigned char *ufrom)
{
unsigned int mant_bits, mant_off;
int mant_bits_left;
mant_off = fmt->man_start;
mant_bits_left = fmt->man_len;
while (mant_bits_left > 0)
{
mant_bits = min (mant_bits_left, 32);
if (get_field (ufrom, fmt->byteorder, fmt->totalsize,
mant_off, mant_bits) != 0)
return 1;
mant_off += mant_bits;
mant_bits_left -= mant_bits;
}
return 0;
}
/* Extract a field which starts at START and is LEN bits long. DATA and
TOTAL_LEN are the thing we are extracting it from, in byteorder ORDER. */
static unsigned long
@ -310,6 +452,10 @@ floatformat_to_double (const struct floatformat *fmt,
int mant_bits_left;
int special_exponent; /* It's a NaN, denorm or zero */
/* Split values are not handled specially, since the top half has
the correctly rounded double value (in the only supported case of
split values). */
exponent = get_field (ufrom, fmt->byteorder, fmt->totalsize,
fmt->exp_start, fmt->exp_len);
@ -318,26 +464,7 @@ floatformat_to_double (const struct floatformat *fmt,
don't try to preserve the type of NaN. FIXME. */
if ((unsigned long) exponent == fmt->exp_nan)
{
int nan;
mant_off = fmt->man_start;
mant_bits_left = fmt->man_len;
nan = 0;
while (mant_bits_left > 0)
{
mant_bits = min (mant_bits_left, 32);
if (get_field (ufrom, fmt->byteorder, fmt->totalsize,
mant_off, mant_bits) != 0)
{
/* This is a NaN. */
nan = 1;
break;
}
mant_off += mant_bits;
mant_bits_left -= mant_bits;
}
int nan = mant_bits_set (fmt, ufrom);
/* On certain systems (such as GNU/Linux), the use of the
INFINITY macro below may generate a warning that can not be
@ -474,6 +601,10 @@ floatformat_from_double (const struct floatformat *fmt,
dfrom = *from;
memset (uto, 0, fmt->totalsize / FLOATFORMAT_CHAR_BIT);
/* Split values are not handled specially, since a bottom half of
zero is correct for any value representable as double (in the
only supported case of split values). */
/* If negative, set the sign bit. */
if (dfrom < 0)
{