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]

soft-fp: support after-rounding tininess detection


IEEE 754-2008 defines two ways in which tiny results can be detected,
"before rounding" (based on the infinite-precision result) and "after
rounding" (based on the result when rounded to normal precision as if
the exponent range were unbounded).  All binary operations on an
architecture must use the same choice of how tininess is detected.

soft-fp has so far implemented only before-rounding tininess
detection.  This patch, intended for after 2.19 branches, adds support
for after-rounding tininess detection.  A new macro
_FP_TININESS_AFTER_ROUNDING is added that sfp-machine.h must define
(soft-fp is meant to be self-contained so the existing tininess.h
files aren't used here, though the information going in sfp-machine.h
has been taken from them).  The soft-fp macros dealing with raising
underflow exceptions then handle the cases where the choice matters
specially, rounding a copy of the input to the appropriate precision
to see if a value that's tiny before rounding isn't tiny after
rounding.

Tested for mips64 using GCC trunk (which now uses soft-fp on MIPS, so
supporting exceptions and rounding modes for long double where not
previously supported - this is the immediate motivation for doing this
patch now) together with (a) a patch to
ports/sysdeps/mips/math-tests.h to enable exceptions / rounding modes
tests for long double for GCC 4.9 and later, and (b) corresponding
changes applied to libgcc's soft-fp and sfp-machine.h files.  In the
libgcc context this is also tested on x86_64 (also an after-rounding
architecture) with testcases for __float128 that I intend to add to
the GCC testsuite when updating soft-fp there.

