aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog9
-rw-r--r--math/libm-test.inc54
-rw-r--r--sysdeps/i386/fpu/e_powl.S29
-rw-r--r--sysdeps/x86_64/fpu/e_powl.S27
4 files changed, 109 insertions, 10 deletions
diff --git a/ChangeLog b/ChangeLog
index 9c0aaa6..ab723eb 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2016-12-06 Joseph Myers <joseph@codesourcery.com>
+
+ [BZ #20916]
+ * sysdeps/i386/fpu/e_powl.S (__ieee754_powl): Do not return 1 for
+ arguments (sNaN, 0) or (1, sNaN). Do arithmetic on NaN arguments
+ to compute result.
+ * sysdeps/x86_64/fpu/e_powl.S (__ieee754_powl): Likewise.
+ * math/libm-test.inc (pow_test_data): Add tests of sNaN arguments.
+
2016-12-05 Torvald Riegel <triegel@redhat.com>
* include/atomic.h (__atomic_check_size_ls): New.
diff --git a/math/libm-test.inc b/math/libm-test.inc
index 85df9de..9123dcf 100644
--- a/math/libm-test.inc
+++ b/math/libm-test.inc
@@ -11090,6 +11090,10 @@ static const struct test_ff_f_data pow_test_data[] =
TEST_ff_f (pow, -qnan_value, 0, 1, ERRNO_UNCHANGED|NO_TEST_MATHVEC),
TEST_ff_f (pow, qnan_value, minus_zero, 1, ERRNO_UNCHANGED|NO_TEST_MATHVEC),
TEST_ff_f (pow, -qnan_value, minus_zero, 1, ERRNO_UNCHANGED|NO_TEST_MATHVEC),
+ TEST_ff_f (pow, snan_value, 0, qnan_value, INVALID_EXCEPTION|NO_TEST_MATHVEC),
+ TEST_ff_f (pow, -snan_value, 0, qnan_value, INVALID_EXCEPTION|NO_TEST_MATHVEC),
+ TEST_ff_f (pow, snan_value, minus_zero, qnan_value, INVALID_EXCEPTION|NO_TEST_MATHVEC),
+ TEST_ff_f (pow, -snan_value, minus_zero, qnan_value, INVALID_EXCEPTION|NO_TEST_MATHVEC),
TEST_ff_f (pow, 1.1L, plus_infty, plus_infty, ERRNO_UNCHANGED|NO_TEST_INLINE),
TEST_ff_f (pow, plus_infty, plus_infty, plus_infty, ERRNO_UNCHANGED|NO_TEST_INLINE),
@@ -11151,18 +11155,40 @@ static const struct test_ff_f_data pow_test_data[] =
TEST_ff_f (pow, qnan_value, -qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
TEST_ff_f (pow, -qnan_value, qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
TEST_ff_f (pow, -qnan_value, -qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+ TEST_ff_f (pow, qnan_value, snan_value, qnan_value, INVALID_EXCEPTION),
+ TEST_ff_f (pow, qnan_value, -snan_value, qnan_value, INVALID_EXCEPTION),
+ TEST_ff_f (pow, -qnan_value, snan_value, qnan_value, INVALID_EXCEPTION),
+ TEST_ff_f (pow, -qnan_value, -snan_value, qnan_value, INVALID_EXCEPTION),
+ TEST_ff_f (pow, snan_value, qnan_value, qnan_value, INVALID_EXCEPTION),
+ TEST_ff_f (pow, snan_value, -qnan_value, qnan_value, INVALID_EXCEPTION),
+ TEST_ff_f (pow, -snan_value, qnan_value, qnan_value, INVALID_EXCEPTION),
+ TEST_ff_f (pow, -snan_value, -qnan_value, qnan_value, INVALID_EXCEPTION),
+ TEST_ff_f (pow, snan_value, snan_value, qnan_value, INVALID_EXCEPTION),
+ TEST_ff_f (pow, snan_value, -snan_value, qnan_value, INVALID_EXCEPTION),
+ TEST_ff_f (pow, -snan_value, snan_value, qnan_value, INVALID_EXCEPTION),
+ TEST_ff_f (pow, -snan_value, -snan_value, qnan_value, INVALID_EXCEPTION),
TEST_ff_f (pow, 0, qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
TEST_ff_f (pow, 0, -qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+ TEST_ff_f (pow, 0, snan_value, qnan_value, INVALID_EXCEPTION),
+ TEST_ff_f (pow, 0, -snan_value, qnan_value, INVALID_EXCEPTION),
TEST_ff_f (pow, 1, qnan_value, 1, ERRNO_UNCHANGED),
TEST_ff_f (pow, 1, -qnan_value, 1, ERRNO_UNCHANGED),
+ TEST_ff_f (pow, 1, snan_value, qnan_value, INVALID_EXCEPTION|NO_TEST_MATHVEC),
+ TEST_ff_f (pow, 1, -snan_value, qnan_value, INVALID_EXCEPTION|NO_TEST_MATHVEC),
TEST_ff_f (pow, -1, qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
TEST_ff_f (pow, -1, -qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+ TEST_ff_f (pow, -1, snan_value, qnan_value, INVALID_EXCEPTION),
+ TEST_ff_f (pow, -1, -snan_value, qnan_value, INVALID_EXCEPTION),
TEST_ff_f (pow, qnan_value, 1, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
TEST_ff_f (pow, -qnan_value, 1, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+ TEST_ff_f (pow, snan_value, 1, qnan_value, INVALID_EXCEPTION),
+ TEST_ff_f (pow, -snan_value, 1, qnan_value, INVALID_EXCEPTION),
TEST_ff_f (pow, qnan_value, -1, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
TEST_ff_f (pow, -qnan_value, -1, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+ TEST_ff_f (pow, snan_value, -1, qnan_value, INVALID_EXCEPTION),
+ TEST_ff_f (pow, -snan_value, -1, qnan_value, INVALID_EXCEPTION),
- /* pow (x, qNaN) == qNaN. */
+ /* pow (x, qNaN or sNaN) == qNaN. */
TEST_ff_f (pow, 3.0, qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
TEST_ff_f (pow, 3.0, -qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
TEST_ff_f (pow, minus_zero, qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
@@ -11173,6 +11199,16 @@ static const struct test_ff_f_data pow_test_data[] =
TEST_ff_f (pow, -3.0, -qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
TEST_ff_f (pow, minus_infty, qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
TEST_ff_f (pow, minus_infty, -qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+ TEST_ff_f (pow, 3.0, snan_value, qnan_value, INVALID_EXCEPTION),
+ TEST_ff_f (pow, 3.0, -snan_value, qnan_value, INVALID_EXCEPTION),
+ TEST_ff_f (pow, minus_zero, snan_value, qnan_value, INVALID_EXCEPTION),
+ TEST_ff_f (pow, minus_zero, -snan_value, qnan_value, INVALID_EXCEPTION),
+ TEST_ff_f (pow, plus_infty, snan_value, qnan_value, INVALID_EXCEPTION),
+ TEST_ff_f (pow, plus_infty, -snan_value, qnan_value, INVALID_EXCEPTION),
+ TEST_ff_f (pow, -3.0, snan_value, qnan_value, INVALID_EXCEPTION),
+ TEST_ff_f (pow, -3.0, -snan_value, qnan_value, INVALID_EXCEPTION),
+ TEST_ff_f (pow, minus_infty, snan_value, qnan_value, INVALID_EXCEPTION),
+ TEST_ff_f (pow, minus_infty, -snan_value, qnan_value, INVALID_EXCEPTION),
TEST_ff_f (pow, qnan_value, 3.0, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
TEST_ff_f (pow, -qnan_value, 3.0, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
@@ -11190,6 +11226,22 @@ static const struct test_ff_f_data pow_test_data[] =
TEST_ff_f (pow, -qnan_value, min_subnorm_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
TEST_ff_f (pow, qnan_value, -min_subnorm_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
TEST_ff_f (pow, -qnan_value, -min_subnorm_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+ TEST_ff_f (pow, snan_value, 3.0, qnan_value, INVALID_EXCEPTION),
+ TEST_ff_f (pow, -snan_value, 3.0, qnan_value, INVALID_EXCEPTION),
+ TEST_ff_f (pow, snan_value, -3.0, qnan_value, INVALID_EXCEPTION),
+ TEST_ff_f (pow, -snan_value, -3.0, qnan_value, INVALID_EXCEPTION),
+ TEST_ff_f (pow, snan_value, plus_infty, qnan_value, INVALID_EXCEPTION),
+ TEST_ff_f (pow, -snan_value, plus_infty, qnan_value, INVALID_EXCEPTION),
+ TEST_ff_f (pow, snan_value, minus_infty, qnan_value, INVALID_EXCEPTION),
+ TEST_ff_f (pow, -snan_value, minus_infty, qnan_value, INVALID_EXCEPTION),
+ TEST_ff_f (pow, snan_value, 2.5, qnan_value, INVALID_EXCEPTION),
+ TEST_ff_f (pow, -snan_value, 2.5, qnan_value, INVALID_EXCEPTION),
+ TEST_ff_f (pow, snan_value, -2.5, qnan_value, INVALID_EXCEPTION),
+ TEST_ff_f (pow, -snan_value, -2.5, qnan_value, INVALID_EXCEPTION),
+ TEST_ff_f (pow, snan_value, min_subnorm_value, qnan_value, INVALID_EXCEPTION),
+ TEST_ff_f (pow, -snan_value, min_subnorm_value, qnan_value, INVALID_EXCEPTION),
+ TEST_ff_f (pow, snan_value, -min_subnorm_value, qnan_value, INVALID_EXCEPTION),
+ TEST_ff_f (pow, -snan_value, -min_subnorm_value, qnan_value, INVALID_EXCEPTION),
TEST_ff_f (pow, 1, plus_infty, 1, ERRNO_UNCHANGED),
TEST_ff_f (pow, -1, plus_infty, 1, ERRNO_UNCHANGED),
diff --git a/sysdeps/i386/fpu/e_powl.S b/sysdeps/i386/fpu/e_powl.S
index 923ee37..57b80be 100644
--- a/sysdeps/i386/fpu/e_powl.S
+++ b/sysdeps/i386/fpu/e_powl.S
@@ -201,15 +201,21 @@ ENTRY(__ieee754_powl)
fucomp %st(1) // x : y
fnstsw
sahf
- je 31f
- fxch // y : x
-31: fstp %st(1)
+ je 33f
+31: /* At least one argument NaN, and result should be NaN. */
+ faddp
+ ret
+33: jp 31b
+ /* pow (1, NaN); check if the NaN signaling. */
+ testb $0x40, 23(%esp)
+ jz 31b
+ fstp %st(1)
ret
cfi_adjust_cfa_offset (8)
32: addl $8, %esp
cfi_adjust_cfa_offset (-8)
- fstp %st(1)
+ faddp
ret
cfi_adjust_cfa_offset (8)
@@ -241,12 +247,24 @@ ENTRY(__ieee754_powl)
cfi_adjust_cfa_offset (-36)
ret
- // pow(x,±0) = 1
+ // pow(x,±0) = 1, unless x is sNaN
.align ALIGNARG(4)
11: fstp %st(0) // pop y
+ fldt 4(%esp) // x
+ fxam
+ fnstsw
+ andb $0x45, %ah
+ cmpb $0x01, %ah
+ je 112f // x is NaN
+111: fstp %st(0)
fldl MO(one)
ret
+112: testb $0x40, 11(%esp)
+ jnz 111b
+ fadd %st(0)
+ ret
+
// y == ±inf
.align ALIGNARG(4)
12: fstp %st(0) // pop y
@@ -274,6 +292,7 @@ ENTRY(__ieee754_powl)
.align ALIGNARG(4)
13: fldt 4(%esp) // load x == NaN
+ fadd %st(0)
ret
cfi_adjust_cfa_offset (8)
diff --git a/sysdeps/x86_64/fpu/e_powl.S b/sysdeps/x86_64/fpu/e_powl.S
index 4a7f3a1..2b36077 100644
--- a/sysdeps/x86_64/fpu/e_powl.S
+++ b/sysdeps/x86_64/fpu/e_powl.S
@@ -184,9 +184,15 @@ ENTRY(__ieee754_powl)
30: fldt 8(%rsp) // x : y
fldl MO(one) // 1.0 : x : y
fucomip %st(1),%st // x : y
- je 31f
- fxch // y : x
-31: fstp %st(1)
+ je 32f
+31: /* At least one argument NaN, and result should be NaN. */
+ faddp
+ ret
+32: jc 31b
+ /* pow (1, NaN); check if the NaN signaling. */
+ testb $0x40, 31(%rsp)
+ jz 31b
+ fstp %st(1)
ret
.align ALIGNARG(4)
@@ -217,12 +223,24 @@ ENTRY(__ieee754_powl)
cfi_adjust_cfa_offset (-40)
ret
- // pow(x,±0) = 1
+ // pow(x,±0) = 1, unless x is sNaN
.align ALIGNARG(4)
11: fstp %st(0) // pop y
+ fldt 8(%rsp) // x
+ fxam
+ fnstsw
+ andb $0x45, %ah
+ cmpb $0x01, %ah
+ je 112f // x is NaN
+111: fstp %st(0)
fldl MO(one)
ret
+112: testb $0x40, 15(%rsp)
+ jnz 111b
+ fadd %st(0)
+ ret
+
// y == ±inf
.align ALIGNARG(4)
12: fstp %st(0) // pop y
@@ -255,6 +273,7 @@ ENTRY(__ieee754_powl)
.align ALIGNARG(4)
13: fldt 8(%rsp) // load x == NaN
+ fadd %st(0)
ret
.align ALIGNARG(4)