This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc 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/glibc: soft-fp NaN representation corrections


Hi,

 Unlike many platforms traditional MIPS targets interpret the quiet bit of 
NaN data in the inverse way, a NaN is quiet whenever the bit is clear.  
Additionally the canonical qNaN encoding has all the payload bits set 
rather than clear.  The quiet bit convention is however currently not 
respected by our soft-fp implementation.  Here's a suitable change to 
correct it.

 The changes are extensive, however the only use by the MIPS target within 
glibc is sqrtl on the new ABIs (I have an outstanding change to make GCC's 
copy of soft-fp used in a more extensive manner though).  I have manually 
verified that this change has the desired effect on that function, both 
with the n64 and the n32 ABI and both endiannesses each.  The o32 version 
of sfp-machine.h appears unused, however I changed it for correctness 
regardless (perhaps the file should be dropped).

 For the sake of readability and ease of maintenance I decided to factor 
out both raw (_FP_FRAC_SNANP, _FP_SETQNAN) and semi-raw 
(_FP_FRAC_SNANP_SEMIRAW, _FP_SETQNAN_SEMIRAW) macros even though the 
latters are only used once each.

 These changes touch generic code, for the most part.  They are supposed 
not to affect targets other than MIPS, however I think it would make sense 
to test them at least on a selection of other targets glibc supports.  
However I am not familiar enough with other targets to know how much 
soft-fp is used across them; also I think automatic testing may have a 
better value than manually poking at a function or three.  I will 
therefore appreciate ideas as to how to test these changes, or any other 
help with that indeed.

 Otherwise, do these changes look OK?

2013-04-24  Maciej W. Rozycki  <macro@codesourcery.com>

	/
	* soft-fp/op-common.h (_FP_FRAC_SNANP): New macro.
	(_FP_FRAC_SNANP_SEMIRAW): Likewise.
	(_FP_UNPACK_CANONICAL): Use _FP_FRAC_SNANP.
	(_FP_CHECK_SIGNAN_SEMIRAW): Use _FP_FRAC_SNANP_SEMIRAW.
	(_FP_SETQNAN): New macro.
	(_FP_SETQNAN_SEMIRAW): Likewise.
	(_FP_PACK_SEMIRAW): Use _FP_SETQNAN.
	(_FP_PACK_CANONICAL): Use _FP_SETQNAN.
	(_FP_ISSIGNAN): Use _FP_FRAC_SNANP.
	(FP_EXTEND): Use _FP_FRAC_SNANP.
	(FP_TRUNC): Use _FP_SETQNAN_SEMIRAW.
	* soft-fp/testit.c (gen_special_double): Take _FP_QNANNEGATEDP
	into account.
	* sysdeps/sparc/sparc32/soft-fp/sfp-machine.h (_FP_QNANNEGATEDP):
	New macro.
	* sysdeps/sparc/sparc64/soft-fp/sfp-machine.h (_FP_QNANNEGATEDP):
	Likewise.

	ports/
	* sysdeps/mips/mips64/soft-fp/sfp-machine.h (_FP_QNANNEGATEDP):
	New macro.
	(_FP_NANFRAC_S): Don't set the quiet bit.
	(_FP_NANFRAC_D): Likewise.
	(_FP_NANFRAC_Q): Likewise.
	* sysdeps/mips/soft-fp/sfp-machine.h (_FP_QNANNEGATEDP): New
	macro.
	(_FP_NANFRAC_S): Don't set the quiet bit.
	(_FP_NANFRAC_D): Likewise.
	(_FP_NANFRAC_Q): Likewise.
	* sysdeps/aarch64/soft-fp/sfp-machine.h (_FP_QNANNEGATEDP): New 
	macro.
	* sysdeps/alpha/soft-fp/sfp-machine.h (_FP_QNANNEGATEDP): 
	Likewise.
	* sysdeps/powerpc/soft-fp/sfp-machine.h (_FP_QNANNEGATEDP): New
	macro.

  Maciej

