This is the mail archive of the libc-alpha@sources.redhat.com mailing list for the glibc project.


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

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;
}


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