(To be clear: this patch does not fix any glibc bugs that were
user-visible in past releases, since after-rounding architectures
didn't use soft-fp in any affected case with support for
floating-point exceptions - so there is no corresponding Bugzilla bug.
Rather, it works together with the GCC changes to use soft-fp on MIPS
to allow previously absent long double functionality to work properly,
and allows soft-fp to be used in glibc on after-rounding architectures
in cases where it couldn't previously be used.)

Richard, this should allow you to use the soft-fp version of fmal for
alpha, where previously
<https://sourceware.org/ml/libc-alpha/2013-06/msg00933.html> it caused
spurious exceptions.  (I have no benchmarks, but whenever the
underlying floating-point arithmetic uses soft-fp it should be a lot
faster to use the straight soft-fp fma instead of the sysdeps/ieee754
versions that build fma on lots of individual floating-point
operations with saving and restoring of the rounding mode along the
way.  Adding fmaf / fma / fmal tests to the glibc benchmark suite
would be useful.)

2014-02-03  Joseph Myers  <joseph@codesourcery.com>

	* soft-fp/op-common.h (_FP_DECL): Mark exponent as possibly
	unused.
	(_FP_PACK_SEMIRAW): Determine tininess based on rounding shifted
	value if _FP_TININESS_AFTER_ROUNDING and unrounded value is in
	subnormal range.
	(_FP_PACK_CANONICAL): Determine tininess based on rounding to
	normal precision if _FP_TININESS_AFTER_ROUNDING and unrounded
	value has largest subnormal exponent.
	* soft-fp/soft-fp.h [FP_NO_EXCEPTIONS]
	(_FP_TININESS_AFTER_ROUNDING): Undefine and redefine to 0.
	* sysdeps/powerpc/soft-fp/sfp-machine.h
	(_FP_TININESS_AFTER_ROUNDING): New macro.
	* sysdeps/sh/soft-fp/sfp-machine.h (_FP_TININESS_AFTER_ROUNDING):
	Likewise.
	* sysdeps/sparc/sparc32/soft-fp/sfp-machine.h
	(_FP_TININESS_AFTER_ROUNDING): Likewise.
	* sysdeps/sparc/sparc64/soft-fp/sfp-machine.h
	(_FP_TININESS_AFTER_ROUNDING): Likewise.

ports/ChangeLog.aarch64:
2014-02-03  Joseph Myers  <joseph@codesourcery.com>

	* sysdeps/aarch64/soft-fp/sfp-machine.h
	(_FP_TININESS_AFTER_ROUNDING): New macro.

ports/ChangeLog.alpha:
2014-02-03  Joseph Myers  <joseph@codesourcery.com>

	* sysdeps/alpha/soft-fp/sfp-machine.h
	(_FP_TININESS_AFTER_ROUNDING): New macro.

ports/ChangeLog.arm:
2014-02-03  Joseph Myers  <joseph@codesourcery.com>

	* sysdeps/arm/soft-fp/sfp-machine.h (_FP_TININESS_AFTER_ROUNDING):
	New macro.

ports/ChangeLog.mips:
2014-02-03  Joseph Myers  <joseph@codesourcery.com>

	* sysdeps/mips/mips64/soft-fp/sfp-machine.h
	(_FP_TININESS_AFTER_ROUNDING): New macro.
	* sysdeps/mips/soft-fp/sfp-machine.h
	(_FP_TININESS_AFTER_ROUNDING): Likewise.

ports/ChangeLog.tile:
2014-02-03  Joseph Myers  <joseph@codesourcery.com>

	* sysdeps/tile/sfp-machine.h (_FP_TININESS_AFTER_ROUNDING): New
	macro.

diff --git a/ports/sysdeps/aarch64/soft-fp/sfp-machine.h b/ports/sysdeps/aarch64/soft-fp/sfp-machine.h
index 9bb94e5..3e96995 100644
--- a/ports/sysdeps/aarch64/soft-fp/sfp-machine.h
+++ b/ports/sysdeps/aarch64/soft-fp/sfp-machine.h
@@ -60,6 +60,8 @@
 #define FP_EX_DIVZERO		FE_DIVBYZERO
 #define FP_EX_INEXACT		FE_INEXACT
 
+#define _FP_TININESS_AFTER_ROUNDING 0
+
 #define FP_INIT_ROUNDMODE			\
 do {						\
   _FPU_GETCW (_fcw);				\
diff --git a/ports/sysdeps/alpha/soft-fp/sfp-machine.h b/ports/sysdeps/alpha/soft-fp/sfp-machine.h
index cceccaf..e11a8dd 100644
--- a/ports/sysdeps/alpha/soft-fp/sfp-machine.h
+++ b/ports/sysdeps/alpha/soft-fp/sfp-machine.h
@@ -74,6 +74,8 @@
 #define FP_EX_DIVZERO		FE_DIVBYZERO
 #define FP_EX_INEXACT		FE_INEXACT
 
+#define _FP_TININESS_AFTER_ROUNDING 1
+
 #define FP_INIT_ROUNDMODE					\
 do {								\
   if (__builtin_expect (_round == 4, 0))			\
diff --git a/ports/sysdeps/arm/soft-fp/sfp-machine.h b/ports/sysdeps/arm/soft-fp/sfp-machine.h
index eba6e35..52a08b5 100644
--- a/ports/sysdeps/arm/soft-fp/sfp-machine.h
+++ b/ports/sysdeps/arm/soft-fp/sfp-machine.h
@@ -47,3 +47,5 @@
       }								\
     R##_c = FP_CLS_NAN;						\
   } while (0)
+
+#define _FP_TININESS_AFTER_ROUNDING 0
diff --git a/ports/sysdeps/mips/mips64/soft-fp/sfp-machine.h b/ports/sysdeps/mips/mips64/soft-fp/sfp-machine.h
index 5be5092..708afc7 100644
--- a/ports/sysdeps/mips/mips64/soft-fp/sfp-machine.h
+++ b/ports/sysdeps/mips/mips64/soft-fp/sfp-machine.h
@@ -77,6 +77,8 @@
 #define FP_EX_DIVZERO		FE_DIVBYZERO
 #define FP_EX_INEXACT		FE_INEXACT
 
+#define _FP_TININESS_AFTER_ROUNDING 1
+
 #ifdef __mips_hard_float
 #define FP_INIT_ROUNDMODE			\
 do {						\
diff --git a/ports/sysdeps/mips/soft-fp/sfp-machine.h b/ports/sysdeps/mips/soft-fp/sfp-machine.h
index fff3b3c..4e23aa8 100644
--- a/ports/sysdeps/mips/soft-fp/sfp-machine.h
+++ b/ports/sysdeps/mips/soft-fp/sfp-machine.h
@@ -64,3 +64,5 @@
 #define FP_EX_OVERFLOW          (1 << 2)
 #define FP_EX_UNDERFLOW         (1 << 1)
 #define FP_EX_INEXACT           (1 << 0)
+
+#define _FP_TININESS_AFTER_ROUNDING 1
diff --git a/ports/sysdeps/tile/sfp-machine.h b/ports/sysdeps/tile/sfp-machine.h
index ff8beef..7a1993e 100644
--- a/ports/sysdeps/tile/sfp-machine.h
+++ b/ports/sysdeps/tile/sfp-machine.h
@@ -95,3 +95,5 @@
       }								\
     R##_c = FP_CLS_NAN;						\
   } while (0)
