This is the mail archive of the newlib@sourceware.org mailing list for the newlib project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] MIPS: NaN encoding fixes and IEEE 754-2008 updates


Hi,

 As many of you have been aware it has been a long practice for software
using IEEE 754 floating-point arithmetic run on MIPS processors to use an
encoding of Not-a-Number (NaN) data different to one used by software run
on other processors.  And as of IEEE 754-2008 revision this encoding does
not follow one recommended in the standard, as specified in section 6.2.1,
where it is stated that quiet NaNs should have the first bit (d1) of their
significand set to 1 while signalling NaNs should have that bit set to 0,
but MIPS software interprets the two bits in the opposite manner.

 A recent MIPS Architecture revision[1][2] provides for processors that 
support the IEEE 754-2008 preferred NaN encoding format.  As the two 
formats (further referred to as "legacy NaN" and "2008 NaN") are 
incompatible to each other, tools have been updated to provide support for 
the two formats to help people avoid using incompatible binary modules.  
In particular GCC versions that produce the 2008 NaN encoding predefine 
the `__mips_nan2008' macro that can be used to select code to compile at 
the preprocessor level.

 This change corrects inconsistencies for the MIPS target in NaN encodings 
between endiannesses and makes sure the correct encodings are used both in 
the legacy-NaN and the 2008-NaN mode.

 This code unconditionally expects floating-point types having the 
significand field width of 24, 53, 64 and 113 bits to be present.  
Additionally the 64-bit format expects the leading significand bit to be 
explicitly encoded as in Intel x86/x87 FPUs.  Having no better choice I 
have implemented the handling of these extra data types as they might be 
reasonably implemented by MIPS hardware.  Ideally this code should be 
audited and dead pieces disabled for targets that do not use them.

 Furthermore some macros are present that encode constants comprising 
whole or parts of NaN data of different widths.  They use different 
encodings and data formats between endiannesses, apparently implying the 
Intel x86/x87 format for the little endianness and Motorola M68k format 
for the big endianness.  Neither fully applies for MIPS targets, so I have 
added separate definitions for the values that make sense and are actually 
referred to from code elsewhere.  Any future references to the currently 
unused macros defined for non-MIPS targets to support a long double data 
type will cause a build failure on MIPS, which is exactly what we want.

 For nan and nanf I decided to switch to __builtin_nan and __builtin_nanf 
respectively as the implementation where available -- which is always true 
for GCC versions that support the 2008-NaN encoding on the MIPS target.  
These built-ins guarantee the correct NaN encoding for all platforms and 
compilation options and are already used elsewhere in Newlib (which is 
where I copied the preprocessor condition from).

 For MIPS, additionally, in many cases they produce slightly better or at 
worst identical code; unfortunately in some other ones GCC misses the 
opportunity to inline the value loaded -- it looks to me like with these 
built-ins the compiler always insists to put the value loaded in memory.  
I don't think this should stop us from using them regardless though, the 
maintainability gain is too high compared to the memory loss, which is on 
the order of 4 to 8 bytes.

 FWIW I have regression-tested the change with the mips-sde-elf target, 
although I can't say this provides much value as the newlib test suite 
doesn't seem to cover much of IEEE arithmetic.  However this change has 
been used for ~1yr with the Mentor CodeBench toolchain with no problems 
spotted.

 Please apply.

2013-03-19  Maciej W. Rozycki  <macro@codesourcery.com>

	newlib/
	* libc/stdlib/gd_qnan.h (f_QNAN, d_QNAN0, d_QNAN1): Add MIPS
	versions.
	(ld_QNAN0, ld_QNAN1, ld_QNAN2, ld_QNAN3): Don't define for MIPS.
	(ldus_QNAN0, ldus_QNAN1, ldus_QNAN2, ldus_QNAN3, ldus_QNAN4):
	Likewise.
	* libc/stdlib/ldtoa.c (nan113, nan64, nan53, nan24): Add MIPS
	versions.
	(enan): Handle legacy MIPS payloads.
	* libm/common/s_nan.c (nan): Use __builtin_nan if supported by
	the compiler.
	* libm/common/sf_nan.c (nanf): Likewise.

  Maciej

 References:

[1] "MIPS Architecture For Programmers, Volume I-A: Introduction to the 
     MIPS32 Architecture", MIPS Technologies, Inc., Document Number: 
     MD00082, Revision 5.03, Sept. 9, 2013, Section 5.4.1.5 "Quiet 
     Non-Number (QNaN)", p. 71,

[2] "MIPS Architecture For Programmers, Volume I-A: Introduction to the
     MIPS64 Architecture", MIPS Technologies, Inc., Document Number:
     MD00083, Revision 5.03, Sept. 9, 2013, Section 5.4.1.5 "Quiet 
     Non-Number (QNaN)", p. 74.

newlib-mips-nan2008.diff
Index: newlib-fsf-trunk-quilt/newlib/libc/stdlib/gd_qnan.h
===================================================================
--- newlib-fsf-trunk-quilt.orig/newlib/libc/stdlib/gd_qnan.h	2014-03-10 18:58:45.000000000 +0000
+++ newlib-fsf-trunk-quilt/newlib/libc/stdlib/gd_qnan.h	2014-03-10 21:26:11.248970516 +0000
@@ -1,5 +1,6 @@
 #ifdef __IEEE_BIG_ENDIAN
 
+#if !defined(__mips)
 #define f_QNAN 0x7fc00000
 #define d_QNAN0 0x7ff80000
 #define d_QNAN1 0x0
@@ -12,9 +13,19 @@
 #define ldus_QNAN2 0x0
 #define ldus_QNAN3 0x0
 #define ldus_QNAN4 0x0
+#elif defined(__mips_nan2008)
+#define f_QNAN 0x7fc00000
+#define d_QNAN0 0x7ff80000
+#define d_QNAN1 0x0
+#else
+#define f_QNAN 0x7fbfffff
+#define d_QNAN0 0x7ff7ffff
+#define d_QNAN1 0xffffffff
+#endif
 
 #elif defined(__IEEE_LITTLE_ENDIAN)
 
+#if !defined(__mips)
 #define f_QNAN 0xffc00000
 #define d_QNAN0 0x0
 #define d_QNAN1 0xfff80000
@@ -27,6 +38,15 @@
 #define ldus_QNAN2 0x0
 #define ldus_QNAN3 0xc000
 #define ldus_QNAN4 0xffff
+#elif defined(__mips_nan2008)
+#define f_QNAN 0x7fc00000
+#define d_QNAN0 0x0
+#define d_QNAN1 0x7ff80000
+#else
+#define f_QNAN 0x7fbfffff
+#define d_QNAN0 0xffffffff
+#define d_QNAN1 0x7ff7ffff
+#endif
 
 #else
 #error IEEE endian not defined
Index: newlib-fsf-trunk-quilt/newlib/libc/stdlib/ldtoa.c
===================================================================
--- newlib-fsf-trunk-quilt.orig/newlib/libc/stdlib/ldtoa.c	2014-03-10 18:58:45.000000000 +0000
+++ newlib-fsf-trunk-quilt/newlib/libc/stdlib/ldtoa.c	2014-03-10 21:29:32.268975182 +0000
@@ -3679,16 +3679,40 @@ emdnorm( num, 0, 0, ln, 0, ldp );
 /* NaN bit patterns
  */
 #ifdef MIEEE
+#if !defined(__mips)
 static _CONST unsigned short nan113[8] = {
   0x7fff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff};
-static _CONST unsigned short nan64[6] = {0x7fff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff};
+static _CONST unsigned short nan64[6] = {
+  0x7fff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff};
 static _CONST unsigned short nan53[4] = {0x7fff, 0xffff, 0xffff, 0xffff};
 static _CONST unsigned short nan24[2] = {0x7fff, 0xffff};
+#elif defined(__mips_nan2008) /* __mips */
+static _CONST unsigned short nan113[8] = {0x7fff, 0x8000, 0, 0, 0, 0, 0, 0};
+static _CONST unsigned short nan64[6] = {0x7fff, 0xc000, 0, 0, 0, 0};
+static _CONST unsigned short nan53[4] = {0x7ff8, 0, 0, 0};
+static _CONST unsigned short nan24[2] = {0x7fc0, 0};
+#else /* __mips && !__mips_nan2008 */
+static _CONST unsigned short nan113[8] = {
+  0x7fff, 0x7fff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff};
+static _CONST unsigned short nan64[6] = {
+  0x7fff, 0xbfff, 0xffff, 0xffff, 0xffff, 0xffff};
+static _CONST unsigned short nan53[4] = {0x7ff7, 0xffff, 0xffff, 0xffff};
+static _CONST unsigned short nan24[2] = {0x7fbf, 0xffff};
+#endif /* __mips && !__mips_nan2008 */
 #else /* !MIEEE */
+#if !defined(__mips) || defined(__mips_nan2008)
 static _CONST unsigned short nan113[8] = {0, 0, 0, 0, 0, 0, 0x8000, 0x7fff};
 static _CONST unsigned short nan64[6] = {0, 0, 0, 0, 0xc000, 0x7fff};
 static _CONST unsigned short nan53[4] = {0, 0, 0, 0x7ff8};
 static _CONST unsigned short nan24[2] = {0, 0x7fc0};
+#else /* __mips && !__mips_nan2008 */
+static _CONST unsigned short nan113[8] = {
+  0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x7fff, 0x7fff};
+static _CONST unsigned short nan64[6] = {
+  0xffff, 0xffff, 0xffff, 0xffff, 0xbfff, 0x7fff};
+static _CONST unsigned short nan53[4] = {0xffff, 0xffff, 0xffff, 0x7ff7};
+static _CONST unsigned short nan24[2] = {0xffff, 0x7fbf};
+#endif /* __mips && !__mips_nan2008 */
 #endif /* !MIEEE */
 
 
@@ -3721,9 +3745,15 @@ switch( size )
 	break;
 
 	case NBITS:
+#if !defined(__mips) || defined(__mips_nan2008)
 	for( i=0; i<NE-2; i++ )
 		*nan++ = 0;
 	*nan++ = 0xc000;
+#else /* __mips && !__mips_nan2008 */
+	for( i=0; i<NE-2; i++ )
+		*nan++ = 0xffff;
+	*nan++ = 0xbfff;
+#endif /* __mips && !__mips_nan2008 */
 	*nan++ = 0x7fff;
 	return;
 
@@ -3731,9 +3761,16 @@ switch( size )
 	*nan++ = 0;
 	*nan++ = 0x7fff;
 	*nan++ = 0;
+#if !defined(__mips) || defined(__mips_nan2008)
 	*nan++ = 0xc000;
-	for( i=4; i<NI; i++ )
+	for( i=4; i<NI-1; i++ )
 		*nan++ = 0;
+#else /* __mips && !__mips_nan2008 */
+	*nan++ = 0xbfff;
+	for( i=4; i<NI-1; i++ )
+		*nan++ = 0xffff;
+#endif /* __mips && !__mips_nan2008 */
+	*nan++ = 0;
 	return;
 #endif
 	default:
Index: newlib-fsf-trunk-quilt/newlib/libm/common/s_nan.c
===================================================================
--- newlib-fsf-trunk-quilt.orig/newlib/libm/common/s_nan.c	2014-03-10 18:58:42.000000000 +0000
+++ newlib-fsf-trunk-quilt/newlib/libm/common/s_nan.c	2014-03-10 21:26:11.748926514 +0000
@@ -41,7 +41,13 @@ QUICKREF
 {
 	double x;
 
+#if defined(__GNUC__) && \
+  ( (__GNUC__ >= 4) || \
+    ( (__GNUC__ >= 3) && defined(__GNUC_MINOR__) && (__GNUC_MINOR__ >= 3) ) )
+	x = __builtin_nan("");
+#else
 	INSERT_WORDS(x,0x7ff80000,0);
+#endif
 	return x;
 }
 
Index: newlib-fsf-trunk-quilt/newlib/libm/common/sf_nan.c
===================================================================
--- newlib-fsf-trunk-quilt.orig/newlib/libm/common/sf_nan.c	2014-03-10 18:58:42.000000000 +0000
+++ newlib-fsf-trunk-quilt/newlib/libm/common/sf_nan.c	2014-03-10 21:26:11.748926514 +0000
@@ -9,7 +9,13 @@
 {
 	float x;
 
+#if defined(__GNUC__) && \
+  ( (__GNUC__ >= 4) || \
+    ( (__GNUC__ >= 3) && defined(__GNUC_MINOR__) && (__GNUC_MINOR__ >= 3) ) )
+	x = __builtin_nanf("");
+#else
 	SET_FLOAT_WORD(x,0x7fc00000);
+#endif
 	return x;
 }
 


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]