From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 6879 invoked by alias); 22 Mar 2007 14:49:38 -0000 Received: (qmail 6858 invoked by uid 22791); 22 Mar 2007 14:49:36 -0000 X-Spam-Check-By: sourceware.org Received: from sunsite.ms.mff.cuni.cz (HELO sunsite.mff.cuni.cz) (195.113.15.26) by sourceware.org (qpsmtpd/0.31) with ESMTP; Thu, 22 Mar 2007 14:49:28 +0000 Received: from sunsite.mff.cuni.cz (localhost.localdomain [127.0.0.1]) by sunsite.mff.cuni.cz (8.13.8/8.13.8) with ESMTP id l2MErk1H013815; Thu, 22 Mar 2007 15:53:46 +0100 Received: (from jakub@localhost) by sunsite.mff.cuni.cz (8.13.8/8.13.8/Submit) id l2MErkm1013814; Thu, 22 Mar 2007 15:53:46 +0100 Date: Thu, 22 Mar 2007 14:49:00 -0000 From: Jakub Jelinek To: Ulrich Drepper Cc: Glibc hackers Subject: [PATCH] fenv fixes for x86_64/i386/ia64 Message-ID: <20070322145345.GZ1826@sunsite.mff.cuni.cz> Reply-To: Jakub Jelinek Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.4.2.2i Mailing-List: contact libc-hacker-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-hacker-owner@sourceware.org X-SW-Source: 2007-03/txt/msg00032.txt.bz2 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 [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 [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 and Ulrich Drepper , 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 , 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 , 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 , 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 , 1997. @@ -20,20 +20,29 @@ #include #include +#include +#include +#include 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 , 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 + +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 +#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 , 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 , 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