+
+#define _FP_TININESS_AFTER_ROUNDING 0
diff --git a/soft-fp/op-common.h b/soft-fp/op-common.h
index e901981..6f8c1f3 100644
--- a/soft-fp/op-common.h
+++ b/soft-fp/op-common.h
@@ -32,7 +32,7 @@
 #define _FP_DECL(wc, X)				\
   _FP_I_TYPE X##_c __attribute__ ((unused));	\
   _FP_I_TYPE X##_s __attribute__ ((unused));	\
-  _FP_I_TYPE X##_e;				\
+  _FP_I_TYPE X##_e __attribute__ ((unused));	\
   _FP_FRAC_DECL_##wc (X)
 
 /* Test whether the qNaN bit denotes a signaling NaN.  */
@@ -191,8 +191,22 @@
 #define _FP_PACK_SEMIRAW(fs, wc, X)				\
   do								\
     {								\
+      int _FP_PACK_SEMIRAW_is_tiny				\
+	= X##_e == 0 && !_FP_FRAC_ZEROP_##wc (X);		\
+      if (_FP_TININESS_AFTER_ROUNDING				\
+	  && _FP_PACK_SEMIRAW_is_tiny)				\
+	{							\
+	  FP_DECL_##fs (_FP_PACK_SEMIRAW_T);			\
+	  _FP_FRAC_COPY_##wc (_FP_PACK_SEMIRAW_T, X);		\
+	  _FP_PACK_SEMIRAW_T##_s = X##_s;			\
+	  _FP_PACK_SEMIRAW_T##_e = X##_e;			\
+	  _FP_FRAC_SLL_##wc (_FP_PACK_SEMIRAW_T, 1);		\
+	  _FP_ROUND (wc, _FP_PACK_SEMIRAW_T);			\
+	  if (_FP_FRAC_OVERP_##wc (fs, _FP_PACK_SEMIRAW_T))	\
+	    _FP_PACK_SEMIRAW_is_tiny = 0;			\
+	}							\
       _FP_ROUND (wc, X);					\
-      if (X##_e == 0 && !_FP_FRAC_ZEROP_##wc (X))		\
+      if (_FP_PACK_SEMIRAW_is_tiny)				\
 	{							\
 	  if ((FP_CUR_EXCEPTIONS & FP_EX_INEXACT)		\
 	      || (FP_TRAPPING_EXCEPTIONS & FP_EX_UNDERFLOW))	\
@@ -279,6 +293,17 @@
 	  else								\
 	    {								\
 	      /* we've got a denormalized number */			\
+	      int _FP_PACK_CANONICAL_is_tiny = 1;			\
+	      if (_FP_TININESS_AFTER_ROUNDING && X##_e == 0)		\
+		{							\
+		  FP_DECL_##fs (_FP_PACK_CANONICAL_T);			\
+		  _FP_FRAC_COPY_##wc (_FP_PACK_CANONICAL_T, X);		\
+		  _FP_PACK_CANONICAL_T##_s = X##_s;			\
+		  _FP_PACK_CANONICAL_T##_e = X##_e;			\
+		  _FP_ROUND (wc, _FP_PACK_CANONICAL_T);			\
+		  if (_FP_FRAC_OVERP_##wc (fs, _FP_PACK_CANONICAL_T))	\
+		    _FP_PACK_CANONICAL_is_tiny = 0;			\
+		}							\
 	      X##_e = -X##_e + 1;					\
 	      if (X##_e <= _FP_WFRACBITS_##fs)				\
 		{							\
@@ -296,8 +321,10 @@
 		      X##_e = 0;					\
 		      _FP_FRAC_SRL_##wc (X, _FP_WORKBITS);		\
 		    }							\
-		  if ((FP_CUR_EXCEPTIONS & FP_EX_INEXACT)		\
-		      || (FP_TRAPPING_EXCEPTIONS & FP_EX_UNDERFLOW))	\
+		  if (_FP_PACK_CANONICAL_is_tiny			\
+		      && ((FP_CUR_EXCEPTIONS & FP_EX_INEXACT)		\
+			  || (FP_TRAPPING_EXCEPTIONS			\
+			      & FP_EX_UNDERFLOW)))			\
 		    FP_SET_EXCEPTION (FP_EX_UNDERFLOW);			\
 		}							\
 	      else							\
diff --git a/soft-fp/soft-fp.h b/soft-fp/soft-fp.h
index c8a9894..8d0efa5 100644
--- a/soft-fp/soft-fp.h
+++ b/soft-fp/soft-fp.h
@@ -161,6 +161,9 @@
 # undef FP_ROUNDMODE
 # define FP_ROUNDMODE FP_RND_ZERO
 
+# undef _FP_TININESS_AFTER_ROUNDING
+# define _FP_TININESS_AFTER_ROUNDING 0
+
 #endif
 
 #define _FP_ROUND_NEAREST(wc, X)				\
diff --git a/sysdeps/powerpc/soft-fp/sfp-machine.h b/sysdeps/powerpc/soft-fp/sfp-machine.h
index 35a38b0..d92a90e 100644
--- a/sysdeps/powerpc/soft-fp/sfp-machine.h
+++ b/sysdeps/powerpc/soft-fp/sfp-machine.h
@@ -41,6 +41,8 @@
     R##_c = FP_CLS_NAN;						\
   } while (0)
 
+#define _FP_TININESS_AFTER_ROUNDING 0
+
 #if defined __NO_FPRS__ && !defined _SOFT_FLOAT
 
 /* Exception flags.  We use the bit positions of the appropriate bits
diff --git a/sysdeps/sh/soft-fp/sfp-machine.h b/sysdeps/sh/soft-fp/sfp-machine.h
index 9b90748..81474e8 100644
--- a/sysdeps/sh/soft-fp/sfp-machine.h
+++ b/sysdeps/sh/soft-fp/sfp-machine.h
@@ -53,3 +53,5 @@
 #define FP_EX_OVERFLOW          (1 << 4)
 #define FP_EX_UNDERFLOW         (1 << 3)
 #define FP_EX_INEXACT           (1 << 2)
+
+#define _FP_TININESS_AFTER_ROUNDING 1
diff --git a/sysdeps/sparc/sparc32/soft-fp/sfp-machine.h b/sysdeps/sparc/sparc32/soft-fp/sfp-machine.h
index 025b3ab..b6baa81 100644
--- a/sysdeps/sparc/sparc32/soft-fp/sfp-machine.h
+++ b/sysdeps/sparc/sparc32/soft-fp/sfp-machine.h
@@ -185,6 +185,8 @@
 #define FP_EX_DIVZERO		(1 << 1)
 #define FP_EX_INEXACT		(1 << 0)
 
+#define _FP_TININESS_AFTER_ROUNDING 0
+
 #define _FP_DECL_EX \
   fpu_control_t _fcw __attribute__ ((unused)) = (FP_RND_NEAREST << 30)
 
diff --git a/sysdeps/sparc/sparc64/soft-fp/sfp-machine.h b/sysdeps/sparc/sparc64/soft-fp/sfp-machine.h
index 9a0384b..80c1ac5 100644
--- a/sysdeps/sparc/sparc64/soft-fp/sfp-machine.h
+++ b/sysdeps/sparc/sparc64/soft-fp/sfp-machine.h
@@ -93,6 +93,8 @@ do {								\
 #define FP_EX_DIVZERO		(1 << 1)
 #define FP_EX_INEXACT		(1 << 0)
 
+#define _FP_TININESS_AFTER_ROUNDING 0
+
 #define _FP_DECL_EX \
   fpu_control_t _fcw __attribute__ ((unused)) = (FP_RND_NEAREST << 30)
 

-- 
Joseph S. Myers
joseph@codesourcery.com


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