Bug 10 - feclearexcept() error on CPUs with SSE
Summary: feclearexcept() error on CPUs with SSE
Status: RESOLVED FIXED
Alias: None
Product: glibc
Classification: Unclassified
Component: libc (show other bugs)
Version: 2.3.3
: P2 normal
Target Milestone: ---
Assignee: Ulrich Drepper
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2004-02-06 21:43 UTC by H.J. Lu
Modified: 2004-02-09 08:20 UTC (History)
0 users

See Also:
Host:
Target: i386
Build:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description H.J. Lu 2004-02-06 21:43:26 UTC
Steve Chaplin [stevech1097@yahoo.com.au] reported:

Problem/error message

#include <fenv.h>
void feclearexcept(int ex)

This function should clear the specified exception status bits in the
FPU status register.
For CPUs with SSE support it should also clear the MXCSR status register
bits.

The problem is that feclearexcept() clears the status control bits also,
causing future floating-point errors to generate interrupts which will
lead to a SIGFPE signal which terminates the program (unless caught by a
SIGFPE handler).

The program that follows illustrates the problem
When compiled on a SSE processor, such as an athlon-xp, with
'gcc -march=athlon-xp file.c'
It shows that:
The status bits change  - they are cleared - which is correct
The control bits change - this is the bug


Test program:
/* start or file */
#include <stdio.h>
#include <fenv.h>

int
main (void)
{
  int exc_control, exc_status;

  __asm__ ("stmxcsr %0" : "=m" (*&exc_control)); 
  exc_control = ~(exc_control >> 7) & FE_ALL_EXCEPT;
  // we cannot use:
  // exc_control = fegetexcept ();
  // since it does not return the SSE flags (that's another bug)

  /* raise all exceptions - set their status bit to on */
  feraiseexcept(FE_ALL_EXCEPT);
  exc_status = fetestexcept(FE_ALL_EXCEPT);

  printf ("Before\n");
  printf ("Exception control : %X\n", exc_control);
  printf ("Exception status  : %X\n", exc_status);

  feclearexcept (FE_ALL_EXCEPT);

  __asm__ ("stmxcsr %0" : "=m" (*&exc_control)); 
  exc_control = ~(exc_control >> 7) & FE_ALL_EXCEPT;
  exc_status  = fetestexcept(FE_ALL_EXCEPT);
  printf ("After\n");
  printf ("Exception control : %X\n", exc_control); // the bug - this
should not change
  printf ("Exception status  : %X\n", exc_status);  // this is supposed
to change to 0
}
/* end of file */
Comment 1 H.J. Lu 2004-02-06 21:47:27 UTC
This is the patch from Steve:

Index: fclrexcpt.c
===================================================================
RCS file: /cvs/glibc/libc/sysdeps/i386/fpu/fclrexcpt.c,v
retrieving revision 1.8
diff -u -r1.8 fclrexcpt.c
--- fclrexcpt.c	25 Sep 2003 05:57:16 -0000	1.8
+++ fclrexcpt.c	8 Jan 2004 13:28:26 -0000
@@ -50,7 +50,7 @@
       __asm__ ("stmxcsr %0" : "=m" (*&xnew_exc));
 
       /* Clear the relevant bits.  */
-      xnew_exc &= excepts ^ FE_ALL_EXCEPT;
+      xnew_exc &= ~excepts;
 
       /* Put the new data in effect.  */
       __asm__ ("ldmxcsr %0" : : "m" (*&xnew_exc));
Comment 2 Ulrich Drepper 2004-02-09 08:20:25 UTC
The test program isn't really testing what it is supposed to (the SSE status is
never touched) but the SSE control change is indeed wrong.