Fix x86_64/x86 powl handling of sNaN arguments (bug 20916).

The x86_64/x86 powl implementations mishandle sNaN arguments, both by
returning sNaN in some cases (instead of doing arithmetic on the
arguments to produce the result when NaN arguments result in NaN
results) and by treating sNaN the same as qNaN for arguments (1, sNaN)
and (sNaN, 0), contrary to TS 18661-1 which requires those cases to
return qNaN instead of 1.

This patch makes the x86_64/x86 powl implementations follow TS 18661-1
semantics for sNaN arguments; sNaN tests are also added for pow.
Given the problems with testing float and double sNaN arguments on
32-bit x86 (sNaN tests disabled because the compiler may convert
unnecessarily to a qNaN when passing arguments), no changes are made
to the powf and pow implementations there.

Tested for x86_64 and x86.

	[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.
This commit is contained in:
Joseph Myers 2016-12-06 00:33:19 +00:00
parent ca6e601a9d
commit a91fd168a0
4 changed files with 109 additions and 10 deletions

View File

@ -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> 2016-12-05 Torvald Riegel <triegel@redhat.com>
* include/atomic.h (__atomic_check_size_ls): New. * include/atomic.h (__atomic_check_size_ls): New.

View File

@ -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, 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, -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, 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), 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, 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, -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, -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, -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, -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, -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, 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), 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, -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, 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),
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, 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),
TEST_ff_f (pow, -1, plus_infty, 1, ERRNO_UNCHANGED), TEST_ff_f (pow, -1, plus_infty, 1, ERRNO_UNCHANGED),

View File

@ -201,15 +201,21 @@ ENTRY(__ieee754_powl)
fucomp %st(1) // x : y fucomp %st(1) // x : y
fnstsw fnstsw
sahf sahf
je 31f je 33f
fxch // y : x 31: /* At least one argument NaN, and result should be NaN. */
31: fstp %st(1) faddp
ret
33: jp 31b
/* pow (1, NaN); check if the NaN signaling. */
testb $0x40, 23(%esp)
jz 31b
fstp %st(1)
ret ret
cfi_adjust_cfa_offset (8) cfi_adjust_cfa_offset (8)
32: addl $8, %esp 32: addl $8, %esp
cfi_adjust_cfa_offset (-8) cfi_adjust_cfa_offset (-8)
fstp %st(1) faddp
ret ret
cfi_adjust_cfa_offset (8) cfi_adjust_cfa_offset (8)
@ -241,12 +247,24 @@ ENTRY(__ieee754_powl)
cfi_adjust_cfa_offset (-36) cfi_adjust_cfa_offset (-36)
ret ret
// pow(x,ą0) = 1 // pow(x,±0) = 1, unless x is sNaN
.align ALIGNARG(4) .align ALIGNARG(4)
11: fstp %st(0) // pop y 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) fldl MO(one)
ret ret
112: testb $0x40, 11(%esp)
jnz 111b
fadd %st(0)
ret
// y == ±inf // y == ±inf
.align ALIGNARG(4) .align ALIGNARG(4)
12: fstp %st(0) // pop y 12: fstp %st(0) // pop y
@ -274,6 +292,7 @@ ENTRY(__ieee754_powl)
.align ALIGNARG(4) .align ALIGNARG(4)
13: fldt 4(%esp) // load x == NaN 13: fldt 4(%esp) // load x == NaN
fadd %st(0)
ret ret
cfi_adjust_cfa_offset (8) cfi_adjust_cfa_offset (8)

View File

@ -184,9 +184,15 @@ ENTRY(__ieee754_powl)
30: fldt 8(%rsp) // x : y 30: fldt 8(%rsp) // x : y
fldl MO(one) // 1.0 : x : y fldl MO(one) // 1.0 : x : y
fucomip %st(1),%st // x : y fucomip %st(1),%st // x : y
je 31f je 32f
fxch // y : x 31: /* At least one argument NaN, and result should be NaN. */
31: fstp %st(1) faddp
ret
32: jc 31b
/* pow (1, NaN); check if the NaN signaling. */
testb $0x40, 31(%rsp)
jz 31b
fstp %st(1)
ret ret
.align ALIGNARG(4) .align ALIGNARG(4)
@ -217,12 +223,24 @@ ENTRY(__ieee754_powl)
cfi_adjust_cfa_offset (-40) cfi_adjust_cfa_offset (-40)
ret ret
// pow(x,ą0) = 1 // pow(x,±0) = 1, unless x is sNaN
.align ALIGNARG(4) .align ALIGNARG(4)
11: fstp %st(0) // pop y 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) fldl MO(one)
ret ret
112: testb $0x40, 15(%rsp)
jnz 111b
fadd %st(0)
ret
// y == ±inf // y == ±inf
.align ALIGNARG(4) .align ALIGNARG(4)
12: fstp %st(0) // pop y 12: fstp %st(0) // pop y
@ -255,6 +273,7 @@ ENTRY(__ieee754_powl)
.align ALIGNARG(4) .align ALIGNARG(4)
13: fldt 8(%rsp) // load x == NaN 13: fldt 8(%rsp) // load x == NaN
fadd %st(0)
ret ret
.align ALIGNARG(4) .align ALIGNARG(4)