Fix i386/x86_64 scalbl with sNaN input (bug 20296).

The x86_64 and i386 versions of scalbl return sNaN for some cases of
sNaN input and are missing "invalid" exceptions for other cases.  This
results from overly complicated code that either returns a NaN input,
or discards both inputs when one is NaN and loads a NaN from memory.
This patch fixes this by simplifying the code to add the arguments
when either one is NaN.

Tested for x86_64 and x86.

	[BZ #20296]
	* sysdeps/i386/fpu/e_scalbl.S (__ieee754_scalbl): Add arguments
	when either argument is a NaN.
	* sysdeps/x86_64/fpu/e_scalbl.S (__ieee754_scalbl): Likewise.
	* math/libm-test.inc (scalb_test_data): Add sNaN tests.
This commit is contained in:
Joseph Myers 2016-06-23 22:17:41 +00:00
parent 7ed84b89f3
commit 40244be372
4 changed files with 48 additions and 23 deletions

View File

@ -1,5 +1,11 @@
2016-06-23 Joseph Myers <joseph@codesourcery.com>
[BZ #20296]
* sysdeps/i386/fpu/e_scalbl.S (__ieee754_scalbl): Add arguments
when either argument is a NaN.
* sysdeps/x86_64/fpu/e_scalbl.S (__ieee754_scalbl): Likewise.
* math/libm-test.inc (scalb_test_data): Add sNaN tests.
* math/libm-test.inc (snan_value_ld): New macro.
(isgreater_test_data): Add sNaN tests.
(isgreaterequal_test_data): Likewise.

View File

@ -11598,6 +11598,10 @@ static const struct test_ff_f_data scalb_test_data[] =
TEST_ff_f (scalb, 0, -qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
TEST_ff_f (scalb, 1, qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
TEST_ff_f (scalb, 1, -qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
TEST_ff_f (scalb, 0, snan_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
TEST_ff_f (scalb, 0, -snan_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
TEST_ff_f (scalb, 1, snan_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
TEST_ff_f (scalb, 1, -snan_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
TEST_ff_f (scalb, 1, 0, 1, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
TEST_ff_f (scalb, -1, 0, -1, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
@ -11634,28 +11638,60 @@ static const struct test_ff_f_data scalb_test_data[] =
TEST_ff_f (scalb, qnan_value, 1, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
TEST_ff_f (scalb, -qnan_value, 1, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
TEST_ff_f (scalb, snan_value, 1, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
TEST_ff_f (scalb, -snan_value, 1, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
TEST_ff_f (scalb, 1, qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
TEST_ff_f (scalb, 1, -qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
TEST_ff_f (scalb, 1, snan_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
TEST_ff_f (scalb, 1, -snan_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
TEST_ff_f (scalb, qnan_value, 0.5, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
TEST_ff_f (scalb, -qnan_value, 0.5, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
TEST_ff_f (scalb, snan_value, 0.5, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
TEST_ff_f (scalb, -snan_value, 0.5, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
TEST_ff_f (scalb, 0.5, qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
TEST_ff_f (scalb, 0.5, -qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
TEST_ff_f (scalb, 0.5, snan_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
TEST_ff_f (scalb, 0.5, -snan_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
TEST_ff_f (scalb, qnan_value, 0, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
TEST_ff_f (scalb, -qnan_value, 0, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
TEST_ff_f (scalb, snan_value, 0, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
TEST_ff_f (scalb, -snan_value, 0, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
TEST_ff_f (scalb, 0, qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
TEST_ff_f (scalb, 0, -qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
TEST_ff_f (scalb, 0, snan_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
TEST_ff_f (scalb, 0, -snan_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
TEST_ff_f (scalb, qnan_value, plus_infty, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
TEST_ff_f (scalb, -qnan_value, plus_infty, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
TEST_ff_f (scalb, snan_value, plus_infty, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
TEST_ff_f (scalb, -snan_value, plus_infty, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
TEST_ff_f (scalb, plus_infty, qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
TEST_ff_f (scalb, plus_infty, -qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
TEST_ff_f (scalb, plus_infty, snan_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
TEST_ff_f (scalb, plus_infty, -snan_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
TEST_ff_f (scalb, qnan_value, minus_infty, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
TEST_ff_f (scalb, -qnan_value, minus_infty, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
TEST_ff_f (scalb, snan_value, minus_infty, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
TEST_ff_f (scalb, -snan_value, minus_infty, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
TEST_ff_f (scalb, minus_infty, qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
TEST_ff_f (scalb, minus_infty, -qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
TEST_ff_f (scalb, minus_infty, snan_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
TEST_ff_f (scalb, minus_infty, -snan_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
TEST_ff_f (scalb, qnan_value, qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
TEST_ff_f (scalb, qnan_value, -qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
TEST_ff_f (scalb, -qnan_value, qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
TEST_ff_f (scalb, -qnan_value, -qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
TEST_ff_f (scalb, snan_value, qnan_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
TEST_ff_f (scalb, snan_value, -qnan_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
TEST_ff_f (scalb, -snan_value, qnan_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
TEST_ff_f (scalb, -snan_value, -qnan_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
TEST_ff_f (scalb, qnan_value, snan_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
TEST_ff_f (scalb, qnan_value, -snan_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
TEST_ff_f (scalb, -qnan_value, snan_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
TEST_ff_f (scalb, -qnan_value, -snan_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
TEST_ff_f (scalb, snan_value, snan_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
TEST_ff_f (scalb, snan_value, -snan_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
TEST_ff_f (scalb, -snan_value, snan_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
TEST_ff_f (scalb, -snan_value, -snan_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
TEST_ff_f (scalb, max_value, max_value, plus_oflow, INEXACT_EXCEPTION|OVERFLOW_EXCEPTION|ERRNO_PLUS_OFLOW),
TEST_ff_f (scalb, max_value, -max_value, plus_uflow, INEXACT_EXCEPTION|UNDERFLOW_EXCEPTION|ERRNO_PLUS_UFLOW),

View File

@ -45,7 +45,7 @@ ENTRY(__ieee754_scalbl)
fnstsw
andl $0x4500, %eax
cmpl $0x0100, %eax
je 3f
je 2f
fld %st(1)
frndint
fcomp %st(2)
@ -76,18 +76,8 @@ ENTRY(__ieee754_scalbl)
fldl MOX(zero_nan, %eax, 1)
ret
/* The result is NaN, but we must not raise an exception.
So use a variable. */
2: fstp %st
fstp %st
#ifdef PIC
LOAD_PIC_REG (cx)
#endif
fldl MO(nan)
ret
/* The first parameter is a NaN. Return it. */
3: fstp %st(1)
/* The result is NaN; raise an exception for sNaN arguments. */
2: faddp
ret
/* Return NaN and raise the invalid exception. */

View File

@ -44,7 +44,7 @@ ENTRY(__ieee754_scalbl)
fnstsw
andl $0x4500, %eax
cmpl $0x0100, %eax
je 3f
je 2f
fld %st(1)
frndint
fcomip %st(2), %st
@ -75,15 +75,8 @@ ENTRY(__ieee754_scalbl)
#endif
ret
/* The result is NaN, but we must not raise an exception.
So use a variable. */
2: fstp %st
fstp %st
fldl MO(nan)
ret
/* The first parameter is a NaN. Return it. */
3: fstp %st(1)
/* The result is NaN; raise an exception for sNaN arguments. */
2: faddp
ret
/* Return NaN and raise the invalid exception. */