glibc-mips-soft-fp-nan.diff
Index: glibc-fsf-trunk-quilt/ports/sysdeps/aarch64/soft-fp/sfp-machine.h
===================================================================
--- glibc-fsf-trunk-quilt.orig/ports/sysdeps/aarch64/soft-fp/sfp-machine.h	2013-04-23 00:28:50.097012113 +0100
+++ glibc-fsf-trunk-quilt/ports/sysdeps/aarch64/soft-fp/sfp-machine.h	2013-04-23 00:33:47.108144185 +0100
@@ -25,6 +25,8 @@
 #define _FP_NANSIGN_Q		0
 
 #define _FP_KEEPNANFRACP 1
+#define _FP_QNANNEGATEDP 0
+
 /* From my experiments it seems X is chosen unless one of the
    NaNs is sNaN,  in which case the result is NANSIGN/NANFRAC.  */
 #define _FP_CHOOSENAN(fs, wc, R, X, Y, OP)			\
Index: glibc-fsf-trunk-quilt/ports/sysdeps/alpha/soft-fp/sfp-machine.h
===================================================================
--- glibc-fsf-trunk-quilt.orig/ports/sysdeps/alpha/soft-fp/sfp-machine.h	2013-04-23 00:28:50.097012113 +0100
+++ glibc-fsf-trunk-quilt/ports/sysdeps/alpha/soft-fp/sfp-machine.h	2013-04-23 00:33:47.108144185 +0100
@@ -46,6 +46,7 @@
 #define _FP_NANSIGN_Q		0
 
 #define _FP_KEEPNANFRACP 1
+#define _FP_QNANNEGATEDP 0
 
 /* Alpha Architecture Handbook, 4.7.10.4 sez that we should prefer any
    type of NaN in Fb, then Fa.  */
Index: glibc-fsf-trunk-quilt/ports/sysdeps/mips/mips64/soft-fp/sfp-machine.h
===================================================================
--- glibc-fsf-trunk-quilt.orig/ports/sysdeps/mips/mips64/soft-fp/sfp-machine.h	2013-04-23 00:28:50.097012113 +0100
+++ glibc-fsf-trunk-quilt/ports/sysdeps/mips/mips64/soft-fp/sfp-machine.h	2013-04-23 00:33:47.108144185 +0100
@@ -17,14 +17,16 @@
 #define _FP_DIV_MEAT_D(R,X,Y)	_FP_DIV_MEAT_1_udiv_norm(D,R,X,Y)
 #define _FP_DIV_MEAT_Q(R,X,Y)	_FP_DIV_MEAT_2_udiv(Q,R,X,Y)
 
-#define _FP_NANFRAC_S		((_FP_QNANBIT_S << 1) - 1)
-#define _FP_NANFRAC_D		((_FP_QNANBIT_D << 1) - 1)
-#define _FP_NANFRAC_Q		((_FP_QNANBIT_Q << 1) - 1), -1
+#define _FP_NANFRAC_S		(_FP_QNANBIT_S - 1)
+#define _FP_NANFRAC_D		(_FP_QNANBIT_D - 1)
+#define _FP_NANFRAC_Q		(_FP_QNANBIT_Q - 1), -1
 #define _FP_NANSIGN_S		0
 #define _FP_NANSIGN_D		0
 #define _FP_NANSIGN_Q		0
 
 #define _FP_KEEPNANFRACP 1
+#define _FP_QNANNEGATEDP 1
+
 /* From my experiments it seems X is chosen unless one of the
    NaNs is sNaN,  in which case the result is NANSIGN/NANFRAC.  */
 #define _FP_CHOOSENAN(fs, wc, R, X, Y, OP)			\
Index: glibc-fsf-trunk-quilt/ports/sysdeps/mips/soft-fp/sfp-machine.h
===================================================================
--- glibc-fsf-trunk-quilt.orig/ports/sysdeps/mips/soft-fp/sfp-machine.h	2013-04-23 00:28:50.097012113 +0100
+++ glibc-fsf-trunk-quilt/ports/sysdeps/mips/soft-fp/sfp-machine.h	2013-04-23 00:33:47.108144185 +0100
@@ -14,14 +14,16 @@
 #define _FP_DIV_MEAT_D(R,X,Y)	_FP_DIV_MEAT_2_udiv(D,R,X,Y)
 #define _FP_DIV_MEAT_Q(R,X,Y)	_FP_DIV_MEAT_4_udiv(Q,R,X,Y)
 
