As noted in the comment below, IBM long double is really an array of
two doubles. In little-endian mode this means the words of each
double should be reversed in write_real_cst, but the large magnitude
double remains the first element of the array.
This patch specially treats IBM long double so that mangling for
template literal args of a given long double value is the same for
both little and big endian. Bootstrapped etc. powerpc64-linux.
This is of course an ABI change for any existing little-endian users
of IBM long double literals in templates. On powerpc, I think we can
safely say there are no such users. However it does look like MIPS
also uses a variant of IBM long double, and I'm less certain there.
* mangle.c (write_real_cst): Specially treat IBM long double.
Index: gcc/cp/mangle.c
===================================================================
--- gcc/cp/mangle.c (revision 199975)
+++ gcc/cp/mangle.c (working copy)
@@ -1591,28 +1591,35 @@ write_real_cst (const tree value)
{
if (abi_version_at_least (2))
{
+ const struct real_format *fmt;
long target_real[4]; /* largest supported float */
char buffer[9]; /* eight hex digits in a 32-bit number */
- int i, limit, dir;
+ int i, limit, dir, twid;
tree type = TREE_TYPE (value);
int words = GET_MODE_BITSIZE (TYPE_MODE (type)) / 32;
- real_to_target (target_real, &TREE_REAL_CST (value),
- TYPE_MODE (type));
+ fmt = REAL_MODE_FORMAT (TYPE_MODE (type));
+ real_to_target_fmt (target_real, &TREE_REAL_CST (value), fmt);
/* The value in target_real is in the target word order,
so we must write it out backward if that happens to be
little-endian. write_number cannot be used, it will
produce uppercase. */
if (FLOAT_WORDS_BIG_ENDIAN)
- i = 0, limit = words, dir = 1;
+ i = 0, limit = words, dir = 1, twid = 0;
+ else if (fmt->pnan < fmt->p)
+ /* This is an IBM extended double format made up of two IEEE
+ doubles. When little-endian, the doubles are in
+ little-endian word order, but the array order stays the
+ same. */
+ i = 0, limit = words, dir = 1, twid = 1;
else
- i = words - 1, limit = -1, dir = -1;
+ i = words - 1, limit = -1, dir = -1, twid = 0;
for (; i != limit; i += dir)
{
- sprintf (buffer, "%08lx", (unsigned long) target_real[i]);
+ sprintf (buffer, "%08lx", (unsigned long) target_real[i ^ twid]);
write_chars (buffer, 8);
}
}
--
Alan Modra
Australia Development Lab, IBM