dnl -*- Autoconf -*-
dnl Copyright (C) 2002-2008, 2017 Free Software Foundation, Inc.
dnl This file is free software, distributed under the terms of the GNU
dnl General Public License.  As a special exception to the GNU General
dnl Public License, this file may be distributed as part of a program
dnl that contains a configuration script generated by Autoconf, under
dnl the same distribution terms as the rest of that program.

dnl From Bruno Haible, Sam Steingold.

AC_PREREQ([2.61])

dnl Each of the macros determines a facet of the default floating-point
dnl environment.
dnl   CL_FLOAT_DIV0        CL_DOUBLE_DIV0        CL_LONGDOUBLE_DIV0
dnl   CL_FLOAT_OVERFLOW    CL_DOUBLE_OVERFLOW    CL_LONGDOUBLE_OVERFLOW
dnl   CL_FLOAT_UNDERFLOW   CL_DOUBLE_UNDERFLOW   CL_LONGDOUBLE_UNDERFLOW
dnl   CL_FLOAT_INEXACT     CL_DOUBLE_INEXACT     CL_LONGDOUBLE_INEXACT

m4_define([CL_FENV_SIGNAL_INSTALL],
[signal (SIGFPE, sigfpe_handler);
 #if (defined (__sgi) || defined (_AIX)) && defined (SIGTRAP)
   signal (SIGTRAP, sigfpe_handler);
 #endif
])

AC_DEFUN([CL_FENV_CHECK],
[
  AC_CACHE_CHECK([whether $1],[$2],
    [AC_RUN_IFELSE(
       [AC_LANG_SOURCE([
          #include <stdlib.h>
          #include <signal.h>
          static void sigfpe_handler (int sig) { exit (1); }
          $3
          ])
       ],
       [$2=no],
       [$2=yes],
       [$2="guessing no"])
    ])
])

AC_DEFUN([CL_FLOAT_DIV0],
[
  CL_FENV_CHECK([single-float divbyzero raises an exception],
    [cl_cv_cc_float_divbyzero],
    [
     float x = 1;
     float y = 0;
     float z;
     float nan;
     int main ()
     {
       CL_FENV_SIGNAL_INSTALL
       z = x / y; nan = y / y;
       return 0;
     }
    ])
  if test "$cl_cv_cc_float_divbyzero" = yes; then
    AC_DEFINE([FLOAT_DIV0_EXCEPTION], [1],
      [Define to 1 if 'float' division by zero raises an exception.])
  fi
])

AC_DEFUN([CL_DOUBLE_DIV0],
[
  CL_FENV_CHECK([double-float divbyzero raises an exception],
    [cl_cv_cc_double_divbyzero],
    [
     double x = 1;
     double y = 0;
     double z;
     double nan;
     int main ()
     {
       CL_FENV_SIGNAL_INSTALL
       z = x / y; nan = y / y;
       return 0;
     }
    ])
  if test "$cl_cv_cc_double_divbyzero" = yes; then
    AC_DEFINE([DOUBLE_DIV0_EXCEPTION], [1],
      [Define to 1 if 'double' division by zero raises an exception.])
  fi
])

AC_DEFUN([CL_LONGDOUBLE_DIV0],
[
  CL_FENV_CHECK([long-float divbyzero raises an exception],
    [cl_cv_cc_longdouble_divbyzero],
    [
     long double x = 1;
     long double y = 0;
     long double z;
     long double nan;
     int main ()
     {
       CL_FENV_SIGNAL_INSTALL
       z = x / y; nan = y / y;
       return 0;
     }
    ])
  if test "$cl_cv_cc_longdouble_divbyzero" = yes; then
    AC_DEFINE([LONGDOUBLE_DIV0_EXCEPTION], [1],
      [Define to 1 if 'long double' division by zero raises an exception.])
  fi
])


AC_DEFUN([CL_FLOAT_OVERFLOW],
[
  CL_FENV_CHECK([single-float overflow raises an exception],
    [cl_cv_cc_float_overflow],
    [
     #include <float.h>
     float x = FLT_MAX;
     float y = FLT_MAX;
     float z;
     int main ()
     {
       CL_FENV_SIGNAL_INSTALL
       z = x * y;
       return 0;
     }
    ])
  if test "$cl_cv_cc_float_overflow" = yes; then
    AC_DEFINE([FLOAT_OVERFLOW_EXCEPTION], [1],
      [Define to 1 if 'float' overflow raises an exception.])
  fi
])

AC_DEFUN([CL_DOUBLE_OVERFLOW],
[
  CL_FENV_CHECK([double-float overflow raises an exception],
    [cl_cv_cc_double_overflow],
    [
     #include <float.h>
     double x = DBL_MAX;
     double y = DBL_MAX;
     double z;
     int main ()
     {
       CL_FENV_SIGNAL_INSTALL
       z = x * y;
       return 0;
     }
    ])
  if test "$cl_cv_cc_double_overflow" = yes; then
    AC_DEFINE([DOUBLE_OVERFLOW_EXCEPTION], [1],
      [Define to 1 if 'double' overflow raises an exception.])
  fi
])

