This is the mail archive of the
libc-alpha@sources.redhat.com
mailing list for the glibc project.
feenableexcept and FE_NOMASK_ENV are broken on i386
- From: Bruno Haible <bruno at clisp dot org>
- To: libc-alpha at sources dot redhat dot com
- Date: Fri, 31 May 2002 13:28:11 +0200 (CEST)
- Subject: feenableexcept and FE_NOMASK_ENV are broken on i386
Hi,
The function feenableexcept and the macro FE_NOMASK_ENV, both GNU extensions
in <fenv.h>, appear to be broken on i386.
1) fesetenv (FE_NOMASK_ENV) does not clear all interrupts.
$ echo '#define HAVE_LONGDOUBLE 1' > config.h
$ gcc -O2 -Wall fenvparam.c -lm -DTRY_FENV_H -DTRY_FESETNOMASK -D_GNU_SOURCE
$ ./a.out > /dev/null
whether integer divbyzero raises an exception... yes
whether single-float divbyzero raises an exception... yes
whether double-float divbyzero raises an exception... yes
whether long-float divbyzero raises an exception... yes
whether single-float overflow raises an exception... no
whether double-float overflow raises an exception... yes
whether long-float overflow raises an exception... yes
whether single-float underflow raises an exception... no
whether double-float underflow raises an exception... no
whether long-float underflow raises an exception... yes
whether single-float inexact raises an exception... yes
whether double-float inexact raises an exception... yes
whether long-float inexact raises an exception... yes
Apparently it disallows some cases of overflow and underflow exceptions
but not division by zero and inexact exceptions.
2) feenableexcept (FE_ALL_EXCEPT) does not enable overflow and underflow
checking for 'float', although it does for 'double' and 'long double'.
$ echo '#define HAVE_LONGDOUBLE 1' > config.h
$ gcc -O2 -Wall fenvparam.c -lm -DTRY_FENV_H -DTRY_FEENABLEEXCEPT -D_GNU_SOURCE
$ ./a.out > /dev/null
whether integer divbyzero raises an exception... yes
whether single-float divbyzero raises an exception... yes
whether double-float divbyzero raises an exception... yes
whether long-float divbyzero raises an exception... yes
whether single-float overflow raises an exception... no
whether double-float overflow raises an exception... yes
whether long-float overflow raises an exception... yes
whether single-float underflow raises an exception... no
whether double-float underflow raises an exception... yes
whether long-float underflow raises an exception... yes
whether single-float inexact raises an exception... yes
whether double-float inexact raises an exception... yes
whether long-float inexact raises an exception... yes
This occurs with glibc-20020425, on Linux 2.4.18, with either gcc 3.0.4
or gcc 3.1, and "cat /proc/cpuinfo" shows
processor : 0
vendor_id : AuthenticAMD
cpu family : 6
model : 1
model name : AMD-K7(tm) Processor
stepping : 2
cpu MHz : 503.544
cache size : 512 KB
fdiv_bug : no
hlt_bug : no
f00f_bug : no
coma_bug : no
fpu : yes
fpu_exception : yes
cpuid level : 1
wp : yes
flags : fpu vme de pse tsc msr pae mce cx8 sep mtrr pge mca cmov pat mmx syscall mmxext 3dnowext 3dnow
bogomips : 1002.70
Appended: The program fenvparam.c.
========================== fenvparam.c ======================================
/* Determine floating point environment. */
/* This program expects to be compiled by an ANSI C or C++ compiler. */
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <float.h>
#include <signal.h>
#include <setjmp.h>
#ifdef TRY_FPU_IEEE
#include <fpu_control.h>
fpu_control_t __fpu_control = _FPU_IEEE;
#endif
#ifdef TRY_FENV_H
#include <fenv.h>
#ifdef HAVE_PRAGMA_FENV_ACCESS
#pragma stdc fenv_access
#endif
#endif
static int step;
static sigjmp_buf sigfpe_exit;
static int caughtsig;
static void sigfpe_handler (int sig)
{
caughtsig = 1;
siglongjmp (sigfpe_exit, step);
}
static void install_sigfpe_handler (void)
{
signal (SIGFPE, sigfpe_handler);
#if (defined (__sgi) || defined (_AIX)) && defined (SIGTRAP)
signal (SIGTRAP, sigfpe_handler);
#endif
caughtsig = 0;
#ifdef TRY_FEHOLDEXCEPT
{ fenv_t dummy; feholdexcept (&dummy); }
#endif
#ifdef TRY_FESETNOMASK
fesetenv (FE_NOMASK_ENV);
#endif
#ifdef TRY_FEENABLEEXCEPT
feenableexcept (FE_ALL_EXCEPT);
#endif
#ifdef TRY_FEDISABLEEXCEPT
fedisableexcept (FE_ALL_EXCEPT);
#endif
}
int int_zero = 0;
int int_one = 1;
int int_res;
int int_nan;
float flt_zero = 0;
float flt_one = 1;
float flt_three = 3;
float flt_min = FLT_MIN;
float flt_max = FLT_MAX;
float flt_res;
float flt_nan;
double dbl_zero = 0;
double dbl_one = 1;
double dbl_three = 3;
double dbl_min = DBL_MIN;
double dbl_max = DBL_MAX;
double dbl_res;
double dbl_nan;
#ifdef HAVE_LONGDOUBLE
long double ldbl_zero = 0;
long double ldbl_one = 1;
long double ldbl_three = 3;
long double ldbl_min /*= LDBL_MIN*/;
long double ldbl_max /*= LDBL_MAX*/;
long double ldbl_res;
long double ldbl_nan;
#endif
int main ()
{
static const char *english[2] = { "no", "yes" };
static const char *boolstr[2] = { "false", "true" };
#ifdef HAVE_LONGDOUBLE
ldbl_min = LDBL_MIN;
ldbl_max = LDBL_MAX;
#endif
switch (setjmp (sigfpe_exit)) {
case 0:
step = 1;
fprintf (stderr, "whether integer divbyzero raises an exception...");
install_sigfpe_handler ();
int_res = int_one / int_zero;
int_nan = int_zero / int_zero;
case 1:
fprintf (stderr, " %s\n", english[caughtsig]);
printf ("#define int_divbyzero_exception %s\n", boolstr[caughtsig]);
step = 2;
fprintf (stderr, "whether single-float divbyzero raises an exception...");
install_sigfpe_handler ();
flt_res = flt_one / flt_zero;
flt_nan = flt_zero / flt_zero;
case 2:
fprintf (stderr, " %s\n", english[caughtsig]);
printf ("#define float_divbyzero_exception %s\n", boolstr[caughtsig]);
step = 3;
fprintf (stderr, "whether double-float divbyzero raises an exception...");
install_sigfpe_handler ();
dbl_res = dbl_one / dbl_zero;
dbl_nan = dbl_zero / dbl_zero;
case 3:
fprintf (stderr, " %s\n", english[caughtsig]);
printf ("#define double_divbyzero_exception %s\n", boolstr[caughtsig]);
#ifdef HAVE_LONGDOUBLE
step = 4;
fprintf (stderr, "whether long-float divbyzero raises an exception...");
install_sigfpe_handler ();
ldbl_res = ldbl_one / ldbl_zero;
ldbl_nan = ldbl_zero / ldbl_zero;
case 4:
fprintf (stderr, " %s\n", english[caughtsig]);
printf ("#define long_double_divbyzero_exception %s\n", boolstr[caughtsig]);
#endif
step = 12;
fprintf (stderr, "whether single-float overflow raises an exception...");
install_sigfpe_handler ();
flt_res = flt_max * flt_max;
case 12:
fprintf (stderr, " %s\n", english[caughtsig]);
printf ("#define float_overflow_exception %s\n", boolstr[caughtsig]);
step = 13;
fprintf (stderr, "whether double-float overflow raises an exception...");
install_sigfpe_handler ();
dbl_res = dbl_max * dbl_max;
case 13:
fprintf (stderr, " %s\n", english[caughtsig]);
printf ("#define double_overflow_exception %s\n", boolstr[caughtsig]);
#ifdef HAVE_LONGDOUBLE
step = 14;
fprintf (stderr, "whether long-float overflow raises an exception...");
install_sigfpe_handler ();
ldbl_res = ldbl_max * ldbl_max;
case 14:
fprintf (stderr, " %s\n", english[caughtsig]);
printf ("#define long_double_overflow_exception %s\n", boolstr[caughtsig]);
#endif
step = 22;
fprintf (stderr, "whether single-float underflow raises an exception...");
install_sigfpe_handler ();
flt_res = flt_min * flt_min;
case 22:
fprintf (stderr, " %s\n", english[caughtsig]);
printf ("#define float_underflow_exception %s\n", boolstr[caughtsig]);
step = 23;
fprintf (stderr, "whether double-float underflow raises an exception...");
install_sigfpe_handler ();
dbl_res = dbl_min * dbl_min;
case 23:
fprintf (stderr, " %s\n", english[caughtsig]);
printf ("#define double_underflow_exception %s\n", boolstr[caughtsig]);
#ifdef HAVE_LONGDOUBLE
step = 24;
fprintf (stderr, "whether long-float underflow raises an exception...");
install_sigfpe_handler ();
ldbl_res = ldbl_min * ldbl_min;
case 24:
fprintf (stderr, " %s\n", english[caughtsig]);
printf ("#define long_double_underflow_exception %s\n", boolstr[caughtsig]);
#endif
step = 32;
fprintf (stderr, "whether single-float inexact raises an exception...");
install_sigfpe_handler ();
flt_res = flt_one / flt_three;
case 32:
fprintf (stderr, " %s\n", english[caughtsig]);
printf ("#define float_inexact_exception %s\n", boolstr[caughtsig]);
step = 33;
fprintf (stderr, "whether double-float inexact raises an exception...");
install_sigfpe_handler ();
dbl_res = dbl_one / dbl_three;
case 33:
fprintf (stderr, " %s\n", english[caughtsig]);
printf ("#define double_inexact_exception %s\n", boolstr[caughtsig]);
#ifdef HAVE_LONGDOUBLE
step = 34;
fprintf (stderr, "whether long-float inexact raises an exception...");
install_sigfpe_handler ();
ldbl_res = ldbl_one / ldbl_three;
case 34:
fprintf (stderr, " %s\n", english[caughtsig]);
printf ("#define long_double_inexact_exception %s\n", boolstr[caughtsig]);
#endif
}
return 0;
}