about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJoseph Myers <joseph@codesourcery.com>2015-02-06 15:41:49 +0000
committerJoseph Myers <joseph@codesourcery.com>2015-02-06 15:41:49 +0000
commit61f006c12d8ff3a80a95a36fed81c908a2e39650 (patch)
treeb669c8f9c4ef70907f386bf034f5567fcded7ba7
parent639e42eb901b69d3a4d6414751c60fab0ca25119 (diff)
downloadglibc-61f006c12d8ff3a80a95a36fed81c908a2e39650.tar.gz
glibc-61f006c12d8ff3a80a95a36fed81c908a2e39650.tar.xz
glibc-61f006c12d8ff3a80a95a36fed81c908a2e39650.zip
soft-fp: Refine FP_EX_DENORM handling for comparisons.
In <https://sourceware.org/ml/libc-alpha/2014-09/msg00488.html>, I
noted that comparisons in soft-fp did not set FP_EX_DENORM unless
denormal operands were flushed to zero.

This patch fixes soft-fp to check for denormal operands for
comparisons and set that exception whenever FP_EX_DENORM is not zero.
In particular, for the one architecture for which the Linux kernel
defines FP_EX_DENORM (alpha), this corresponds to the existing logic
for comparisons and so allows that logic to be replaced by a simple
call to FP_CMP_D when soft-fp is updated in the kernel.

Tested for powerpc (e500) that installed stripped shared libraries are
unchanged by this patch.

	* soft-fp/op-common.h (_FP_CMP_CHECK_DENORM): New macro.
	(_FP_CMP_CHECK_FLUSH_ZERO): Likewise.
	(_FP_CMP): Use_FP_CMP_CHECK_DENORM and _FP_CMP_CHECK_FLUSH_ZERO.
	(_FP_CMP_EQ): Likewise.
	(_FP_CMP_UNORD): Use _FP_CMP_CHECK_DENORM.
-rw-r--r--ChangeLog6
-rw-r--r--soft-fp/op-common.h49
2 files changed, 51 insertions, 4 deletions
diff --git a/ChangeLog b/ChangeLog
index 0ef8a61b65..32b766728e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,11 @@
 2015-02-06  Joseph Myers  <joseph@codesourcery.com>
 
+	* soft-fp/op-common.h (_FP_CMP_CHECK_DENORM): New macro.
+	(_FP_CMP_CHECK_FLUSH_ZERO): Likewise.
+	(_FP_CMP): Use_FP_CMP_CHECK_DENORM and _FP_CMP_CHECK_FLUSH_ZERO.
+	(_FP_CMP_EQ): Likewise.
+	(_FP_CMP_UNORD): Use _FP_CMP_CHECK_DENORM.
+
 	* soft-fp/op-common.h (FP_EXTEND): Rename to _FP_EXTEND_CNAN with
 	extra argument CHECK_NAN.  Redefine as wrapper around
 	_FP_EXTEND_CNAN.
diff --git a/soft-fp/op-common.h b/soft-fp/op-common.h
index 98cc721355..389ba3fcfa 100644
--- a/soft-fp/op-common.h
+++ b/soft-fp/op-common.h
@@ -1251,6 +1251,46 @@
     }									\
   while (0)
 