AC_DEFUN([CL_LONGDOUBLE_OVERFLOW],
[
  CL_FENV_CHECK([long-float overflow raises an exception],
    [cl_cv_cc_longdouble_overflow],
    [
     #include <float.h>
     long double x;
     long double y;
     long double z;
     int main ()
     {
       x = LDBL_MAX;
       y = LDBL_MAX;
       CL_FENV_SIGNAL_INSTALL
       z = x * y;
       return 0;
     }
    ])
  if test "$cl_cv_cc_longdouble_overflow" = yes; then
    AC_DEFINE([LONGDOUBLE_OVERFLOW_EXCEPTION], [1],
      [Define to 1 if 'long double' overflow raises an exception.])
  fi
])


AC_DEFUN([CL_FLOAT_UNDERFLOW],
[
  CL_FENV_CHECK([single-float underflow raises an exception],
    [cl_cv_cc_float_underflow],
    [
     #include <float.h>
     float x = FLT_MIN;
     float y = FLT_MIN;
     float z;
     int main ()
     {
       CL_FENV_SIGNAL_INSTALL
       z = x * y;
       return 0;
     }
    ])
  if test "$cl_cv_cc_float_underflow" = yes; then
    AC_DEFINE([FLOAT_UNDERFLOW_EXCEPTION], [1],
      [Define to 1 if 'float' underflow raises an exception.])
  fi
])

AC_DEFUN([CL_DOUBLE_UNDERFLOW],
[
  CL_FENV_CHECK([double-float underflow raises an exception],
    [cl_cv_cc_double_underflow],
    [
     #include <float.h>
     double x = DBL_MIN;
     double y = DBL_MIN;
     double z;
     int main ()
     {
       CL_FENV_SIGNAL_INSTALL
       z = x * y;
       return 0;
     }
    ])
  if test "$cl_cv_cc_double_underflow" = yes; then
    AC_DEFINE([DOUBLE_UNDERFLOW_EXCEPTION], [1],
      [Define to 1 if 'double' underflow raises an exception.])
  fi
])

AC_DEFUN([CL_LONGDOUBLE_UNDERFLOW],
[
  CL_FENV_CHECK([long-float underflow raises an exception],
    [cl_cv_cc_longdouble_underflow],
    [
     #include <float.h>
     long double x;
     long double y;
     long double z;
     int main ()
     {
       x = LDBL_MIN;
       y = LDBL_MIN;
       CL_FENV_SIGNAL_INSTALL
       z = x * y;
       return 0;
     }
    ])
  if test "$cl_cv_cc_longdouble_underflow" = yes; then
    AC_DEFINE([LONGDOUBLE_UNDERFLOW_EXCEPTION], [1],
      [Define to 1 if 'long double' underflow raises an exception.])
  fi
])


AC_DEFUN([CL_FLOAT_INEXACT],
[
  CL_FENV_CHECK([single-float inexact raises an exception],
    [cl_cv_cc_float_inexact],
    [
     float x = 1;
     float y = 3;
     float z;
     int main ()
     {
       CL_FENV_SIGNAL_INSTALL
       z = x / y;
       return 0;
     }
    ])
  if test "$cl_cv_cc_float_inexact" = yes; then
    AC_DEFINE([FLOAT_INEXACT_EXCEPTION], [1],
      [Define to 1 if a 'float' inexact operation raises an exception.])
  fi
])

AC_DEFUN([CL_DOUBLE_INEXACT],
[
  CL_FENV_CHECK([double-float inexact raises an exception],
    [cl_cv_cc_double_inexact],
    [
     double x = 1;
     double y = 3;
     double z;
     int main ()
     {
       CL_FENV_SIGNAL_INSTALL
       z = x / y;
       return 0;
     }
    ])
  if test "$cl_cv_cc_double_inexact" = yes; then
    AC_DEFINE([DOUBLE_INEXACT_EXCEPTION], [1],
      [Define to 1 if a 'double' inexact operation raises an exception.])
  fi
])

AC_DEFUN([CL_LONGDOUBLE_INEXACT],
[
  CL_FENV_CHECK([long-float inexact raises an exception],
    [cl_cv_cc_longdouble_inexact],
    [
     long double x = 1;
     long double y = 3;
     long double z;
     int main ()
     {
       CL_FENV_SIGNAL_INSTALL
       z = x / y;
       return 0;
     }
    ])
  if test "$cl_cv_cc_longdouble_inexact" = yes; then
    AC_DEFINE([LONGDOUBLE_INEXACT_EXCEPTION], [1],
      [Define to 1 if a 'long double' inexact operation raises an exception.])
  fi
])
