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 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 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.)

	* 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/aarch64/soft-fp/sfp-machine.h
	(_FP_TININESS_AFTER_ROUNDING): New macro.
	* sysdeps/alpha/soft-fp/sfp-machine.h
	(_FP_TININESS_AFTER_ROUNDING): Likewise.
	* sysdeps/arm/soft-fp/sfp-machine.h (_FP_TININESS_AFTER_ROUNDING):
	Likewise.
	* sysdeps/mips/mips64/soft-fp/sfp-machine.h
	(_FP_TININESS_AFTER_ROUNDING): Likewise.
	* sysdeps/mips/soft-fp/sfp-machine.h
	(_FP_TININESS_AFTER_ROUNDING): Likewise.
	* sysdeps/powerpc/soft-fp/sfp-machine.h
	(_FP_TININESS_AFTER_ROUNDING): Likewise.
	* 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.
	* sysdeps/tile/sfp-machine.h (_FP_TININESS_AFTER_ROUNDING):
	Likewise.
This commit is contained in:
Joseph Myers 2014-02-12 18:27:12 +00:00
parent fbfdf9cb03
commit ace614b8a5
13 changed files with 87 additions and 4 deletions

View File

@ -1,3 +1,36 @@
2014-02-12 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/aarch64/soft-fp/sfp-machine.h
(_FP_TININESS_AFTER_ROUNDING): New macro.
* sysdeps/alpha/soft-fp/sfp-machine.h
(_FP_TININESS_AFTER_ROUNDING): Likewise.
* sysdeps/arm/soft-fp/sfp-machine.h (_FP_TININESS_AFTER_ROUNDING):
Likewise.
* sysdeps/mips/mips64/soft-fp/sfp-machine.h
(_FP_TININESS_AFTER_ROUNDING): Likewise.
* sysdeps/mips/soft-fp/sfp-machine.h
(_FP_TININESS_AFTER_ROUNDING): Likewise.
* sysdeps/powerpc/soft-fp/sfp-machine.h
(_FP_TININESS_AFTER_ROUNDING): Likewise.
* 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.
* sysdeps/tile/sfp-machine.h (_FP_TININESS_AFTER_ROUNDING):
Likewise.
2014-02-12 Dylan Alex Simon <dylan@dylex.net> 2014-02-12 Dylan Alex Simon <dylan@dylex.net>
[BZ #16545] [BZ #16545]

View File

@ -32,7 +32,7 @@
#define _FP_DECL(wc, X) \ #define _FP_DECL(wc, X) \
_FP_I_TYPE X##_c __attribute__ ((unused)); \ _FP_I_TYPE X##_c __attribute__ ((unused)); \
_FP_I_TYPE X##_s __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) _FP_FRAC_DECL_##wc (X)
/* Test whether the qNaN bit denotes a signaling NaN. */ /* Test whether the qNaN bit denotes a signaling NaN. */
@ -191,8 +191,22 @@
#define _FP_PACK_SEMIRAW(fs, wc, X) \ #define _FP_PACK_SEMIRAW(fs, wc, X) \
do \ 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); \ _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) \ if ((FP_CUR_EXCEPTIONS & FP_EX_INEXACT) \
|| (FP_TRAPPING_EXCEPTIONS & FP_EX_UNDERFLOW)) \ || (FP_TRAPPING_EXCEPTIONS & FP_EX_UNDERFLOW)) \
@ -279,6 +293,17 @@
else \ else \
{ \ { \
/* we've got a denormalized number */ \ /* 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; \ X##_e = -X##_e + 1; \
if (X##_e <= _FP_WFRACBITS_##fs) \ if (X##_e <= _FP_WFRACBITS_##fs) \
{ \ { \
@ -296,8 +321,10 @@
X##_e = 0; \ X##_e = 0; \
_FP_FRAC_SRL_##wc (X, _FP_WORKBITS); \ _FP_FRAC_SRL_##wc (X, _FP_WORKBITS); \
} \ } \
if ((FP_CUR_EXCEPTIONS & FP_EX_INEXACT) \ if (_FP_PACK_CANONICAL_is_tiny \
|| (FP_TRAPPING_EXCEPTIONS & FP_EX_UNDERFLOW)) \ && ((FP_CUR_EXCEPTIONS & FP_EX_INEXACT) \
|| (FP_TRAPPING_EXCEPTIONS \
& FP_EX_UNDERFLOW))) \
FP_SET_EXCEPTION (FP_EX_UNDERFLOW); \ FP_SET_EXCEPTION (FP_EX_UNDERFLOW); \
} \ } \
else \ else \

View File

@ -161,6 +161,9 @@
# undef FP_ROUNDMODE # undef FP_ROUNDMODE
# define FP_ROUNDMODE FP_RND_ZERO # define FP_ROUNDMODE FP_RND_ZERO
# undef _FP_TININESS_AFTER_ROUNDING
# define _FP_TININESS_AFTER_ROUNDING 0
#endif #endif
#define _FP_ROUND_NEAREST(wc, X) \ #define _FP_ROUND_NEAREST(wc, X) \

View File

@ -60,6 +60,8 @@
#define FP_EX_DIVZERO FE_DIVBYZERO #define FP_EX_DIVZERO FE_DIVBYZERO
#define FP_EX_INEXACT FE_INEXACT #define FP_EX_INEXACT FE_INEXACT
#define _FP_TININESS_AFTER_ROUNDING 0
#define FP_INIT_ROUNDMODE \ #define FP_INIT_ROUNDMODE \
do { \ do { \
_FPU_GETCW (_fcw); \ _FPU_GETCW (_fcw); \

View File

@ -74,6 +74,8 @@
#define FP_EX_DIVZERO FE_DIVBYZERO #define FP_EX_DIVZERO FE_DIVBYZERO
#define FP_EX_INEXACT FE_INEXACT #define FP_EX_INEXACT FE_INEXACT
#define _FP_TININESS_AFTER_ROUNDING 1
#define FP_INIT_ROUNDMODE \ #define FP_INIT_ROUNDMODE \
do { \ do { \
if (__builtin_expect (_round == 4, 0)) \ if (__builtin_expect (_round == 4, 0)) \

View File

@ -47,3 +47,5 @@
} \ } \
R##_c = FP_CLS_NAN; \ R##_c = FP_CLS_NAN; \
} while (0) } while (0)
#define _FP_TININESS_AFTER_ROUNDING 0

View File

@ -77,6 +77,8 @@
#define FP_EX_DIVZERO FE_DIVBYZERO #define FP_EX_DIVZERO FE_DIVBYZERO
#define FP_EX_INEXACT FE_INEXACT #define FP_EX_INEXACT FE_INEXACT
#define _FP_TININESS_AFTER_ROUNDING 1
#ifdef __mips_hard_float #ifdef __mips_hard_float
#define FP_INIT_ROUNDMODE \ #define FP_INIT_ROUNDMODE \
do { \ do { \

View File

@ -64,3 +64,5 @@
#define FP_EX_OVERFLOW (1 << 2) #define FP_EX_OVERFLOW (1 << 2)
#define FP_EX_UNDERFLOW (1 << 1) #define FP_EX_UNDERFLOW (1 << 1)
#define FP_EX_INEXACT (1 << 0) #define FP_EX_INEXACT (1 << 0)
#define _FP_TININESS_AFTER_ROUNDING 1

View File

@ -41,6 +41,8 @@
R##_c = FP_CLS_NAN; \ R##_c = FP_CLS_NAN; \
} while (0) } while (0)
#define _FP_TININESS_AFTER_ROUNDING 0
#if defined __NO_FPRS__ && !defined _SOFT_FLOAT #if defined __NO_FPRS__ && !defined _SOFT_FLOAT
/* Exception flags. We use the bit positions of the appropriate bits /* Exception flags. We use the bit positions of the appropriate bits

View File

@ -53,3 +53,5 @@
#define FP_EX_OVERFLOW (1 << 4) #define FP_EX_OVERFLOW (1 << 4)
#define FP_EX_UNDERFLOW (1 << 3) #define FP_EX_UNDERFLOW (1 << 3)
#define FP_EX_INEXACT (1 << 2) #define FP_EX_INEXACT (1 << 2)
#define _FP_TININESS_AFTER_ROUNDING 1

View File

@ -185,6 +185,8 @@
#define FP_EX_DIVZERO (1 << 1) #define FP_EX_DIVZERO (1 << 1)
#define FP_EX_INEXACT (1 << 0) #define FP_EX_INEXACT (1 << 0)
#define _FP_TININESS_AFTER_ROUNDING 0
#define _FP_DECL_EX \ #define _FP_DECL_EX \
fpu_control_t _fcw __attribute__ ((unused)) = (FP_RND_NEAREST << 30) fpu_control_t _fcw __attribute__ ((unused)) = (FP_RND_NEAREST << 30)

View File

@ -93,6 +93,8 @@ do { \
#define FP_EX_DIVZERO (1 << 1) #define FP_EX_DIVZERO (1 << 1)
#define FP_EX_INEXACT (1 << 0) #define FP_EX_INEXACT (1 << 0)
#define _FP_TININESS_AFTER_ROUNDING 0
#define _FP_DECL_EX \ #define _FP_DECL_EX \
fpu_control_t _fcw __attribute__ ((unused)) = (FP_RND_NEAREST << 30) fpu_control_t _fcw __attribute__ ((unused)) = (FP_RND_NEAREST << 30)

View File

@ -95,3 +95,5 @@
} \ } \
R##_c = FP_CLS_NAN; \ R##_c = FP_CLS_NAN; \
} while (0) } while (0)
#define _FP_TININESS_AFTER_ROUNDING 0