This is the mail archive of the libc-hacker@sourceware.org mailing list for the glibc project.

Note that libc-hacker is a closed list. You may look at the archives of this list, but subscription and posting are not open.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] fenv fixes for x86_64/i386/ia64


Hi!

feholdexcept is supposed to clear the sticky exception bits:
"The feholdexcept function saves the current floating-point environment in the object
pointed to by envp, clears the floating-point status flags, and then installs a non-stop
(continue on floating-point exceptions) mode, if available, for all floating-point
exceptions."
and
"A floating-point status flag is a system variable whose value is set
(but never cleared) when a floating-point exception is raised, which occurs as a side effect
of exceptional floating-point arithmetic to provide auxiliary information."

Several feholdexcept implementations didn't handle this right.
Also, e.g. feupdateenv was a stub on x86_64 eventhough it is IMHO easily
implementable and other arches had bugs in it too (e.g. ia64 would rise
wrong exceptions and always return a failure).
I added a new testcase for feholdexcept/feupdateenv (hopefully I haven't
misinterpreted the standard) and I believe other arches (ppc*, s390*, ...)
will need some care too.

2007-03-22  Jakub Jelinek  <jakub@redhat.com>

	[BZ #3427]
	* sysdeps/x86_64/fpu/feholdexcpt.c (feholdexcept): Clear all
	exceptions both in SW and MXCSR.
	* sysdeps/x86_64/fpu/feupdateenv.c: New file.
	* sysdeps/x86_64/fpu/feenablxcpt.c (feenableexcept): Remove dead code.
	* sysdeps/x86_64/fpu/fedisblxcpt.c (fedisableexcept): Likewise.
	* sysdeps/i386/fpu/feholdexcpt.c (feholdexcept): Clear all exceptions
	in MXCSR if SSE is available.
	* sysdeps/i386/fpu/feupdateenv.c: Include unistd.h, dl-procinfo.h
	and ldsodefs.h.
	(__feupdateenv): Query exceptions also from MXCSR if SSE is available.
	Fix comment typo.
	* sysdeps/ia64/fpu/feholdexcpt.c (feholdexcept): Clear all exceptions.
	Return 0 rather than 1.
	* sysdeps/ia64/fpu/feupdateenv.c (feupdateenv): Fix comment typo.
	Remove incorrect part of a comment.  Fix argument to feraiseexcept.
	* math/test-fenv.c (feholdexcept_tests): New function.
	(main): Call it.

2007-01-05  Richard B. Kreckel  <kreckel@ginac.de>

	[BZ #3427]
	* sysdeps/i386/fpu/feholdexcpt.c (feholdexcept): Clear all exceptions
	in SW.

--- libc/math/test-fenv.c.jj	2003-05-22 04:08:50.000000000 +0200
+++ libc/math/test-fenv.c	2007-03-22 14:41:33.000000000 +0100
@@ -1,4 +1,5 @@
-/* Copyright (C) 1997, 1998, 2000, 2001, 2003 Free Software Foundation, Inc.
+/* Copyright (C) 1997, 1998, 2000, 2001, 2003, 2007
+   Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Andreas Jaeger <aj@suse.de> and
    Ulrich Drepper <drepper@cygnus.com>, 1997.
@@ -636,6 +637,102 @@ feenv_tests (void)
 }
 
 
+static void
+feholdexcept_tests (void)
+{
+  fenv_t saved, saved2;
+  int res;
+
+  feclearexcept (FE_ALL_EXCEPT);
+  fedisableexcept (FE_ALL_EXCEPT);
+#ifdef FE_DIVBYZERO
+  feraiseexcept (FE_DIVBYZERO);
+#endif
+  test_exceptions ("feholdexcept_tests FE_DIVBYZERO test",
+		   DIVBYZERO_EXC, 0);
+  res = feholdexcept (&saved);
+  if (res != 0)
+    {
+      printf ("feholdexcept failed: %d\n", res);
+      ++count_errors;
+    }
+#if defined FE_TONEAREST && defined FE_TOWARDZERO
+  res = fesetround (FE_TOWARDZERO);
+  if (res != 0)
+    {
+      printf ("fesetround failed: %d\n", res);
+      ++count_errors;
+    }
+#endif
+  test_exceptions ("feholdexcept_tests 0 test", NO_EXC, 0);
+  feraiseexcept (FE_INVALID);
+  test_exceptions ("feholdexcept_tests FE_INVALID test",
+		   INVALID_EXC, 0);
+  res = feupdateenv (&saved);
+  if (res != 0)
+    {
+      printf ("feupdateenv failed: %d\n", res);
+      ++count_errors;
+    }
+#if defined FE_TONEAREST && defined FE_TOWARDZERO
+  res = fegetround ();
+  if (res != FE_TONEAREST)
+    {
+      printf ("feupdateenv didn't restore rounding mode: %d\n", res);
+      ++count_errors;
+    }
+#endif
+  test_exceptions ("feholdexcept_tests FE_DIVBYZERO|FE_INVALID test",
+		   DIVBYZERO_EXC | INVALID_EXC, 0);
+  feclearexcept (FE_ALL_EXCEPT);
+  feraiseexcept (FE_INVALID);
+#if defined FE_TONEAREST && defined FE_UPWARD
+  res = fesetround (FE_UPWARD);
+  if (res != 0)
+    {
+      printf ("fesetround failed: %d\n", res);
+      ++count_errors;
+    }
+#endif
+  res = feholdexcept (&saved2);
+  if (res != 0)
+    {
+      printf ("feholdexcept failed: %d\n", res);
+      ++count_errors;
+    }
+#if defined FE_TONEAREST && defined FE_UPWARD
+  res = fesetround (FE_TONEAREST);
+  if (res != 0)
+    {
+      printf ("fesetround failed: %d\n", res);
+      ++count_errors;
+    }
+#endif
+  test_exceptions ("feholdexcept_tests 0 2nd test", NO_EXC, 0);
+  feraiseexcept (FE_INEXACT);
+  test_exceptions ("feholdexcept_tests FE_INEXACT test",
+		   INEXACT_EXC, 0);
+  res = feupdateenv (&saved2);
+  if (res != 0)
+    {
+      printf ("feupdateenv failed: %d\n", res);
+      ++count_errors;
+    }
+#if defined FE_TONEAREST && defined FE_UPWARD
+  res = fegetround ();
+  if (res != FE_UPWARD)
+    {
+      printf ("feupdateenv didn't restore rounding mode: %d\n", res);
+      ++count_errors;
+    }
+  fesetround (FE_TONEAREST);
+#endif
+  test_exceptions ("feholdexcept_tests FE_INEXACT|FE_INVALID test",
+		   INVALID_EXC | INEXACT_EXC, 0);
+  feclearexcept (FE_ALL_EXCEPT);
+}
+
+
 /* IEC 559 and ISO C99 define a default startup environment */
 static void
 initial_tests (void)
@@ -654,6 +751,7 @@ main (void)
   initial_tests ();
   fe_tests ();
   feenv_tests ();
+  feholdexcept_tests ();
 
   if (count_errors)
     {
--- libc/sysdeps/ia64/fpu/feholdexcpt.c.jj	2005-07-08 20:52:46.000000000 +0200
+++ libc/sysdeps/ia64/fpu/feholdexcpt.c	2007-03-22 13:28:45.000000000 +0100
@@ -1,5 +1,5 @@
 /* Store current floating-point environment and clear exceptions.
-   Copyright (C) 1997, 1999, 2000, 2005 Free Software Foundation, Inc.
+   Copyright (C) 1997, 1999, 2000, 2005, 2007 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Christian Boissat <Christian.Boissat@cern.ch>, 1999
 
@@ -23,12 +23,20 @@
 int
 feholdexcept (fenv_t *envp)
 {
+  fenv_t fpsr;
   /* Save the current state.  */
-  fegetenv (envp);
+  __asm__ __volatile__ ("mov.m %0=ar.fpsr" : "=r" (fpsr));
+  *envp = fpsr;
 
-  /* set the trap disable bit */
-  __asm__ __volatile__ ("mov.m ar.fpsr=%0" :: "r" (*envp | FE_ALL_EXCEPT));
+  /* Set the trap disable bits.  */
+  fpsr |= FE_ALL_EXCEPT;
 
-  return 1;
+  /* And clear the exception bits.  */
+  fpsr &= ~(fenv_t) (FE_ALL_EXCEPT << 13);
+
+  __asm__ __volatile__ ("mov.m ar.fpsr=%0" :: "r" (fpsr));
+
+  /* Success.  */
+  return 0;
 }
 libm_hidden_def (feholdexcept)
--- libc/sysdeps/ia64/fpu/feupdateenv.c.jj	2001-07-06 06:55:54.000000000 +0200
+++ libc/sysdeps/ia64/fpu/feupdateenv.c	2007-03-22 13:27:28.000000000 +0100
@@ -1,5 +1,5 @@
 /* Install given floating-point environment and raise exceptions.
-   Copyright (C) 1997, 2000 Free Software Foundation, Inc.
+   Copyright (C) 1997, 2000, 2007 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Christian Boissat <Christian.Boissat@cern.ch>, 1999.
 
@@ -32,10 +32,8 @@ feupdateenv (const fenv_t *envp)
   /* Install new environment.  */
   fesetenv (envp);
 
-  /* Raise the safed exception.  Incidently for us the implementation
-     defined format of the values in objects of type fexcept_t is the
-     same as the ones specified using the FE_* constants.  */
-  feraiseexcept ((int) fpsr & FE_ALL_EXCEPT);
+  /* Raise the saved exceptions.  */
+  feraiseexcept ((int) (fpsr >> 13) & FE_ALL_EXCEPT);
 
   /* Success.  */
   return 0;
--- libc/sysdeps/i386/fpu/feholdexcpt.c.jj	2005-07-08 20:52:47.000000000 +0200
+++ libc/sysdeps/i386/fpu/feholdexcpt.c	2007-03-22 14:56:35.000000000 +0100
@@ -1,5 +1,6 @@
 /* Store current floating-point environment and clear exceptions.
-   Copyright (C) 1997, 1999, 2003, 2004, 2005 Free Software Foundation, Inc.
+   Copyright (C) 1997, 1999, 2003, 2004, 2005, 2007
+   Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
 
@@ -26,14 +27,19 @@
 int
 feholdexcept (fenv_t *envp)
 {
-  unsigned short int work;
+  fenv_t temp;
 
   /* Store the environment.  */
-  __asm__ ("fnstenv %0" : "=m" (*envp));
+  __asm__ ("fnstenv %0" : "=m" (temp));
+  *envp = temp;
 
   /* Now set all exceptions to non-stop.  */
-  work = envp->__control_word | 0x3f;
-  __asm__ ("fldcw %0" : : "m" (*&work));
+  temp.__control_word |= 0x3f;
+
+  /* And clear all exceptions.  */
+  temp.__status_word &= ~0x3f;
+
+  __asm__ ("fldenv %0" : : "m" (temp));
 
   /* If the CPU supports SSE we set the MXCSR as well.  */
   if ((GLRO(dl_hwcap) & HWCAP_I386_XMM) != 0)
@@ -43,8 +49,8 @@ feholdexcept (fenv_t *envp)
       /* Get the current control word.  */
       __asm__ ("stmxcsr %0" : "=m" (*&xwork));
 
-      /* Set all exceptions to non-stop.  */
-      xwork |= 0x1f80;
+      /* Set all exceptions to non-stop and clear them.  */
+      xwork = (xwork | 0x1f80) & ~0x3f;
 
       __asm__ ("ldmxcsr %0" : : "m" (*&xwork));
     }
--- libc/sysdeps/i386/fpu/feupdateenv.c.jj	2001-07-06 06:55:53.000000000 +0200
+++ libc/sysdeps/i386/fpu/feupdateenv.c	2007-03-22 14:47:22.000000000 +0100
@@ -1,5 +1,5 @@
 /* Install given floating-point environment and raise exceptions.
-   Copyright (C) 1997,99,2000,01 Free Software Foundation, Inc.
+   Copyright (C) 1997,99,2000,01,07 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
 
@@ -20,20 +20,29 @@
 
 #include <fenv.h>
 #include <bp-sym.h>
+#include <unistd.h>
+#include <dl-procinfo.h>
+#include <ldsodefs.h>
 
 int
 __feupdateenv (const fenv_t *envp)
 {
   fexcept_t temp;
+  unsigned int xtemp = 0;
 
   /* Save current exceptions.  */
   __asm__ ("fnstsw %0" : "=m" (*&temp));
-  temp &= FE_ALL_EXCEPT;
+
+  /* If the CPU supports SSE we test the MXCSR as well.  */
+  if ((GLRO(dl_hwcap) & HWCAP_I386_XMM) != 0)
+    __asm__ ("stmxcsr %0" : "=m" (*&xtemp));
+
+  temp = (temp | xtemp) & FE_ALL_EXCEPT;
 
   /* Install new environment.  */
   fesetenv (envp);
 
-  /* Raise the safed exception.  Incidently for us the implementation
+  /* Raise the saved exception.  Incidently for us the implementation
      defined format of the values in objects of type fexcept_t is the
      same as the ones specified using the FE_* constants.  */
   feraiseexcept ((int) temp);
--- libc/sysdeps/x86_64/fpu/feholdexcpt.c.jj	2005-07-08 20:52:45.000000000 +0200
+++ libc/sysdeps/x86_64/fpu/feholdexcpt.c	2007-03-22 11:46:47.000000000 +0100
@@ -1,5 +1,5 @@
 /* Store current floating-point environment and clear exceptions.
-   Copyright (C) 2001, 2005 Free Software Foundation, Inc.
+   Copyright (C) 2001, 2005, 2007 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -22,19 +22,24 @@
 int
 feholdexcept (fenv_t *envp)
 {
-  unsigned short int work;
   unsigned int mxcsr;
+  fenv_t temp;
 
   /* Store the environment.  */
   __asm__ ("fnstenv %0\n"
-	   "stmxcsr %1" : "=m" (*envp), "=m" (envp->__mxcsr));
+	   "stmxcsr %1" : "=m" (temp), "=m" (temp.__mxcsr));
+  *envp = temp;
 
   /* Now set all exceptions to non-stop, first the x87 FPU.  */
