This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: mips SNaN/QNaN is swapped
On Tue, Mar 25, 2003 at 06:46:27AM -0300, Alexandre Oliva wrote:
> It fixes the very bug I mentioned in my earlier posts.
Not quite. It moves the bug around.
I think the cleanest way to correct this is to fix the representation.
I've briefly tested the following by eye on both x86 and mips.
r~
Index: real.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/real.c,v
retrieving revision 1.111
diff -c -p -d -u -r1.111 real.c
--- real.c 26 Feb 2003 21:07:40 -0000 1.111
+++ real.c 27 Mar 2003 01:23:42 -0000
@@ -158,7 +158,6 @@ get_canonical_qnan (r, sign)
memset (r, 0, sizeof (*r));
r->class = rvc_nan;
r->sign = sign;
- r->sig[SIGSZ-1] = SIG_MSB >> 1;
}
static inline void
@@ -169,7 +168,7 @@ get_canonical_snan (r, sign)
memset (r, 0, sizeof (*r));
r->class = rvc_nan;
r->sign = sign;
- r->sig[SIGSZ-1] = SIG_MSB >> 2;
+ r->signalling = 1;
}
static inline void
@@ -1235,6 +1234,8 @@ real_identical (a, b)
return false;
/* FALLTHRU */
case rvc_nan:
+ if (a->signalling != b->signalling)
+ return false;
for (i = 0; i < SIGSZ; ++i)
if (a->sig[i] != b->sig[i])
return false;
@@ -2249,23 +2250,7 @@ real_nan (r, str, quiet, mode)
r->sig[SIGSZ-1] &= ~SIG_MSB;
/* Force quiet or signalling NaN. */
- if (quiet)
- r->sig[SIGSZ-1] |= SIG_MSB >> 1;
- else
- r->sig[SIGSZ-1] &= ~(SIG_MSB >> 1);
-
- /* Force at least one bit of the significand set. */
- for (d = 0; d < SIGSZ; ++d)
- if (r->sig[d])
- break;
- if (d == SIGSZ)
- r->sig[SIGSZ-1] |= SIG_MSB >> 2;
-
- /* Our intermediate format forces QNaNs to have MSB-1 set.
- If the target format has QNaNs with the top bit unset,
- mirror the output routines and invert the top two bits. */
- if (!fmt->qnan_msb_set)
- r->sig[SIGSZ-1] ^= (SIG_MSB >> 1) | (SIG_MSB >> 2);
+ r->signalling = !quiet;
}
return true;
@@ -2325,14 +2310,6 @@ round_for_format (fmt, r)
case rvc_nan:
clear_significand_below (r, np2);
-
- /* If we've cleared the entire significand, we need one bit
- set for this to continue to be a NaN. */
- for (i = 0; i < SIGSZ; ++i)
- if (r->sig[i])
- break;
- if (i == SIGSZ)
- r->sig[SIGSZ-1] = SIG_MSB >> 2;
return;
case rvc_normal:
@@ -2642,10 +2619,15 @@ encode_ieee_single (fmt, buf, r)
case rvc_nan:
if (fmt->has_nans)
{
+ if (r->signalling == fmt->qnan_msb_set)
+ sig &= ~(1 << 22);
+ else
+ sig |= 1 << 22;
+ if (sig == 0)
+ sig = 1 << 21;
+
image |= 255 << 23;
image |= sig;
- if (!fmt->qnan_msb_set)
- image ^= 1 << 23 | 1 << 22;
}
else
image |= 0x7fffffff;
@@ -2703,8 +2685,7 @@ decode_ieee_single (fmt, r, buf)
{
r->class = rvc_nan;
r->sign = sign;
- if (!fmt->qnan_msb_set)
- image ^= (SIG_MSB >> 1 | SIG_MSB >> 2);
+ r->signalling = ((image >> 22) & 1) ^ fmt->qnan_msb_set;
r->sig[SIGSZ-1] = image;
}
else
@@ -2739,6 +2720,23 @@ const struct real_format ieee_single_for
true
};
+const struct real_format mips_single_format =
+ {
+ encode_ieee_single,
+ decode_ieee_single,
+ 2,
+ 1,
+ 24,
+ -125,
+ 128,
+ 31,
+ true,
+ true,
+ true,
+ true,
+ false
+ };
+
/* IEEE double-precision format. */
@@ -2791,10 +2789,15 @@ encode_ieee_double (fmt, buf, r)
case rvc_nan:
if (fmt->has_nans)
{
+ if (r->signalling == fmt->qnan_msb_set)
+ sig_hi &= ~(1 << 19);
+ else
+ sig_hi |= 1 << 19;
+ if (sig_hi == 0 && sig_lo == 0)
+ sig_hi = 1 << 18;
+
image_hi |= 2047 << 20;
image_hi |= sig_hi;
- if (!fmt->qnan_msb_set)
- image_hi ^= 1 << 19 | 1 << 18;
image_lo = sig_lo;
}
else
@@ -2884,6 +2887,7 @@ decode_ieee_double (fmt, r, buf)
{
r->class = rvc_nan;
r->sign = sign;
+ r->signalling = ((image_hi >> 30) & 1) ^ fmt->qnan_msb_set;
if (HOST_BITS_PER_LONG == 32)
{
r->sig[SIGSZ-1] = image_hi;
@@ -2891,9 +2895,6 @@ decode_ieee_double (fmt, r, buf)
}
else
r->sig[SIGSZ-1] = (image_hi << 31 << 1) | image_lo;
-
- if (!fmt->qnan_msb_set)
- r->sig[SIGSZ-1] ^= (SIG_MSB >> 1 | SIG_MSB >> 2);
}
else
{
@@ -2933,6 +2934,23 @@ const struct real_format ieee_double_for
true
};
+const struct real_format mips_double_format =
+ {
+ encode_ieee_double,
+ decode_ieee_double,
+ 2,
+ 1,
+ 53,
+ -1021,
+ 1024,
+ 63,
+ true,
+ true,
+ true,
+ true,
+ false
+ };
+
/* IEEE extended double precision format. This comes in three
flavours: Intel's as a 12 byte image, Intel's as a 16 byte image,
@@ -2999,8 +3017,12 @@ encode_ieee_extended (fmt, buf, r)
sig_hi = sig_lo >> 31 >> 1;
sig_lo &= 0xffffffff;
}
- if (!fmt->qnan_msb_set)
- sig_hi ^= 1 << 30 | 1 << 29;
+ if (r->signalling == fmt->qnan_msb_set)
+ sig_hi &= ~(1 << 30);
+ else
+ sig_hi |= 1 << 30;
+ if ((sig_hi & 0x7fffffff) == 0 && sig_lo == 0)
+ sig_hi = 1 << 29;
/* Intel requires the explicit integer bit to be set, otherwise
it considers the value a "pseudo-nan". Motorola docs say it
@@ -3131,6 +3153,7 @@ decode_ieee_extended (fmt, r, buf)
{
r->class = rvc_nan;
r->sign = sign;
+ r->signalling = ((sig_hi >> 30) & 1) ^ fmt->qnan_msb_set;
if (HOST_BITS_PER_LONG == 32)
{
r->sig[SIGSZ-1] = sig_hi;
@@ -3138,9 +3161,6 @@ decode_ieee_extended (fmt, r, buf)
}
else
r->sig[SIGSZ-1] = (sig_hi << 31 << 1) | sig_lo;
-
- if (!fmt->qnan_msb_set)
- r->sig[SIGSZ-1] ^= (SIG_MSB >> 1 | SIG_MSB >> 2);
}
else
{
@@ -3332,6 +3352,23 @@ const struct real_format ibm_extended_fo
true
};
+const struct real_format mips_extended_format =
+ {
+ encode_ibm_extended,
+ decode_ibm_extended,
+ 2,
+ 1,
+ 53 + 53,
+ -1021 + 53,
+ 1024,
+ -1,
+ true,
+ true,
+ true,
+ true,
+ false
+ };
+
/* IEEE quad precision format. */
@@ -3395,9 +3432,12 @@ encode_ieee_quad (fmt, buf, r)
image0 &= 0xffffffff;
image2 &= 0xffffffff;
}
-
- if (!fmt->qnan_msb_set)
- image3 ^= 1 << 15 | 1 << 14;
+ if (r->signalling == fmt->qnan_msb_set)
+ image3 &= ~0x8000;
+ else
+ image3 |= 0x8000;
+ if (((image3 & 0xffff) | image2 | image1 | image0) == 0)
+ image3 |= 0x4000;
}
else
{
@@ -3522,6 +3562,7 @@ decode_ieee_quad (fmt, r, buf)
{
r->class = rvc_nan;
r->sign = sign;
+ r->signalling = ((image3 >> 15) & 1) ^ fmt->qnan_msb_set;
if (HOST_BITS_PER_LONG == 32)
{
@@ -3536,9 +3577,6 @@ decode_ieee_quad (fmt, r, buf)
r->sig[1] = (image3 << 31 << 1) | image2;
}
lshift_significand (r, r, SIGNIFICAND_BITS - 113);
-
- if (!fmt->qnan_msb_set)
- r->sig[SIGSZ-1] ^= (SIG_MSB >> 1 | SIG_MSB >> 2);
}
else
{
@@ -3584,6 +3622,23 @@ const struct real_format ieee_quad_forma
true,
true,
true
+ };
+
+const struct real_format mips_quad_format =
+ {
+ encode_ieee_quad,
+ decode_ieee_quad,
+ 2,
+ 1,
+ 113,
+ -16381,
+ 16384,
+ 127,
+ true,
+ true,
+ true,
+ true,
+ false
};
/* Descriptions of VAX floating point formats can be found beginning at
Index: real.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/real.h,v
retrieving revision 1.61
diff -c -p -d -u -r1.61 real.h
--- real.h 15 Jan 2003 17:40:26 -0000 1.61
+++ real.h 27 Mar 2003 01:23:42 -0000
@@ -35,7 +35,7 @@ enum real_value_class {
};
#define SIGNIFICAND_BITS (128 + HOST_BITS_PER_LONG)
-#define EXP_BITS (32 - 3)
+#define EXP_BITS (32 - 4)
#define MAX_EXP ((1 << (EXP_BITS - 1)) - 1)
#define SIGSZ (SIGNIFICAND_BITS / HOST_BITS_PER_LONG)
#define SIG_MSB ((unsigned long)1 << (HOST_BITS_PER_LONG - 1))
@@ -44,6 +44,7 @@ struct real_value GTY(())
{
ENUM_BITFIELD (real_value_class) class : 2;
unsigned int sign : 1;
+ unsigned int signalling : 1;
signed int exp : EXP_BITS;
unsigned long sig[SIGSZ];
};
@@ -221,12 +222,16 @@ extern unsigned int real_hash PARAMS ((c
/* Target formats defined in real.c. */
extern const struct real_format ieee_single_format;
+extern const struct real_format mips_single_format;
extern const struct real_format ieee_double_format;
+extern const struct real_format mips_double_format;
extern const struct real_format ieee_extended_motorola_format;
extern const struct real_format ieee_extended_intel_96_format;
extern const struct real_format ieee_extended_intel_128_format;
extern const struct real_format ibm_extended_format;
+extern const struct real_format mips_extended_format;
extern const struct real_format ieee_quad_format;
+extern const struct real_format mips_quad_format;
extern const struct real_format vax_f_format;
extern const struct real_format vax_d_format;
extern const struct real_format vax_g_format;