public inbox for libc-alpha@sourceware.org
 help / color / mirror / Atom feed
* Fix x86_64/x86 powl handling of sNaN arguments (bug 20916) [committed]
@ 2016-12-06  0:34 Joseph Myers
  0 siblings, 0 replies; only message in thread
From: Joseph Myers @ 2016-12-06  0:34 UTC (permalink / raw)
  To: libc-alpha

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.  Committed.

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.

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)

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2016-12-06  0:34 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-12-06  0:34 Fix x86_64/x86 powl handling of sNaN arguments (bug 20916) [committed] Joseph Myers

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).