-#define _FP_NANFRAC_S		((_FP_QNANBIT_S << 1) - 1)
-#define _FP_NANFRAC_D		((_FP_QNANBIT_D << 1) - 1), -1
-#define _FP_NANFRAC_Q		((_FP_QNANBIT_Q << 1) - 1), -1, -1, -1
+#define _FP_NANFRAC_S		(_FP_QNANBIT_S - 1)
+#define _FP_NANFRAC_D		(_FP_QNANBIT_D - 1), -1
+#define _FP_NANFRAC_Q		(_FP_QNANBIT_Q - 1), -1, -1, -1
 #define _FP_NANSIGN_S		0
 #define _FP_NANSIGN_D		0
 #define _FP_NANSIGN_Q		0
 
 #define _FP_KEEPNANFRACP 1
+#define _FP_QNANNEGATEDP 1
+
 /* From my experiments it seems X is chosen unless one of the
    NaNs is sNaN,  in which case the result is NANSIGN/NANFRAC.  */
 #define _FP_CHOOSENAN(fs, wc, R, X, Y, OP)			\
Index: glibc-fsf-trunk-quilt/ports/sysdeps/powerpc/soft-fp/sfp-machine.h
===================================================================
--- glibc-fsf-trunk-quilt.orig/ports/sysdeps/powerpc/soft-fp/sfp-machine.h	2013-04-23 00:28:50.097012113 +0100
+++ glibc-fsf-trunk-quilt/ports/sysdeps/powerpc/soft-fp/sfp-machine.h	2013-04-23 00:33:47.108144185 +0100
@@ -22,6 +22,7 @@
 #define _FP_NANSIGN_Q		0
 
 #define _FP_KEEPNANFRACP 1
+#define _FP_QNANNEGATEDP 0
 
 /* Someone please check this.  */
 #define _FP_CHOOSENAN(fs, wc, R, X, Y, OP)			\
Index: glibc-fsf-trunk-quilt/soft-fp/op-common.h
===================================================================
--- glibc-fsf-trunk-quilt.orig/soft-fp/op-common.h	2013-04-23 00:33:45.606803329 +0100
+++ glibc-fsf-trunk-quilt/soft-fp/op-common.h	2013-04-23 00:33:47.108144185 +0100
@@ -35,6 +35,16 @@
   _FP_I_TYPE X##_e;				\
   _FP_FRAC_DECL_##wc(X)
 
