diff --git a/ChangeLog b/ChangeLog index 9c0aaa6e43..ab723ebfbb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2016-12-06 Joseph Myers + + [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 * include/atomic.h (__atomic_check_size_ls): New. diff --git a/math/libm-test.inc b/math/libm-test.inc index 85df9deb86..9123dcfc48 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 923ee37222..57b80beb64 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 4a7f3a18d3..2b36077a32 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)