about summary refs log tree commit diff
path: root/sysdeps/powerpc/powerpc64/fpu
diff options
context:
space:
mode:
authorJoseph Myers <joseph@codesourcery.com>2015-11-11 00:06:09 +0000
committerJoseph Myers <joseph@codesourcery.com>2015-11-11 00:06:09 +0000
commit71d1b0166b4ace0d804af2993b3815758b852efc (patch)
tree1cfe69ef93cf1fa482ecbd57dc324cd2494895a1 /sysdeps/powerpc/powerpc64/fpu
parentfe534fe8980fa214c410e3661a4216e781073353 (diff)
downloadglibc-71d1b0166b4ace0d804af2993b3815758b852efc.tar.gz
glibc-71d1b0166b4ace0d804af2993b3815758b852efc.tar.xz
glibc-71d1b0166b4ace0d804af2993b3815758b852efc.zip
Fix powerpc nearbyint wrongly clearing "inexact" and leaving traps disabled (bug 19228).
Similar to bug 15491 recently fixed for x86_64 / x86, the powerpc
(both powerpc32 and powerpc64) hard-float implementations of
nearbyintf and nearbyint wrongly clear an "inexact" exception that was
raised before the function was called; this shows up as failure of the
test math/test-nearbyint-except added when that bug was fixed.  They
also wrongly leave traps on "inexact" disabled if they were enabled
before the function was called.

This patch fixes the bugs similar to how the x86 bug was fixed: saving
and restoring the whole floating-point state, both to restore the
original "inexact" flag state and to restore the original state of
whether traps on "inexact" were enabled.  Because there's a convenient
point in the powerpc implementations to save state after any sNaN
arguments will have raised "invalid" but before "inexact" traps need
to be disabled, no special handling for "invalid" is needed as in the
x86 version.

Tested for powerpc64 and powerpc32, where it fixes the
math/test-nearbyint-except failure as well as fixing the new test
math/test-nearbyint-except-2 added by this patch.  Also tested for
x86_64 and x86 that the new test passes.

If powerpc experts see a more efficient way of doing this
(e.g. instruction positioning that's better for pipelines on typical
processors) then of course followups optimizing the fix are welcome.

	[BZ #19228]
	* sysdeps/powerpc/powerpc32/fpu/s_nearbyint.S (__nearbyint): Save
	and restore full floating-point state.
	* sysdeps/powerpc/powerpc32/fpu/s_nearbyintf.S (__nearbyintf):
	Likewise.
	* sysdeps/powerpc/powerpc64/fpu/s_nearbyint.S (__nearbyint):
	Likewise.
	* sysdeps/powerpc/powerpc64/fpu/s_nearbyintf.S (__nearbyintf):
	Likewise.
	* math/test-nearbyint-except-2.c: New file.
	* math/Makefile (tests): Add test-nearbyint-except-2.
Diffstat (limited to 'sysdeps/powerpc/powerpc64/fpu')
-rw-r--r--sysdeps/powerpc/powerpc64/fpu/s_nearbyint.S6
-rw-r--r--sysdeps/powerpc/powerpc64/fpu/s_nearbyintf.S6
2 files changed, 8 insertions, 4 deletions
diff --git a/sysdeps/powerpc/powerpc64/fpu/s_nearbyint.S b/sysdeps/powerpc/powerpc64/fpu/s_nearbyint.S
index 6654840f7f..9c87596cc4 100644
--- a/sysdeps/powerpc/powerpc64/fpu/s_nearbyint.S
+++ b/sysdeps/powerpc/powerpc64/fpu/s_nearbyint.S
@@ -40,19 +40,21 @@ EALIGN (__nearbyint, 4, 0)
 	fsub	fp12,fp13,fp13	/* generate 0.0 */
 	fcmpu	cr7,fp1,fp12	/* if (x > 0.0) */
 	ble	cr7, L(lessthanzero)
+	mffs	fp11
 	mtfsb0	4*cr7+lt	/* Disable FE_INEXACT exception */
 	fadd	fp1,fp1,fp13	/* x+= TWO52 */
 	fsub	fp1,fp1,fp13	/* x-= TWO52 */
 	fabs	fp1,fp1		/* if (x == 0.0) */
-	mtfsb0	4*cr1+eq	/* Clear any FE_INEXACT exception */
+	mtfsf	0xff,fp11	/* Restore FE_INEXACT state.  */
 	blr			/* x = 0.0; */
 L(lessthanzero):
 	bgelr	cr7		/* if (x < 0.0) */
+	mffs	fp11
 	mtfsb0	4*cr7+lt
 	fsub	fp1,fp1,fp13	/* x -= TWO52 */
 	fadd	fp1,fp1,fp13	/* x += TWO52 */
 	fnabs	fp1,fp1		/* if (x == 0.0) */
-	mtfsb0	4*cr1+eq
+	mtfsf	0xff,fp11	/* Restore FE_INEXACT state.  */
 	blr			/* x = -0.0; */
 END (__nearbyint)
 
diff --git a/sysdeps/powerpc/powerpc64/fpu/s_nearbyintf.S b/sysdeps/powerpc/powerpc64/fpu/s_nearbyintf.S
index 041dfeb46e..9dfbce6b9c 100644
--- a/sysdeps/powerpc/powerpc64/fpu/s_nearbyintf.S
+++ b/sysdeps/powerpc/powerpc64/fpu/s_nearbyintf.S
@@ -41,19 +41,21 @@ EALIGN (__nearbyintf, 4, 0)
 	fsubs	fp12,fp13,fp13	/* generate 0.0 */
 	fcmpu	cr7,fp1,fp12	/* if (x > 0.0)  */
 	ble	cr7, L(lessthanzero)
+	mffs	fp11
 	mtfsb0	4*cr7+lt	/* Disable FE_INEXACT exception */
 	fadds	fp1,fp1,fp13	/* x += TWO23 */
 	fsubs	fp1,fp1,fp13	/* x -= TWO23 */
 	fabs	fp1,fp1		/* if (x == 0.0) */
-	mtfsb0	4*cr1+eq	/* Clear pending FE_INEXACT exception */
+	mtfsf	0xff,fp11	/* Restore FE_INEXACT state.  */
 	blr			/* x = 0.0; */
 L(lessthanzero):
 	bgelr	cr7		/* if (x < 0.0) */
+	mffs	fp11
 	mtfsb0	4*cr7+lt	/* Disable FE_INEXACT exception */
 	fsubs	fp1,fp1,fp13	/* x -= TWO23 */
 	fadds	fp1,fp1,fp13	/* x += TWO23 */
 	fnabs	fp1,fp1		/* if (x == 0.0) */
-	mtfsb0	4*cr1+eq	/* Clear pending FE_INEXACT exception */
+	mtfsf	0xff,fp11	/* Restore FE_INEXACT state.  */
 	blr			/* x = -0.0; */
 END (__nearbyintf)