This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
[PATCH] Fix underflow and inexact signalling in soft-fp whenpacking.
- From: David Miller <davem at davemloft dot net>
- To: libc-alpha at sourceware dot org
- Cc: joseph at codesourcery dot com
- Date: Fri, 25 May 2012 18:09:16 -0400 (EDT)
- Subject: [PATCH] Fix underflow and inexact signalling in soft-fp whenpacking.
This fixes the long double math testsuite regressions that started
showing up on Sparc with Joseph's recent change to check underflow.
The corresponding changes needed in glibc-ports for powerpc/nofp,
mips, and alpha should be pretty straightforward.
In the main glibc tree, sparc is the only consumer of this code.
Ok to commit?
* soft-fp/op-common.h (_FP_PACK_CANONICAL): Only set underflow if
the underflow exception is enabled and the non-zero result is
tiny, or the non-zero result is tiny and there will be a loss of
accuracy. Set inexact if overflow is detected after rounding, but
not if it is detected before.
* soft-fp/soft-fp.h (FP_CUR_EXCEPTIONS): Define.
(FP_TRAPPING_EXCEPTIONS): Provide default define.
* sysdeps/sparc/sparc32/soft-fp/sfp-machine.h (_FP_DECL_EX):
Initialize _fcw to zero.
(FP_TRAPPING_EXCEPTIONS): Define.
(FP_HANDLE_EXCEPTIONS): Add dummy use of _fcw.
* sysdeps/sparc/sparc64/soft-fp/sfp-machine.h (_FP_DECL_EX):
Initialize _fcw to zero.
(FP_TRAPPING_EXCEPTIONS): Define.
(FP_HANDLE_EXCEPTIONS): Add dummy use of _fcw.
diff --git a/soft-fp/op-common.h b/soft-fp/op-common.h
index b70026f..4b0fd6c 100644
--- a/soft-fp/op-common.h
+++ b/soft-fp/op-common.h
@@ -220,7 +220,6 @@ do { \
if (X##_e <= _FP_WFRACBITS_##fs) \
{ \
_FP_FRAC_SRS_##wc(X, X##_e, _FP_WFRACBITS_##fs); \
- _FP_ROUND(wc, X); \
if (_FP_FRAC_HIGH_##fs(X) \
& (_FP_OVERFLOW_##fs >> 1)) \
{ \
@@ -229,10 +228,23 @@ do { \
} \
else \
{ \
- X##_e = 0; \
- _FP_FRAC_SRL_##wc(X, _FP_WORKBITS); \
- FP_SET_EXCEPTION(FP_EX_UNDERFLOW); \
+ _FP_ROUND(wc, X); \
+ if (_FP_FRAC_HIGH_##fs(X) \
+ & (_FP_OVERFLOW_##fs >> 1)) \
+ { \
+ X##_e = 1; \
+ _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc); \
+ FP_SET_EXCEPTION(FP_EX_INEXACT); \
+ } \
+ else \
+ { \
+ X##_e = 0; \
+ _FP_FRAC_SRL_##wc(X, _FP_WORKBITS); \
+ } \
} \
+ if ((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 46cb1cf..750c7fe 100644
--- a/soft-fp/soft-fp.h
+++ b/soft-fp/soft-fp.h
@@ -128,6 +128,13 @@
#define FP_CLEAR_EXCEPTIONS \
_fex = 0
+#define FP_CUR_EXCEPTIONS \
+ (_fex)
+
+#ifndef FP_TRAPPING_EXCEPTIONS
+#define FP_TRAPPING_EXCEPTIONS 0
+#endif
+
#define _FP_ROUND_NEAREST(wc, X) \
do { \
if ((_FP_FRAC_LOW_##wc(X) & 15) != _FP_WORK_ROUND) \
diff --git a/sysdeps/sparc/sparc32/soft-fp/sfp-machine.h b/sysdeps/sparc/sparc32/soft-fp/sfp-machine.h
index 8cdc7c2..fb8c723 100644
--- a/sysdeps/sparc/sparc32/soft-fp/sfp-machine.h
+++ b/sysdeps/sparc/sparc32/soft-fp/sfp-machine.h
@@ -184,18 +184,21 @@
#define FP_EX_DIVZERO (1 << 1)
#define FP_EX_INEXACT (1 << 0)
-#define _FP_DECL_EX fpu_control_t _fcw
+#define _FP_DECL_EX fpu_control_t _fcw = 0
#define FP_INIT_ROUNDMODE \
do { \
_FPU_GETCW(_fcw); \
} while (0)
+#define FP_TRAPPING_EXCEPTIONS ((_fcw >> 23) & 0x1f)
+
/* Simulate exceptions using double arithmetics. */
extern double ___Q_simulate_exceptions(int exc);
#define FP_HANDLE_EXCEPTIONS \
do { \
+ (void) (_fcw); \
if (!_fex) \
{ \
/* This is the common case, so we do it inline. \
diff --git a/sysdeps/sparc/sparc64/soft-fp/sfp-machine.h b/sysdeps/sparc/sparc64/soft-fp/sfp-machine.h
index 7ec804d..1f10dbb 100644
--- a/sysdeps/sparc/sparc64/soft-fp/sfp-machine.h
+++ b/sysdeps/sparc/sparc64/soft-fp/sfp-machine.h
@@ -92,13 +92,14 @@ do { \
#define FP_EX_DIVZERO (1 << 1)
#define FP_EX_INEXACT (1 << 0)
-#define _FP_DECL_EX fpu_control_t _fcw
+#define _FP_DECL_EX fpu_control_t _fcw = 0
#define FP_INIT_ROUNDMODE \
do { \
_FPU_GETCW(_fcw); \
} while (0)
+#define FP_TRAPPING_EXCEPTIONS ((_fcw >> 23) & 0x1f)
#define FP_INHIBIT_RESULTS ((_fcw >> 23) & _fex)
/* Simulate exceptions using double arithmetics. */
@@ -106,6 +107,7 @@ extern double __Qp_handle_exceptions(int exc);
#define FP_HANDLE_EXCEPTIONS \
do { \
+ (void) (_fcw); \
if (!_fex) \
{ \
/* This is the common case, so we do it inline. \