This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Fix encoding of IEEE extended real on big-endian ia64 (PR 14610)
- From: Zack Weinberg <zack at codesourcery dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Tue, 15 Jun 2004 11:01:34 -0700
- Subject: Fix encoding of IEEE extended real on big-endian ia64 (PR 14610)
This is my candidate patch for the problem I described last night with
the encoding of IEEE extended values. I believe the problem is only
visible on ia64-hpux, being the only current target that wants Intel
format extended numbers but in big-endian order. The Makefile.in
change is an unrelated bug I found while testing (it's extremely
irritating when you make a change to ia64-modes.def that only affects
insn-modes.c but genattrtab gets run again anyway... where are those
faster-genattrtab patches someone was claiming to have?)
Testing is stalled due to unrelated problems - on ia64, ICE in
expmed.c during stage 2; on x86_64, all execute tests time out due to
an apparent bug in expect. (Does anyone else have this problem/know a
solution?)
Thanks to all who gave advice on proper formatting of these values.
zw
Bug 14610
* Makefile.in (min-insn-modes.o): Correct dependencies.
* real.c (encode_ieee_extended, decode_ieee_extended): Always
produce/consume 12-byte little-endian Intel format.
(encode_ieee_extended_128, decode_ieee_extended_128): Delete.
(encode_ieee_extended_motorola, decode_ieee_extended_motorola)
(encode_ieee_extended_intel_96, decode_ieee_extended_intel_96)
(encode_ieee_extended_intel_128, decode_ieee_extended_intel_128):
New functions which convert between 12-byte little-endian Intel
format and the desired format.
(ieee_extended_motorola_format, ieee_extended_intel_96_round_53_format)
(ieee_extended_intel_96_format, ieee_extended_intel_128_format):
Update.
testsuite:
* gcc.dg/ia64-float80-1.c, gcc.dg/ia64-float80-2.c: New testcases.
===================================================================
Index: Makefile.in
--- Makefile.in 14 Jun 2004 14:17:45 -0000 1.1298
+++ Makefile.in 15 Jun 2004 05:06:54 -0000
@@ -2561,7 +2561,7 @@ $(BUILD_PREFIX_1)ggc-none.o: ggc-none.c
sed -e 's/config[.]h/bconfig.h/' $(srcdir)/ggc-none.c > $(BUILD_PREFIX)ggc-none.c
$(CC_FOR_BUILD) -c $(BUILD_CFLAGS) $(BUILD_CPPFLAGS) $(INCLUDES) $(BUILD_PREFIX)ggc-none.c $(OUTPUT_OPTION)
-min-insn-modes.o: insn-modes.c $(BCONFIG_H) $(SYSTEM_H) $(MACHMODE_H)
+min-insn-modes.o: min-insn-modes.c $(BCONFIG_H) $(SYSTEM_H) $(MACHMODE_H)
$(CC_FOR_BUILD) -c $(BUILD_CFLAGS) $(BUILD_CPPFLAGS) $(INCLUDES) \
min-insn-modes.c $(OUTPUT_OPTION)
===================================================================
Index: real.c
--- real.c 14 Jun 2004 21:07:07 -0000 1.144
+++ real.c 15 Jun 2004 05:06:54 -0000
@@ -2912,20 +2912,14 @@ const struct real_format mips_double_for
};
-/* IEEE extended double precision format. This comes in three
- flavors: Intel's as a 12 byte image, Intel's as a 16 byte image,
- and Motorola's. */
-
-static void encode_ieee_extended (const struct real_format *fmt,
- long *, const REAL_VALUE_TYPE *);
-static void decode_ieee_extended (const struct real_format *,
- REAL_VALUE_TYPE *, const long *);
-
-static void encode_ieee_extended_128 (const struct real_format *fmt,
- long *, const REAL_VALUE_TYPE *);
-static void decode_ieee_extended_128 (const struct real_format *,
- REAL_VALUE_TYPE *, const long *);
-
+/* IEEE extended real format. This comes in three flavors: Intel's as
+ a 12 byte image, Intel's as a 16 byte image, and Motorola's. Intel
+ 12- and 16-byte images may be big- or little endian; Motorola's is
+ always big endian. */
+
+/* Helper subroutine which converts from the internal format to the
+ 12-byte little-endian Intel format. Functions below adjust this
+ for the other possible formats. */
static void
encode_ieee_extended (const struct real_format *fmt, long *buf,
const REAL_VALUE_TYPE *r)
@@ -3033,20 +3027,65 @@ encode_ieee_extended (const struct real_
abort ();
}
+ buf[0] = sig_lo, buf[1] = sig_hi, buf[2] = image_hi;
+}
+
+/* Convert from the internal format to the 12-byte Motorola format
+ for an IEEE extended real. */
+static void
+encode_ieee_extended_motorola (const struct real_format *fmt, long *buf,
+ const REAL_VALUE_TYPE *r)
+{
+ long intermed[3];
+ encode_ieee_extended (fmt, intermed, r);
+
+ /* Motorola chips are assumed always to be big-endian. Also, the
+ padding in a Motorola extended real goes between the exponent and
+ the mantissa. At this point the mantissa is entirely within
+ elements 0 and 1 of intermed, and the exponent entirely within
+ element 2, so all we have to do is swap the order around, and
+ shift element 2 left 16 bits. */
+ buf[0] = intermed[2] << 16;
+ buf[1] = intermed[1];
+ buf[2] = intermed[0];
+}
+
+/* Convert from the internal format to the 12-byte Intel format for
+ an IEEE extended real. */
+static void
+encode_ieee_extended_intel_96 (const struct real_format *fmt, long *buf,
+ const REAL_VALUE_TYPE *r)
+{
if (FLOAT_WORDS_BIG_ENDIAN)
- buf[0] = image_hi << 16, buf[1] = sig_hi, buf[2] = sig_lo;
+ {
+ /* All the padding in an Intel-format extended real goes at the high
+ end, which in this case is after the mantissa, not the exponent.
+ Therefore we must shift everything down 16 bits. */
+ long intermed[3];
+ encode_ieee_extended (fmt, intermed, r);
+ buf[0] = ((intermed[2] << 16) | ((unsigned long)(intermed[1] & 0xFFFF0000) >> 16));
+ buf[1] = ((intermed[1] << 16) | ((unsigned long)(intermed[0] & 0xFFFF0000) >> 16));
+ buf[2] = (intermed[0] << 16);
+ }
else
- buf[0] = sig_lo, buf[1] = sig_hi, buf[2] = image_hi;
+ /* encode_ieee_extended produces what we want directly. */
+ encode_ieee_extended (fmt, buf, r);
}
+/* Convert from the internal format to the 16-byte Intel format for
+ an IEEE extended real. */
static void
-encode_ieee_extended_128 (const struct real_format *fmt, long *buf,
- const REAL_VALUE_TYPE *r)
+encode_ieee_extended_intel_128 (const struct real_format *fmt, long *buf,
+ const REAL_VALUE_TYPE *r)
{
- buf[3 * !FLOAT_WORDS_BIG_ENDIAN] = 0;
- encode_ieee_extended (fmt, buf+!!FLOAT_WORDS_BIG_ENDIAN, r);
+ /* All the padding in an Intel-format extended real goes at the high end. */
+ encode_ieee_extended_intel_96 (fmt, buf, r);
+ buf[3] = 0;
}
+/* As above, we have a helper function which converts from 12-byte
+ little-endian Intel format to internal format. Functions below
+ adjust for the other possible formats. */
static void
decode_ieee_extended (const struct real_format *fmt, REAL_VALUE_TYPE *r,
const long *buf)
@@ -3055,10 +3094,7 @@ decode_ieee_extended (const struct real_
bool sign;
int exp;
- if (FLOAT_WORDS_BIG_ENDIAN)
- image_hi = buf[0] >> 16, sig_hi = buf[1], sig_lo = buf[2];
- else
- sig_lo = buf[0], sig_hi = buf[1], image_hi = buf[2];
+ sig_lo = buf[0], sig_hi = buf[1], image_hi = buf[2];
sig_lo &= 0xffffffff;
sig_hi &= 0xffffffff;
image_hi &= 0xffffffff;
@@ -3135,17 +3171,62 @@ decode_ieee_extended (const struct real_
}
}
+/* Convert from the internal format to the 12-byte Motorola format
+ for an IEEE extended real. */
+static void
+decode_ieee_extended_motorola (const struct real_format *fmt, REAL_VALUE_TYPE *r,
+ const long *buf)
+{
+ long intermed[3];
+
+ /* Motorola chips are assumed always to be big-endian. Also, the
+ padding in a Motorola extended real goes between the exponent and
+ the mantissa; remove it. */
+ intermed[0] = buf[2];
+ intermed[1] = buf[1];
+ intermed[2] = (unsigned long)buf[0] >> 16;
+
+ decode_ieee_extended (fmt, r, intermed);
+}
+
+/* Convert from the internal format to the 12-byte Intel format for
+ an IEEE extended real. */
+static void
+decode_ieee_extended_intel_96 (const struct real_format *fmt, REAL_VALUE_TYPE *r,
+ const long *buf)
+{
+ if (FLOAT_WORDS_BIG_ENDIAN)
+ {
+ /* All the padding in an Intel-format extended real goes at the high
+ end, which in this case is after the mantissa, not the exponent.
+ Therefore we must shift everything up 16 bits. */
+ long intermed[3];
+
+ intermed[0] = (((unsigned long)buf[2] >> 16) | (buf[1] << 16));
+ intermed[1] = (((unsigned long)buf[1] >> 16) | (buf[0] << 16));
+ intermed[2] = ((unsigned long)buf[0] >> 16);
+
+ decode_ieee_extended (fmt, r, intermed);
+ }
+ else
+ /* decode_ieee_extended produces what we want directly. */
+ decode_ieee_extended (fmt, r, buf);
+}
+
+/* Convert from the internal format to the 16-byte Intel format for
+ an IEEE extended real. */
static void
-decode_ieee_extended_128 (const struct real_format *fmt, REAL_VALUE_TYPE *r,
- const long *buf)
+decode_ieee_extended_intel_128 (const struct real_format *fmt, REAL_VALUE_TYPE *r,
+ const long *buf)
{
- decode_ieee_extended (fmt, r, buf+!!FLOAT_WORDS_BIG_ENDIAN);
+ /* All the padding in an Intel-format extended real goes at the high end. */
+ decode_ieee_extended_intel_96 (fmt, r, buf);
}
const struct real_format ieee_extended_motorola_format =
{
- encode_ieee_extended,
- decode_ieee_extended,
+ encode_ieee_extended_motorola,
+ decode_ieee_extended_motorola,
2,
1,
64,
@@ -3162,8 +3243,8 @@ const struct real_format ieee_extended_m
const struct real_format ieee_extended_intel_96_format =
{
- encode_ieee_extended,
- decode_ieee_extended,
+ encode_ieee_extended_intel_96,
+ decode_ieee_extended_intel_96,
2,
1,
64,
@@ -3180,8 +3261,8 @@ const struct real_format ieee_extended_i
const struct real_format ieee_extended_intel_128_format =
{
- encode_ieee_extended_128,
- decode_ieee_extended_128,
+ encode_ieee_extended_intel_128,
+ decode_ieee_extended_intel_128,
2,
1,
64,
@@ -3200,8 +3281,8 @@ const struct real_format ieee_extended_i
to 53 bits instead of 64, e.g. FreeBSD. */
const struct real_format ieee_extended_intel_96_round_53_format =
{
- encode_ieee_extended,
- decode_ieee_extended,
+ encode_ieee_extended_intel_96,
+ decode_ieee_extended_intel_96,
2,
1,
53,
===================================================================
Index: testsuite/gcc.dg/ia64-float80-1.c
--- testsuite/gcc.dg/ia64-float80-1.c 1 Jan 1970 00:00:00 -0000
+++ testsuite/gcc.dg/ia64-float80-1.c 15 Jun 2004 05:06:56 -0000
@@ -0,0 +1,12 @@
+/* Bug 14610 */
+/* { dg-do run { target ia64-*-* } } */
+
+extern void abort(void);
+volatile __float80 x = 30.0;
+
+int main(void)
+{
+ double d = x;
+ if (d != 30.0) abort ();
+ return 0;
+}
===================================================================
Index: testsuite/gcc.dg/ia64-float80-2.c
--- testsuite/gcc.dg/ia64-float80-2.c 1 Jan 1970 00:00:00 -0000
+++ testsuite/gcc.dg/ia64-float80-2.c 15 Jun 2004 05:06:56 -0000
@@ -0,0 +1,13 @@
+/* Bug 14610 */
+/* { dg-do run { target ia64-*-* } } */
+/* { dg-options "-minline-int-divide-max-throughput" } */
+
+extern void abort(void);
+volatile int j = 30;
+
+int main(void)
+{
+ if (29 % j != 29) abort();
+ if (30 % j != 0) abort();
+ return 0;
+}