-  work = envp->__control_word | 0x3f;
-  __asm__ ("fldcw %0" : : "m" (*&work));
+  temp.__control_word |= 0x3f;
+
+  /* And clear all exceptions.  */
+  temp.__status_word &= ~0x3f;
+
+  __asm__ ("fldenv %0" : : "m" (temp));
 
   /* Set the SSE MXCSR register.  */
-  mxcsr = envp->__mxcsr | 0x1f80;
+  mxcsr = (envp->__mxcsr | 0x1f80) & ~0x3f;
   __asm__ ("ldmxcsr %0" : : "m" (*&mxcsr));
 
   return 0;
--- libc/sysdeps/x86_64/fpu/feupdateenv.c.jj	2007-03-22 12:11:41.000000000 +0100
+++ libc/sysdeps/x86_64/fpu/feupdateenv.c	2007-03-22 12:19:23.000000000 +0100
@@ -0,0 +1,51 @@
+/* Install given floating-point environment and raise exceptions.
+   Copyright (C) 1997,99,2000,01,07 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <fenv.h>
+
+int
+__feupdateenv (const fenv_t *envp)
+{
+  fexcept_t temp;
+  unsigned int xtemp;
+
+  /* Save current exceptions.  */
+  __asm__ ("fnstsw %0\n\tstmxcsr %1" : "=m" (*&temp), "=m" (xtemp));
+  temp = (temp | xtemp) & FE_ALL_EXCEPT;
+
+  /* Install new environment.  */
+  fesetenv (envp);
+
+  /* Raise the saved exception.  Incidently for us the implementation
+     defined format of the values in objects of type fexcept_t is the
+     same as the ones specified using the FE_* constants.  */
+  feraiseexcept ((int) temp);
+
+  /* Success.  */
+  return 0;
+}
+
+#include <shlib-compat.h>
+#if SHLIB_COMPAT (libm, GLIBC_2_1, GLIBC_2_2)
+strong_alias (__feupdateenv, __old_feupdateenv)
+compat_symbol (libm, __old_feupdateenv, feupdateenv, GLIBC_2_1);
+#endif
+
+versioned_symbol (libm, __feupdateenv, feupdateenv, GLIBC_2_2);
--- libc/sysdeps/x86_64/fpu/feenablxcpt.c.jj	2001-09-19 12:23:17.000000000 +0200
+++ libc/sysdeps/x86_64/fpu/feenablxcpt.c	2007-03-22 11:24:28.000000000 +0100
@@ -1,5 +1,5 @@
 /* Enable floating-point exceptions.
-   Copyright (C) 2001 Free Software Foundation, Inc.
+   Copyright (C) 2001, 2007 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Andreas Jaeger <aj@suse.de>, 2001.
 
@@ -24,7 +24,7 @@ int
 feenableexcept (int excepts)
 {
   unsigned short int new_exc, old_exc;
-  unsigned int new, old;
+  unsigned int new;
 
   excepts &= FE_ALL_EXCEPT;
 
@@ -40,8 +40,6 @@ feenableexcept (int excepts)
   __asm__ ("stmxcsr %0" : "=m" (*&new));
 
   /* The SSE exception masks are shifted by 7 bits.  */
