summary refs log tree commit diff
path: root/soft-fp
diff options
context:
space:
mode:
authorJoseph Myers <joseph@codesourcery.com>2014-10-09 15:00:37 +0000
committerJoseph Myers <joseph@codesourcery.com>2014-10-09 15:00:37 +0000
commita736ec370a05e4b37e6101eb3168bf8dc4c5af13 (patch)
tree665968c60d407cb06565ee80c8c2dcc996f42807 /soft-fp
parentff12c11f4515a9f83467471e8d4381eb3dbc06b5 (diff)
downloadglibc-a736ec370a05e4b37e6101eb3168bf8dc4c5af13.tar.gz
glibc-a736ec370a05e4b37e6101eb3168bf8dc4c5af13.tar.xz
glibc-a736ec370a05e4b37e6101eb3168bf8dc4c5af13.zip
soft-fp: Support rsigned == 2 in _FP_TO_INT.
Continuing the addition of soft-fp features in the Linux kernel
version, this patch adds _FP_TO_INT support for rsigned == 2 (reduce
overflowing results modulo 2^rsize to fit in the destination, used for
alpha emulation).

The kernel version is buggy; it can left shift by a negative amount
when right shifting is required in an overflow case (the kernel
version also has other bugs fixed long ago in glibc; at least,
spurious exceptions converting to the most negative integer).  This
version avoids that by handling overflow (other than to 0) for rsigned
== 2 along with the normal non-overflow case, which already properly
determines the direction in which to shift.

Tested for powerpc-nofpu.  Some functions get slightly bigger and some
get slightly smaller, no doubt as a result of the change to where in
the macro "inexact" is raised, but I don't think those changes are
significant.  Also tested for powerpc-nofpu with the relevant __fix*
functions changed to use rsigned == 2 (which is after all just as
valid as rsigned == 1 in IEEE terms), including verifying the results
and exceptions for various cases of conversions.

With these seven patches, the one remaining feature to add for the
soft-fp code to have all the features of the kernel version is
_FP_TO_INT_ROUND.

	* soft-fp/op-common.h (_FP_TO_INT): Handle rsigned == 2.
Diffstat (limited to 'soft-fp')
-rw-r--r--soft-fp/op-common.h45
1 files changed, 38 insertions, 7 deletions
diff --git a/soft-fp/op-common.h b/soft-fp/op-common.h
index 8344be5aad..3591c47efb 100644
--- a/soft-fp/op-common.h
+++ b/soft-fp/op-common.h
@@ -1399,6 +1399,8 @@
    1:  the number is required to be -(2^(rsize-1))..(2^(rsize-1))-1, if not,
        NV is set plus the result is either -(2^(rsize-1)) or (2^(rsize-1))-1
        depending on the sign in such case.
+   2:  the number is required to be -(2^(rsize-1))..(2^(rsize-1))-1, if not,
+       NV is set plus the result is reduced modulo 2^rsize.
    -1: the number is required to be -(2^(rsize-1))..(2^rsize)-1, if not, NV is
        set plus the result is either -(2^(rsize-1)) or (2^(rsize-1))-1
        depending on the sign in such case.  */
@@ -1420,10 +1422,28 @@
 	  else								\
 	    FP_SET_EXCEPTION (FP_EX_INEXACT);				\
 	}								\
-      else if (X##_e >= (_FP_EXPMAX_##fs < _FP_EXPBIAS_##fs + rsize	\
-			 ? _FP_EXPMAX_##fs				\
-			 : _FP_EXPBIAS_##fs + rsize - (rsigned > 0 || X##_s)) \
-	       || (!rsigned && X##_s))					\
+      else if (rsigned == 2						\
+	       && (X##_e						\
+		   >= ((_FP_EXPMAX_##fs					\
+			< _FP_EXPBIAS_##fs + _FP_FRACBITS_##fs + rsize - 1) \
+		       ? _FP_EXPMAX_##fs				\
+		       : _FP_EXPBIAS_##fs + _FP_FRACBITS_##fs + rsize - 1))) \
+	{								\
+	  /* Overflow resulting in 0.  */				\
+	  r = 0;							\
+	  FP_SET_EXCEPTION (FP_EX_INVALID				\
+			    | FP_EX_INVALID_CVI				\
+			    | ((FP_EX_INVALID_SNAN			\
+				&& _FP_ISSIGNAN (fs, wc, X))		\
+			       ? FP_EX_INVALID_SNAN			\
+			       : 0));					\
+	}								\
+      else if (rsigned != 2						\
+	       && (X##_e >= (_FP_EXPMAX_##fs < _FP_EXPBIAS_##fs + rsize	\
+			     ? _FP_EXPMAX_##fs				\
+			     : (_FP_EXPBIAS_##fs + rsize		\
+				- (rsigned > 0 || X##_s)))		\
+		   || (!rsigned && X##_s)))				\
 	{								\
 	  /* Overflow or converting to the most negative integer.  */	\
 	  if (rsigned)							\
@@ -1470,6 +1490,7 @@
 	}								\
       else								\
 	{								\
+	  int _FP_TO_INT_inexact = 0;					\
 	  _FP_FRAC_HIGH_RAW_##fs (X) |= _FP_IMPLBIT_##fs;		\
 	  if (X##_e >= _FP_EXPBIAS_##fs + _FP_FRACBITS_##fs - 1)	\
 	    {								\
@@ -1478,17 +1499,27 @@
 	    }								\
 	  else								\
 	    {								\
-	      int _FP_TO_INT_inexact;					\
 	      _FP_FRAC_SRST_##wc (X, _FP_TO_INT_inexact,		\
 				  (_FP_FRACBITS_##fs + _FP_EXPBIAS_##fs - 1 \
 				   - X##_e),				\
 				  _FP_FRACBITS_##fs);			\
-	      if (_FP_TO_INT_inexact)					\
-		FP_SET_EXCEPTION (FP_EX_INEXACT);			\
 	      _FP_FRAC_ASSEMBLE_##wc (r, X, rsize);			\
 	    }								\
 	  if (rsigned && X##_s)						\
 	    r = -r;							\
+	  if (rsigned == 2 && X##_e >= _FP_EXPBIAS_##fs + rsize - 1)	\
+	    {								\
+	      /* Overflow or converting to the most negative integer.  */ \
+	      if (X##_e > _FP_EXPBIAS_##fs + rsize - 1			\
+		  || !X##_s						\
+		  || r != (((typeof (r)) 1) << (rsize - 1)))		\
+		{							\
+		  _FP_TO_INT_inexact = 0;				\
+		  FP_SET_EXCEPTION (FP_EX_INVALID | FP_EX_INVALID_CVI);	\
+		}							\
+	    }								\
+	  if (_FP_TO_INT_inexact)					\
+	    FP_SET_EXCEPTION (FP_EX_INEXACT);				\
 	}								\
     }									\
   while (0)