+/* Helper for comparisons.  If denormal operands would raise an
+   exception, check for them, and flush to zero as appropriate
+   (otherwise, we need only check and flush to zero if it might affect
+   the result, which is done later with _FP_CMP_CHECK_FLUSH_ZERO).  */
+#define _FP_CMP_CHECK_DENORM(fs, wc, X, Y)				\
+  do									\
+    {									\
+      if (FP_EX_DENORM != 0)						\
+	{								\
+	  /* We must ensure the correct exceptions are raised for	\
+	     denormal operands, even though this may not affect the	\
+	     result of the comparison.  */				\
+	  if (FP_DENORM_ZERO)						\
+	    {								\
+	      _FP_CHECK_FLUSH_ZERO (fs, wc, X);				\
+	      _FP_CHECK_FLUSH_ZERO (fs, wc, Y);				\
+	    }								\
+	  else								\
+	    {								\
+	      if ((X##_e == 0 && !_FP_FRAC_ZEROP_##wc (X))		\
+		  || (Y##_e == 0 && !_FP_FRAC_ZEROP_##wc (Y)))		\
+		FP_SET_EXCEPTION (FP_EX_DENORM);			\
+	    }								\
+	}								\
+    }									\
+  while (0)
+
+/* Helper for comparisons.  Check for flushing denormals for zero if
+   we didn't need to check earlier for any denormal operands.  */
+#define _FP_CMP_CHECK_FLUSH_ZERO(fs, wc, X, Y)	\
+  do						\
+    {						\
+      if (FP_EX_DENORM == 0)			\
+	{					\
+	  _FP_CHECK_FLUSH_ZERO (fs, wc, X);	\
+	  _FP_CHECK_FLUSH_ZERO (fs, wc, Y);	\
+	}					\
+    }						\
+  while (0)
+
 /* Main differential comparison routine.  The inputs should be raw not
    cooked.  The return is -1, 0, 1 for normal values, UN
    otherwise.  */
@@ -1258,6 +1298,7 @@
 #define _FP_CMP(fs, wc, ret, X, Y, un, ex)				\
   do									\
     {									\
+      _FP_CMP_CHECK_DENORM (fs, wc, X, Y);				\
       /* NANs are unordered.  */					\
       if ((X##_e == _FP_EXPMAX_##fs && !_FP_FRAC_ZEROP_##wc (X))	\
 	  || (Y##_e == _FP_EXPMAX_##fs && !_FP_FRAC_ZEROP_##wc (Y)))	\
@@ -1270,8 +1311,7 @@
 	  int _FP_CMP_is_zero_x;					\
 	  int _FP_CMP_is_zero_y;					\
 									\
-	  _FP_CHECK_FLUSH_ZERO (fs, wc, X);				\
-	  _FP_CHECK_FLUSH_ZERO (fs, wc, Y);				\
+	  _FP_CMP_CHECK_FLUSH_ZERO (fs, wc, X, Y);			\
 									\
 	  _FP_CMP_is_zero_x						\
 	    = (!X##_e && _FP_FRAC_ZEROP_##wc (X)) ? 1 : 0;		\
@@ -1306,6 +1346,7 @@
 #define _FP_CMP_EQ(fs, wc, ret, X, Y, ex)				\
   do									\
     {									\
+      _FP_CMP_CHECK_DENORM (fs, wc, X, Y);				\
       /* NANs are unordered.  */					\
       if ((X##_e == _FP_EXPMAX_##fs && !_FP_FRAC_ZEROP_##wc (X))	\
 	  || (Y##_e == _FP_EXPMAX_##fs && !_FP_FRAC_ZEROP_##wc (Y)))	\
@@ -1315,8 +1356,7 @@
 	}								\
       else								\
 	{								\
-	  _FP_CHECK_FLUSH_ZERO (fs, wc, X);				\
-	  _FP_CHECK_FLUSH_ZERO (fs, wc, Y);				\
+	  _FP_CMP_CHECK_FLUSH_ZERO (fs, wc, X, Y);			\
 									\
 	  (ret) = !(X##_e == Y##_e					\
 		    && _FP_FRAC_EQ_##wc (X, Y)				\
@@ -1331,6 +1371,7 @@
 #define _FP_CMP_UNORD(fs, wc, ret, X, Y, ex)				\
   do									\
     {									\
+      _FP_CMP_CHECK_DENORM (fs, wc, X, Y);				\
       (ret) = ((X##_e == _FP_EXPMAX_##fs && !_FP_FRAC_ZEROP_##wc (X))	\
 	       || (Y##_e == _FP_EXPMAX_##fs && !_FP_FRAC_ZEROP_##wc (Y))); \
       if (ret)								\