-  old = (~new) & (FE_ALL_EXCEPT << 7);
-
   new &= ~(excepts << 7);
   __asm__ ("ldmxcsr %0" : : "m" (*&new));
 
--- libc/sysdeps/x86_64/fpu/fedisblxcpt.c.jj	2001-09-19 12:23:17.000000000 +0200
+++ libc/sysdeps/x86_64/fpu/fedisblxcpt.c	2007-03-22 11:26:35.000000000 +0100
@@ -1,5 +1,5 @@
 /* Disable floating-point exceptions.
-   Copyright (C) 2001 Free Software Foundation, Inc.
+   Copyright (C) 2001, 2007 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Andreas Jaeger <aj@suse.de>, 2001.
 
@@ -24,7 +24,7 @@ int
 fedisableexcept (int excepts)
 {
   unsigned short int new_exc, old_exc;
-  unsigned int new, old;
+  unsigned int new;
 
   excepts &= FE_ALL_EXCEPT;
 
@@ -40,8 +40,6 @@ fedisableexcept (int excepts)
   __asm__ ("stmxcsr %0" : "=m" (*&new));
 
   /* The SSE exception masks are shifted by 7 bits.  */
-  old = (~new) & (FE_ALL_EXCEPT << 7);
-
   new |= excepts << 7;
   __asm__ ("ldmxcsr %0" : : "m" (*&new));
 

	Jakub


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]