This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
Fix missing exceptions from exp (bugs 13787, 13922, 14036)
- From: "Joseph S. Myers" <joseph at codesourcery dot com>
- To: libc-alpha at sourceware dot org
- Date: Sat, 5 May 2012 17:20:59 +0000 (UTC)
- Subject: Fix missing exceptions from exp (bugs 13787, 13922, 14036)
There are various bugs for missing overflow and underflow exceptions
on exp-family functions, resulting from the wrappers checking for
overflow and underflow before calling the functions such as
__ieee754_exp, and in the overflow/underflow cases then calling
__kernel_standard so setting errno but missing out on the exceptions.
I propose this patch to fix these bugs by using the approach of some
other wrappers, checking for overflow and underflow based on the
results after calling __ieee754_exp. This in turn requires changes to
the x86/x86_64 code (on top of my previous patch
<http://sourceware.org/ml/libc-alpha/2012-05/msg00184.html> to use .S
files for those) to avoid spurious overflows in internal calculations
for very large (positive or negative) exponents. The long double
wrappers not changed already check for overflow/underflow after
calling __ieee754_expl, so should not need any changes.
Tested x86_64 and x86. The underflow part of bug 14036 isn't fixed by
this patch but hopefully Andreas's patch to use -frounding-math will,
together with this patch, fix that problem; if not, further
investigation will be needed.
2012-05-05 Joseph Myers <joseph@codesourcery.com>
[BZ #13787]
[BZ #13922]
[BZ #14036]
* sysdeps/i386/fpu/e_expl.S (csat): New constant.
(__ieee754_expl): Allow for and saturate large arguments.
* sysdeps/ieee754/dbl-64/w_exp.c (o_threshold): Remove variable.
(u_threshold): Likewise.
(__exp): Call __ieee754_exp before checking for overflow and
underflow.
* sysdeps/ieee754/flt-32/w_expf.c (o_threshold): Remove variable.
(u_threshold): Likewise.
(__expf): Call __ieee754_expf before checking for overflow and
underflow.
* sysdeps/ieee754/ldbl-96/w_expl.c (o_threshold): Remove variable.
(u_threshold): Likewise.
(__expl): Call __ieee754_expl before checking for overflow and
underflow.
* sysdeps/x86_64/fpu/e_expl.S (csat): New constant.
(__ieee754_expl): Allow for and saturate large arguments.
* math/libm-test.inc (exp_test): Add another test. Do not allow
missing overflow exception on overflow.
(expm1_test): Do not allow missing overflow exception on overflow.
diff --git a/math/libm-test.inc b/math/libm-test.inc
index ceb7d35..59192ed 100644
--- a/math/libm-test.inc
+++ b/math/libm-test.inc
@@ -3325,8 +3325,11 @@ exp_test (void)
TEST_f_f (exp, 1000.0L, 0.197007111401704699388887935224332313e435L);
#endif
- /* Bug 13922: OVERFLOW exception may be missing. */
- TEST_f_f (exp, max_value, plus_infty, OVERFLOW_EXCEPTION_OK);
+#if !(defined TEST_LDOUBLE && LDBL_MAX_EXP > 1024)
+ TEST_f_f (exp, 710, plus_infty, OVERFLOW_EXCEPTION);
+#endif
+ TEST_f_f (exp, 1e5, plus_infty, OVERFLOW_EXCEPTION);
+ TEST_f_f (exp, max_value, plus_infty, OVERFLOW_EXCEPTION);
TEST_f_f (exp, -max_value, 0);
END (exp);
@@ -3547,11 +3550,9 @@ expm1_test (void)
#endif
errno = 0;
- /* Bug 13787: OVERFLOW exception may be missing. */
- TEST_f_f (expm1, 100000.0, plus_infty, OVERFLOW_EXCEPTION_OK);
+ TEST_f_f (expm1, 100000.0, plus_infty, OVERFLOW_EXCEPTION);
check_int ("errno for expm1(large) == ERANGE", errno, ERANGE, 0, 0, 0);
- /* Bug 13787: OVERFLOW exception may be missing. */
- TEST_f_f (expm1, max_value, plus_infty, OVERFLOW_EXCEPTION_OK);
+ TEST_f_f (expm1, max_value, plus_infty, OVERFLOW_EXCEPTION);
#ifndef TEST_LDOUBLE /* Bug 13923. */
TEST_f_f (expm1, -max_value, -1);
#endif
diff --git a/sysdeps/i386/fpu/e_expl.S b/sysdeps/i386/fpu/e_expl.S
index a492c29..45c4d07 100644
--- a/sysdeps/i386/fpu/e_expl.S
+++ b/sysdeps/i386/fpu/e_expl.S
@@ -35,6 +35,10 @@ c0: .byte 0, 0, 0, 0, 0, 0, 0xaa, 0xb8, 0xff, 0x3f
c1: .byte 0x20, 0xfa, 0xee, 0xc2, 0x5f, 0x70, 0xa5, 0xec, 0xed, 0x3f
.byte 0, 0, 0, 0, 0, 0
ASM_SIZE_DIRECTIVE(c1)
+ ASM_TYPE_DIRECTIVE(csat,@object)
+csat: .byte 0, 0, 0, 0, 0, 0, 0, 0x80, 0x0e, 0x40
+ .byte 0, 0, 0, 0, 0, 0
+ ASM_SIZE_DIRECTIVE(csat)
#ifdef PIC
# define MO(op) op##@GOTOFF(%ecx)
@@ -53,12 +57,25 @@ ENTRY(__ieee754_expl)
#ifdef PIC
LOAD_PIC_REG (cx)
#endif
+ movzwl 4+8(%esp), %eax
+ andl $0x7fff, %eax
+ cmpl $0x400d, %eax
+ jle 3f
+ /* Overflow, underflow or infinity or NaN as argument. */
fstsw %ax
movb $0x45, %dh
andb %ah, %dh
cmpb $0x05, %dh
je 1f /* Is +-Inf, jump. */
- fldl2e /* 1 log2(e) */
+ cmpb $0x01, %dh
+ je 2f /* Is +-NaN, jump. */
+ /* Overflow or underflow; saturate. */
+ fstp %st
+ fldt MO(csat)
+ andb $2, %ah
+ jz 3f
+ fchs
+3: fldl2e /* 1 log2(e) */
fmul %st(1), %st /* 1 x log2(e) */
frndint /* 1 i */
fld %st(1) /* 2 x */
diff --git a/sysdeps/ieee754/dbl-64/w_exp.c b/sysdeps/ieee754/dbl-64/w_exp.c
index aa8ff76..14328a7 100644
--- a/sysdeps/ieee754/dbl-64/w_exp.c
+++ b/sysdeps/ieee754/dbl-64/w_exp.c
@@ -19,27 +19,16 @@
#include <math.h>
#include <math_private.h>
-static const double
-o_threshold= 7.09782712893383973096e+02, /* 0x40862E42, 0xFEFA39EF */
-u_threshold= -7.45133219101941108420e+02; /* 0xc0874910, 0xD52D3051 */
-
-
/* wrapper exp */
double
__exp (double x)
{
- if (__builtin_expect (isgreater (x, o_threshold), 0))
- {
- if (_LIB_VERSION != _IEEE_)
- return __kernel_standard (x, x, 6);
- }
- else if (__builtin_expect (isless (x, u_threshold), 0))
- {
- if (_LIB_VERSION != _IEEE_)
- return __kernel_standard (x, x, 7);
- }
+ double z = __ieee754_exp (x);
+ if (__builtin_expect (!__finite (z) || z == 0, 0)
+ && __finite (x) && _LIB_VERSION != _IEEE_)
+ return __kernel_standard (x, x, 6 + !!__signbit (x));
- return __ieee754_exp (x);
+ return z;
}
hidden_def (__exp)
weak_alias (__exp, exp)
diff --git a/sysdeps/ieee754/flt-32/w_expf.c b/sysdeps/ieee754/flt-32/w_expf.c
index bc3b2f6..bfef9e4 100644
--- a/sysdeps/ieee754/flt-32/w_expf.c
+++ b/sysdeps/ieee754/flt-32/w_expf.c
@@ -19,27 +19,16 @@
#include <math.h>
#include <math_private.h>
-static const float
-o_threshold= 8.8722831726e+01, /* 0x42b17217 */
-u_threshold= -1.0397208405e+02; /* 0xc2cff1b5 */
-
-
/* wrapper expf */
float
__expf (float x)
{
- if (__builtin_expect (isgreater (x, o_threshold), 0))
- {
- if (_LIB_VERSION != _IEEE_)
- return __kernel_standard_f (x, x, 106);
- }
- else if (__builtin_expect (isless (x, u_threshold), 0))
- {
- if (_LIB_VERSION != _IEEE_)
- return __kernel_standard_f (x, x, 107);
- }
+ float z = __ieee754_expf (x);
+ if (__builtin_expect (!__finitef (z) || z == 0, 0)
+ && __finitef (x) && _LIB_VERSION != _IEEE_)
+ return __kernel_standard_f (x, x, 106 + !!__signbitf (x));
- return __ieee754_expf (x);
+ return z;
}
hidden_def (__expf)
weak_alias (__expf, expf)
diff --git a/sysdeps/ieee754/ldbl-96/w_expl.c b/sysdeps/ieee754/ldbl-96/w_expl.c
index 55c6846..79b10c5 100644
--- a/sysdeps/ieee754/ldbl-96/w_expl.c
+++ b/sysdeps/ieee754/ldbl-96/w_expl.c
@@ -19,29 +19,16 @@
#include <math.h>
#include <math_private.h>
-static const long double
-o_threshold= 1.135652340629414394949193107797076489134e4,
- /* 0x400C, 0xB17217F7, 0xD1CF79AC */
-u_threshold= -1.140019167866942050398521670162263001513e4;
- /* 0x400C, 0xB220C447, 0x69C201E8 */
-
-
/* wrapper expl */
long double
__expl (long double x)
{
- if (__builtin_expect (isgreater (x, o_threshold), 0))
- {
- if (_LIB_VERSION != _IEEE_)
- return __kernel_standard_l (x, x, 206);
- }
- else if (__builtin_expect (isless (x, u_threshold), 0))
- {
- if (_LIB_VERSION != _IEEE_)
- return __kernel_standard_l (x, x, 207);
- }
+ long double z = __ieee754_expl (x);
+ if (__builtin_expect (!__finitel (z) || z == 0, 0)
+ && __finitel (x) && _LIB_VERSION != _IEEE_)
+ return __kernel_standard_l (x, x, 206 + !!__signbitl (x));
- return __ieee754_expl (x);
+ return z;
}
hidden_def (__expl)
weak_alias (__expl, expl)
diff --git a/sysdeps/x86_64/fpu/e_expl.S b/sysdeps/x86_64/fpu/e_expl.S
index c2d1d40..d497b28 100644
--- a/sysdeps/x86_64/fpu/e_expl.S
+++ b/sysdeps/x86_64/fpu/e_expl.S
@@ -35,6 +35,10 @@ c0: .byte 0, 0, 0, 0, 0, 0, 0xaa, 0xb8, 0xff, 0x3f
c1: .byte 0x20, 0xfa, 0xee, 0xc2, 0x5f, 0x70, 0xa5, 0xec, 0xed, 0x3f
.byte 0, 0, 0, 0, 0, 0
ASM_SIZE_DIRECTIVE(c1)
+ ASM_TYPE_DIRECTIVE(csat,@object)
+csat: .byte 0, 0, 0, 0, 0, 0, 0, 0x80, 0x0e, 0x40
+ .byte 0, 0, 0, 0, 0, 0
+ ASM_SIZE_DIRECTIVE(csat)
#ifdef PIC
# define MO(op) op##(%rip)
@@ -50,12 +54,25 @@ ENTRY(__ieee754_expl)
For the i686 the code can be written better.
-- drepper@cygnus.com. */
fxam /* Is NaN or +-Inf? */
+ movzwl 8+8(%rsp), %eax
+ andl $0x7fff, %eax
+ cmpl $0x400d, %eax
+ jle 3f
+ /* Overflow, underflow or infinity or NaN as argument. */
fstsw %ax
movb $0x45, %dh
andb %ah, %dh
cmpb $0x05, %dh
je 1f /* Is +-Inf, jump. */
- fldl2e /* 1 log2(e) */
+ cmpb $0x01, %dh
+ je 2f /* Is +-NaN, jump. */
+ /* Overflow or underflow; saturate. */
+ fstp %st
+ fldt MO(csat)
+ andb $2, %ah
+ jz 3f
+ fchs
+3: fldl2e /* 1 log2(e) */
fmul %st(1), %st /* 1 x log2(e) */
frndint /* 1 i */
fld %st(1) /* 2 x */
--
Joseph S. Myers
joseph@codesourcery.com