+/* Test whether the qNaN bit denotes a signaling NaN.  */
+#define _FP_FRAC_SNANP(fs, X)						\
+  ((_FP_QNANNEGATEDP)							\
+   ? (_FP_FRAC_HIGH_RAW_##fs(X) & _FP_QNANBIT_##fs)			\
+   : !(_FP_FRAC_HIGH_RAW_##fs(X) & _FP_QNANBIT_##fs))
+#define _FP_FRAC_SNANP_SEMIRAW(fs, X)					\
+  ((_FP_QNANNEGATEDP)							\
+   ? (_FP_FRAC_HIGH_##fs(X) & _FP_QNANBIT_SH_##fs)			\
+   : !(_FP_FRAC_HIGH_##fs(X) & _FP_QNANBIT_SH_##fs))
+
 /*
  * Finish truely unpacking a native fp value by classifying the kind
  * of fp value and normalizing both the exponent and the fraction.
@@ -74,7 +84,7 @@ do {									\
       {									\
 	X##_c = FP_CLS_NAN;						\
 	/* Check for signaling NaN */					\
-	if (!(_FP_FRAC_HIGH_RAW_##fs(X) & _FP_QNANBIT_##fs))		\
+	if (_FP_FRAC_SNANP(fs, X))					\
 	  FP_SET_EXCEPTION(FP_EX_INVALID);				\
       }									\
     break;								\
@@ -112,7 +122,7 @@ do {							\
 do {								\
   if (X##_e == _FP_EXPMAX_##fs					\
       && !_FP_FRAC_ZEROP_##wc(X)				\
-      && !(_FP_FRAC_HIGH_##fs(X) & _FP_QNANBIT_SH_##fs))	\
+      && _FP_FRAC_SNANP_SEMIRAW(fs, X))				\
     FP_SET_EXCEPTION(FP_EX_INVALID);				\
 } while (0)
 
@@ -127,6 +137,39 @@ do {									\
   _FP_FRAC_SLL_##wc(R, _FP_WORKBITS);					\
 } while (0)
 
+/* Make the fractional part a quiet NaN, preserving the payload
+   if possible, otherwise make it the canonical quiet NaN and set
+   the sign bit accordingly.  */
+#define _FP_SETQNAN(fs, wc, X)						\
+do {									\
+  if (_FP_QNANNEGATEDP)							\
+    {									\
+      _FP_FRAC_HIGH_RAW_##fs(X) &= _FP_QNANBIT_##fs - 1;		\
+      if (_FP_FRAC_ZEROP_##wc(X))					\
+	{								\
+	  X##_s = _FP_NANSIGN_##fs;					\
+	  _FP_FRAC_SET_##wc(X, _FP_NANFRAC_##fs);			\
+	}								\
+    }									\
+  else									\
+    _FP_FRAC_HIGH_RAW_##fs(X) |= _FP_QNANBIT_##fs;			\
+} while (0)
+#define _FP_SETQNAN_SEMIRAW(fs, wc, X)					\
+do {									\
+  if (_FP_QNANNEGATEDP)							\
+    {									\
+      _FP_FRAC_HIGH_##fs(X) &= _FP_QNANBIT_SH_##fs - 1;			\
+      if (_FP_FRAC_ZEROP_##wc(X))					\
+	{								\
+	  X##_s = _FP_NANSIGN_##fs;					\
+	  _FP_FRAC_SET_##wc(X, _FP_NANFRAC_##fs);			\
+	  _FP_FRAC_SLL_##wc(X, _FP_WORKBITS);				\
+	}								\
+    }									\
+  else									\
+    _FP_FRAC_HIGH_##fs(X) |= _FP_QNANBIT_SH_##fs;			\
+} while (0)
+
 /* Test whether a biased exponent is normal (not zero or maximum).  */
 #define _FP_EXP_NORMAL(fs, wc, X)	(((X##_e + 1) & _FP_EXPMAX_##fs) > 1)
 
@@ -159,7 +202,7 @@ do {								\
 	  X##_s = _FP_NANSIGN_##fs;				\
 	}							\
       else							\
-	_FP_FRAC_HIGH_RAW_##fs(X) |= _FP_QNANBIT_##fs;		\
+	_FP_SETQNAN(fs, wc, X);					\
     }								\
 } while (0)
 
@@ -273,7 +316,7 @@ do {								\
 	X##_s = _FP_NANSIGN_##fs;				\
       }								\
     else							\
-      _FP_FRAC_HIGH_RAW_##fs(X) |= _FP_QNANBIT_##fs;		\
+      _FP_SETQNAN(fs, wc, X);					\
     break;							\
   }								\
 } while (0)
@@ -287,7 +330,7 @@ do {								\
   if (X##_e == _FP_EXPMAX_##fs)					\
     {								\
       if (!_FP_FRAC_ZEROP_##wc(X)				\
-	  && !(_FP_FRAC_HIGH_RAW_##fs(X) & _FP_QNANBIT_##fs))	\
+	  && _FP_FRAC_SNANP(fs, X))				\
 	__ret = 1;						\
     }								\
   __ret;							\
@@ -1199,7 +1242,7 @@ do {									 \
 	  D##_e = _FP_EXPMAX_##dfs;					 \
 	  if (!_FP_FRAC_ZEROP_##swc(S))					 \
 	    {								 \
-	      if (!(_FP_FRAC_HIGH_RAW_##sfs(S) & _FP_QNANBIT_##sfs))	 \
+	      if (_FP_FRAC_SNANP(sfs, S))				 \
 		FP_SET_EXCEPTION(FP_EX_INVALID);			 \
 	      _FP_FRAC_SLL_##dwc(D, (_FP_FRACBITS_##dfs			 \
 				     - _FP_FRACBITS_##sfs));		 \
@@ -1286,7 +1329,7 @@ do {									     \
 	      /* Semi-raw NaN must have all workbits cleared.  */	     \
 	      _FP_FRAC_LOW_##dwc(D)					     \
 		&= ~(_FP_W_TYPE) ((1 << _FP_WORKBITS) - 1);		     \
-	      _FP_FRAC_HIGH_##dfs(D) |= _FP_QNANBIT_SH_##dfs;		     \
+	      _FP_SETQNAN_SEMIRAW(dfs, dwc, D);				     \
 	    }								     \
 	}								     \
     }									     \
Index: glibc-fsf-trunk-quilt/soft-fp/testit.c
===================================================================
--- glibc-fsf-trunk-quilt.orig/soft-fp/testit.c	2013-04-23 00:28:50.598144385 +0100
+++ glibc-fsf-trunk-quilt/soft-fp/testit.c	2013-04-23 00:33:47.108144185 +0100
@@ -200,17 +200,17 @@ double gen_special_double(int i)
       case 0:
 	X_c = FP_CLS_NAN;
 #if _FP_W_TYPE_SIZE < _FP_FRACBITS_D
-	__FP_FRAC_SET_2(X, _FP_QNANBIT_D, 0x1234);
+	__FP_FRAC_SET_2(X, _FP_QNANNEGATEDP ? 0 : _FP_QNANBIT_D, 0x1234);
 #else
-	_FP_FRAC_SET_1(X, _FP_QNANBIT_D | 0x1234);
+	_FP_FRAC_SET_1(X, (_FP_QNANNEGATEDP ? 0 : _FP_QNANBIT_D) | 0x1234);
 #endif
 	break;
       case 2:
 	X_c = FP_CLS_NAN;
 #if _FP_W_TYPE_SIZE < _FP_FRACBITS_D
-	__FP_FRAC_SET_2(X, _FP_QNANBIT_D, 0x1);
+	__FP_FRAC_SET_2(X, _FP_QNANNEGATEDP ? 0 : _FP_QNANBIT_D, 0x1);
 #else
-	_FP_FRAC_SET_1(X, _FP_QNANBIT_D | 0x1);
+	_FP_FRAC_SET_1(X, (_FP_QNANNEGATEDP ? 0 : _FP_QNANBIT_D) | 0x1);
 #endif
 	break;
       case 4:
Index: glibc-fsf-trunk-quilt/sysdeps/sparc/sparc32/soft-fp/sfp-machine.h
===================================================================
--- glibc-fsf-trunk-quilt.orig/sysdeps/sparc/sparc32/soft-fp/sfp-machine.h	2013-04-23 00:28:50.598144385 +0100
+++ glibc-fsf-trunk-quilt/sysdeps/sparc/sparc32/soft-fp/sfp-machine.h	2013-04-23 00:33:47.108144185 +0100
@@ -47,6 +47,7 @@
 #define _FP_NANSIGN_Q		0
 
 #define _FP_KEEPNANFRACP 1
+#define _FP_QNANNEGATEDP 0
 
 /* If one NaN is signaling and the other is not,
  * we choose that one, otherwise we choose X.
Index: glibc-fsf-trunk-quilt/sysdeps/sparc/sparc64/soft-fp/sfp-machine.h
===================================================================
--- glibc-fsf-trunk-quilt.orig/sysdeps/sparc/sparc64/soft-fp/sfp-machine.h	2013-04-23 00:28:50.598144385 +0100
+++ glibc-fsf-trunk-quilt/sysdeps/sparc/sparc64/soft-fp/sfp-machine.h	2013-04-23 00:33:47.108144185 +0100
@@ -60,6 +60,7 @@ do {								\
 #define _FP_NANSIGN_Q		0
 
 #define _FP_KEEPNANFRACP 1
+#define _FP_QNANNEGATEDP 0
 
 /* If one NaN is signaling and the other is not,
  * we choose that one, otherwise we choose Y.


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