diff --git a/src/aclocal.m4 b/src/aclocal.m4 index d1e626a77..dae305572 100644 --- a/src/aclocal.m4 +++ b/src/aclocal.m4 @@ -939,6 +939,53 @@ if test $ECL_WORKING_ENVIRON = yes ; then fi ]) +dnl +dnl -------------------------------------------------------------- +dnl Check if we have feenableexcept and the hardware generates +dnl floating point exceptions. +dnl +AC_DEFUN(ECL_FLOATING_POINT_EXCEPTIONS,[ + if test "${with_fpe}" = "yes" ; then + AC_MSG_CHECKING(for working feenableexcept) + saved_libs="${LIBS}" + LIBS="-lm" + AC_RUN_IFELSE([AC_LANG_SOURCE([[ + +#define _GNU_SOURCE +#include +#include +#include + +const int traps = FE_DIVBYZERO | FE_OVERFLOW; + +void fpe_handler(int code) { + if (code == SIGFPE) + exit(0); +} + +double raises_fpe(double x) { + return x / 0.0; +} + +int main() { + signal(SIGFPE, fpe_handler); + feclearexcept(traps); + feenableexcept(traps); + raises_fpe(1.0); + return 1; +} +]])], + [AC_DEFINE([HAVE_FEENABLEEXCEPT], [], [feenableexcept works]) + AC_MSG_RESULT(yes)], + [AC_MSG_RESULT(no)], + [AC_MSG_RESULT(only checking if feenableexcept is present due to cross compilation) + AC_CHECK_DECL([feenableexcept], + [AC_DEFINE(HAVE_FEENABLEEXCEPT,[],[feenableexcept is declared])], + [], + [#include ])]) + LIBS="${saved_libs}" + fi]) + dnl ---------------------------------------------------------------------- dnl Configure libatomic-ops dnl diff --git a/src/c/ecl_features.h b/src/c/ecl_features.h index c9b0ef24c..963d007d0 100644 --- a/src/c/ecl_features.h +++ b/src/c/ecl_features.h @@ -22,6 +22,9 @@ ecl_def_string_array(feature_names,static,const) = { ecl_def_string_array_elt("PACKAGE-LOCAL-NICKNAMES"), #ifdef ECL_IEEE_FP ecl_def_string_array_elt("IEEE-FLOATING-POINT"), +#endif +#if !defined(ECL_IEEE_FP) || !defined(ECL_AVOID_FPE_H) + ecl_def_string_array_elt("FLOATING-POINT-EXCEPTIONS"), #endif ecl_def_string_array_elt("COMMON-LISP"), ecl_def_string_array_elt("ANSI-CL"), diff --git a/src/c/hash.d b/src/c/hash.d index f121c648d..f580b72f5 100644 --- a/src/c/hash.d +++ b/src/c/hash.d @@ -13,8 +13,6 @@ * */ -/* for ECL_MATHERR_* */ -#define ECL_INCLUDE_MATH_H #include #include #include diff --git a/src/c/number.d b/src/c/number.d index 6287d3fe4..69723e55a 100644 --- a/src/c/number.d +++ b/src/c/number.d @@ -23,26 +23,38 @@ #include #if defined(ECL_IEEE_FP) -# if defined(HAVE_FEENABLEEXCEPT) +# if defined(ECL_AVOID_FPE_H) +/* + * We don't check for floating point exceptions + */ +# define DO_DETECT_FPE(f) +# define DO_DETECT_FPE2(f1,f2) +# elif defined(HAVE_FEENABLEEXCEPT) /* * We are using IEEE arithmetics and can rely on FPE exceptions * to be raised when invalid operations are performed. */ # define DO_DETECT_FPE(f) ecl_detect_fpe() +# define DO_DETECT_FPE2(f1,f2) DO_DETECT_FPE(f1) # else /* - * Floating point exceptions are disabled + * We need explicit checks for floating point exception bits being set */ -# define DO_DETECT_FPE(f) +# define DO_DETECT_FPE(f) do { \ + int status = fetestexcept(ecl_process_env()->trap_fpe_bits); \ + unlikely_if (status) ecl_deliver_fpe(status); \ + } while (0) +# define DO_DETECT_FPE2(f1,f2) DO_DETECT_FPE(f1) # endif #else /* * We do not want IEEE NaNs and infinities */ -# define DO_DETECT_FPE(f) do { \ - unlikely_if (isnan(f)) ecl_deliver_fpe(FE_INVALID); \ - unlikely_if (!isfinite(f)) ecl_deliver_fpe(FE_OVERFLOW); \ +# define DO_DETECT_FPE(f) do { \ + unlikely_if (isnan(f)) ecl_deliver_fpe(FE_INVALID); \ + unlikely_if (!isfinite(f)) ecl_deliver_fpe(FE_OVERFLOW); \ } while (0) +# define DO_DETECT_FPE2(f1,f2) DO_DETECT_FPE(f1); DO_DETECT_FPE(f2) #endif #if !ECL_CAN_INLINE @@ -618,8 +630,7 @@ si_complex_float(cl_object r, cl_object i) } cl_object ecl_make_csfloat(float _Complex x) { - DO_DETECT_FPE(crealf(x)); - DO_DETECT_FPE(cimagf(x)); + DO_DETECT_FPE2(crealf(x), cimagf(x)); cl_object c = ecl_alloc_object(t_csfloat); ecl_csfloat(c) = x; @@ -627,8 +638,7 @@ cl_object ecl_make_csfloat(float _Complex x) { } cl_object ecl_make_cdfloat(double _Complex x) { - DO_DETECT_FPE(creal(x)); - DO_DETECT_FPE(cimag(x)); + DO_DETECT_FPE2(creal(x), cimag(x)); cl_object c = ecl_alloc_object(t_cdfloat); ecl_cdfloat(c) = x; @@ -636,8 +646,7 @@ cl_object ecl_make_cdfloat(double _Complex x) { } cl_object ecl_make_clfloat(long double _Complex x) { - DO_DETECT_FPE(creall(x)); - DO_DETECT_FPE(cimagl(x)); + DO_DETECT_FPE2(creall(x), cimagl(x)); cl_object c = ecl_alloc_object(t_clfloat); ecl_clfloat(c) = x; diff --git a/src/c/numbers/atan.d b/src/c/numbers/atan.d index e63bc8a5e..e4c3b3269 100644 --- a/src/c/numbers/atan.d +++ b/src/c/numbers/atan.d @@ -24,27 +24,23 @@ cl_object ecl_atan2(cl_object y, cl_object x) { cl_object output; - ECL_MATHERR_CLEAR; - { - int tx = ecl_t_of(x); - int ty = ecl_t_of(y); - if (tx < ty) - tx = ty; - if (tx == t_longfloat) { - long double d = atan2l(ecl_to_long_double(y), ecl_to_long_double(x)); - output = ecl_make_long_float(d); + int tx = ecl_t_of(x); + int ty = ecl_t_of(y); + if (tx < ty) + tx = ty; + if (tx == t_longfloat) { + long double d = atan2l(ecl_to_long_double(y), ecl_to_long_double(x)); + output = ecl_make_long_float(d); + } else { + double dx = ecl_to_double(x); + double dy = ecl_to_double(y); + double dz = atan2(dy, dx); + if (tx == t_doublefloat) { + output = ecl_make_double_float(dz); } else { - double dx = ecl_to_double(x); - double dy = ecl_to_double(y); - double dz = atan2(dy, dx); - if (tx == t_doublefloat) { - output = ecl_make_double_float(dz); - } else { - output = ecl_make_single_float(dz); - } + output = ecl_make_single_float(dz); } } - ECL_MATHERR_TEST; return output; } diff --git a/src/c/numbers/expt.d b/src/c/numbers/expt.d index d35817df5..cb83ada17 100644 --- a/src/c/numbers/expt.d +++ b/src/c/numbers/expt.d @@ -100,7 +100,6 @@ ecl_expt_generic(cl_object x, cl_object y) { if (minusp) { y = ecl_negate(y); } - ECL_MATHERR_CLEAR; do { /* INV: ecl_integer_divide outputs an integer */ if (!ecl_evenp(y)) { @@ -113,7 +112,6 @@ ecl_expt_generic(cl_object x, cl_object y) { } x = ecl_times(x, x); } while (1); - ECL_MATHERR_TEST; } static cl_object diff --git a/src/configure b/src/configure index 7864bb403..6cfa5b772 100755 --- a/src/configure +++ b/src/configure @@ -741,6 +741,7 @@ infodir docdir oldincludedir includedir +runstatedir localstatedir sharedstatedir sysconfdir @@ -866,6 +867,7 @@ datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' +runstatedir='${localstatedir}/run' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' @@ -1118,6 +1120,15 @@ do | -silent | --silent | --silen | --sile | --sil) silent=yes ;; + -runstatedir | --runstatedir | --runstatedi | --runstated \ + | --runstate | --runstat | --runsta | --runst | --runs \ + | --run | --ru | --r) + ac_prev=runstatedir ;; + -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ + | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ + | --run=* | --ru=* | --r=*) + runstatedir=$ac_optarg ;; + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ @@ -1255,7 +1266,7 @@ fi for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ - libdir localedir mandir + libdir localedir mandir runstatedir do eval ac_val=\$$ac_var # Remove trailing slashes. @@ -1408,6 +1419,7 @@ Fine tuning of the installation directories: --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] @@ -1525,7 +1537,7 @@ Optional Packages: --with-signed-zero={yes|no} allow for IEEE signed zeros (default=YES). --with-ieee-fp={yes|no} full IEEE floating point system, including denormals - (default=YES). Implies signed-zero and fpe + (default=YES). Implies signed-zero --with-sse={yes|no|auto} implement SSE intrinsics in ECL (default=NO). Only works when supported by the compiler @@ -6499,7 +6511,6 @@ ECL_VERSION_NUMBER=$(($PACKAGE_MAJOR * 10000 + $PACKAGE_MINOR * 100 + $PACKAGE_L if test "${with_ieee_fp}" = yes; then with_signed_zero="yes" - with_fpe="yes" $as_echo "#define ECL_IEEE_FP /**/" >>confdefs.h @@ -8996,6 +9007,8 @@ main () if (*(data + i) != *(data3 + i)) return 14; close (fd); + free (data); + free (data3); return 0; } _ACEOF @@ -9443,17 +9456,6 @@ _ACEOF fi done -ac_fn_c_check_decl "$LINENO" "feenableexcept" "ac_cv_have_decl_feenableexcept" "#include -" -if test "x$ac_cv_have_decl_feenableexcept" = xyes; then : - -$as_echo "#define HAVE_FEENABLEEXCEPT /**/" >>confdefs.h - -else - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: feenableexcept not declared: disabling floating point exceptions" >&5 -$as_echo "$as_me: WARNING: feenableexcept not declared: disabling floating point exceptions" >&2;} -fi - for ac_func in expf powf logf sqrtf cosf sinf tanf sinhf coshf tanhf \ floorf ceilf fabsf frexpf ldexpf log1p log1pf log1pl \ @@ -9537,6 +9539,70 @@ fi + if test "${with_fpe}" = "yes" ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working feenableexcept" >&5 +$as_echo_n "checking for working feenableexcept... " >&6; } + saved_libs="${LIBS}" + LIBS="-lm" + if test "$cross_compiling" = yes; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: only checking if feenableexcept is present due to cross compilation" >&5 +$as_echo "only checking if feenableexcept is present due to cross compilation" >&6; } + ac_fn_c_check_decl "$LINENO" "feenableexcept" "ac_cv_have_decl_feenableexcept" "#include +" +if test "x$ac_cv_have_decl_feenableexcept" = xyes; then : + +$as_echo "#define HAVE_FEENABLEEXCEPT /**/" >>confdefs.h + +fi + +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#define _GNU_SOURCE +#include +#include +#include + +const int traps = FE_DIVBYZERO | FE_OVERFLOW; + +void fpe_handler(int code) { + if (code == SIGFPE) + exit(0); +} + +double raises_fpe(double x) { + return x / 0.0; +} + +int main() { + signal(SIGFPE, fpe_handler); + feclearexcept(traps); + feenableexcept(traps); + raises_fpe(1.0); + return 1; +} + +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + +$as_echo "#define HAVE_FEENABLEEXCEPT /**/" >>confdefs.h + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + LIBS="${saved_libs}" + fi + + if test ${with_cxx} = "no" ; then ECL_CC=${CC} diff --git a/src/configure.ac b/src/configure.ac index 84c45229e..b81ebb093 100644 --- a/src/configure.ac +++ b/src/configure.ac @@ -215,7 +215,7 @@ AC_ARG_WITH(signed-zero, AC_ARG_WITH(ieee-fp, AS_HELP_STRING( [--with-ieee-fp={yes|no}], [full IEEE floating point system, including denormals (default=YES).] - [Implies signed-zero and fpe]), + [Implies signed-zero]), [], [with_ieee_fp="yes"]) AC_ARG_WITH(sse, @@ -633,7 +633,6 @@ dnl ---------------------------------------------------------------------- dnl Deactivate floating point exceptions if asked to if test "${with_ieee_fp}" = yes; then with_signed_zero="yes" - with_fpe="yes" AC_DEFINE([ECL_IEEE_FP], [], [ECL_IEEE_FP]) fi if test "${with_fpe}" != yes; then @@ -738,10 +737,6 @@ dnl !!! end autoscan AC_CHECK_FUNCS( [nanosleep alarm times select setenv putenv] \ [lstat mkstemp sigprocmask isatty tzset] \ [gettimeofday getrusage system] ) -AC_CHECK_DECL([feenableexcept], - [AC_DEFINE(HAVE_FEENABLEEXCEPT,[],[feenableexcept is available])], - [AC_MSG_WARN(feenableexcept not declared: disabling floating point exceptions)], - [#include ]) AC_CHECK_FUNCS( [expf powf logf sqrtf cosf sinf tanf sinhf coshf tanhf] \ [floorf ceilf fabsf frexpf ldexpf log1p log1pf log1pl] \ @@ -756,6 +751,8 @@ AC_CHECK_HEADER( [sys/mman.h], ECL_POSIX_ENVIRON +ECL_FLOATING_POINT_EXCEPTIONS + dnl ===================================================================== dnl Checks for system services diff --git a/src/doc/manual/standards/numbers.txi b/src/doc/manual/standards/numbers.txi index 049f5582e..33f67ae7b 100644 --- a/src/doc/manual/standards/numbers.txi +++ b/src/doc/manual/standards/numbers.txi @@ -55,17 +55,20 @@ ratios all complex numbers are pairs of numbers. @subsection Floating point exceptions ECL supports two ways of dealing with special floating point values, such as Not a Number (NaN), infinity or denormalized floats, which can -occur in floating point computations. Either a condition is signaled -or the value is silently used as it is. There are multiple options +occur in floating point computations. Either a condition is signaled or +the value is silently used as it is. There are multiple options controlling which behaviour is selected: If ECL is built with the -@code{--with-ieee-fp=no} configure option, then a condition is -signaled for every infinity or NaN encountered. If not, the behaviour -can be controlled by @code{ext:trap-fpe}. By default, a condition is -signaled for invalid operation, division by zero and floating point -overflows. If the @code{ECL_OPT_TRAP_SIGFPE} option is false, no -conditions are signaled by default (Note that in this case, if you -enable trapping of floating point exceptions with @code{ext:trap-fpe}, -then you have to install your own signal handler). +@code{--without-ieee-fp} configure option, then a condition is signaled +for every infinity or NaN encountered. If not, floating point exceptions +can be disabled at build time using the @code{--without-fpe} configure +option. Otherwise, if both @code{--with-ieee-fp} and @code{--with-fpe} +options are on, by default, a condition is signaled for invalid +operation, division by zero and floating point overflows. This can be +changed at runtime by using @code{ext:trap-fpe}. If the +@code{ECL_OPT_TRAP_SIGFPE} boot option is false, no conditions are +signaled by default (Note that in this case, if you enable trapping of +floating point exceptions with @code{ext:trap-fpe}, then you have to +install your own signal handler). @lspindex ext:trap-fpe @defun ext:trap-fpe condition flag @@ -91,6 +94,10 @@ floating point exception for the conditions passed in @var{condition}. @var{condition} can be either a symbol denoting a single condition, @code{t} for all conditions that are enabled by default or a value obtained from an earlier call to @code{ext:trap-fpe} with @code{last}. + +@subsubheading See also +@code{ECL_WITH_LISP_FPE} + @end defun @node Numbers - Random-States diff --git a/src/doc/manual/user-guide/embedding.txi b/src/doc/manual/user-guide/embedding.txi index 78e41daab..3be294746 100644 --- a/src/doc/manual/user-guide/embedding.txi +++ b/src/doc/manual/user-guide/embedding.txi @@ -263,4 +263,8 @@ will output @verbatim inf 0 @end verbatim + +@subsubheading See also +@code{ext:trap-fpe} + @end defmac diff --git a/src/ecl/configpre.h b/src/ecl/configpre.h index 41c737dc2..c573e5fd7 100644 --- a/src/ecl/configpre.h +++ b/src/ecl/configpre.h @@ -303,7 +303,7 @@ /* Define to 1 if you have the header file. */ #undef HAVE_FCNTL_H -/* feenableexcept is available */ +/* feenableexcept works */ #undef HAVE_FEENABLEEXCEPT /* Define to 1 if you have the header file. */ diff --git a/src/h/impl/math_dispatch.h b/src/h/impl/math_dispatch.h index 6acf3cffe..a1ee0fca2 100644 --- a/src/h/impl/math_dispatch.h +++ b/src/h/impl/math_dispatch.h @@ -63,9 +63,7 @@ typedef cl_object (*math_one_arg_fn)(cl_object); cl_object ecl_##name(cl_object arg) \ { \ cl_object out; \ - ECL_MATHERR_CLEAR; \ out = ecl_##name##_ne(arg); \ - ECL_MATHERR_TEST; \ return out; \ } diff --git a/src/h/impl/math_fenv.h b/src/h/impl/math_fenv.h index a97b8409c..c916ebe43 100644 --- a/src/h/impl/math_fenv.h +++ b/src/h/impl/math_fenv.h @@ -87,17 +87,4 @@ # define ECL_WITH_LISP_FPE_END } while (0) #endif -#if defined(HAVE_FENV_H) && !defined(HAVE_FEENABLEEXCEPT) && !defined(ECL_AVOID_FPE_H) -# define ECL_USED_EXCEPTIONS (FE_DIVBYZERO|FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW) -# define ECL_MATHERR_CLEAR feclearexcept(FE_ALL_EXCEPT) -# define ECL_MATHERR_TEST do { \ - int bits = fetestexcept(ECL_USED_EXCEPTIONS); \ - unlikely_if (bits) ecl_deliver_fpe(bits); } while(0) -#else -# define ECL_MATHERR_CLEAR -# define ECL_MATHERR_TEST -#endif - -extern void ecl_deliver_fpe(int flags); - #endif /* !ECL_MATH_FENV_H */ diff --git a/src/tests/normal-tests/compiler.lsp b/src/tests/normal-tests/compiler.lsp index 305816804..18317f48b 100644 --- a/src/tests/normal-tests/compiler.lsp +++ b/src/tests/normal-tests/compiler.lsp @@ -1238,6 +1238,7 @@ ;;; ;;; On some platforms (without feenableexcept) compiling code with ;;; constants being infinity cause fpe-exception. +#+ieee-floating-point (test cmp.0056.artificial-fpe (finishes (funcall (compile nil diff --git a/src/tests/normal-tests/complex.lsp b/src/tests/normal-tests/complex.lsp index fe716cd5f..d2276acbc 100644 --- a/src/tests/normal-tests/complex.lsp +++ b/src/tests/normal-tests/complex.lsp @@ -224,9 +224,13 @@ ;; exp, sqrt, log and log1p (finishes (mapc (lambda (cf) (exp cf)) all-cfloats) "exp1") (finishes (mapc (lambda (cf) (sqrt cf)) all-cfloats) "sqrt") - (finishes (mapc (lambda (cf) (if (zerop cf) - (signals division-by-zero (log cf)) - (log cf))) + (finishes (mapc (lambda (cf) + #+floating-point-exceptions + (if (zerop cf) + (signals division-by-zero (log cf)) + (log cf)) + #-floating-point-exceptions + (log cf)) all-cfloats) "log1") (finishes (mapc (lambda (cf) (si:log1p cf)) all-cfloats) "log1p") ;; log operations on floats should give corresponding cfloat type diff --git a/src/tests/normal-tests/ieee-fp.lsp b/src/tests/normal-tests/ieee-fp.lsp index 401a6187d..733f28538 100644 --- a/src/tests/normal-tests/ieee-fp.lsp +++ b/src/tests/normal-tests/ieee-fp.lsp @@ -332,6 +332,7 @@ Common Lisp type contagion rules." ;;; ... but we don't, therefore everything throws arithmetic errors. +#+floating-point-exceptions (test ieee-fp.0010.NaN-floor/ceiling/truncate/round/mod/rem (loop :for function :in '(floor ceiling truncate round ffloor fceiling ftruncate fround @@ -347,6 +348,7 @@ Common Lisp type contagion rules." (for-all-number-subtypes (x float 0) (signals arithmetic-error (funcall function x x))))) +#+floating-point-exceptions (test ieee-fp.0011.infinity-floor/ceiling/truncate/round (loop :for function :in '(floor ceiling truncate round ffloor fceiling ftruncate fround diff --git a/src/tests/normal-tests/mixed.lsp b/src/tests/normal-tests/mixed.lsp index 3e91a7596..3b91ab68f 100644 --- a/src/tests/normal-tests/mixed.lsp +++ b/src/tests/normal-tests/mixed.lsp @@ -191,10 +191,11 @@ ;;; Date: 2016-12-21 ;;; Description: ;;; -;;; `sleep' sues `ECL_WITHOUT_FPE_BEGIN' which didn't restore fpe +;;; `sleep' uses `ECL_WITHOUT_FPE_BEGIN' which didn't restore fpe ;;; correctly. ;;; ;;; Bug: https://gitlab.com/embeddable-common-lisp/ecl/issues/317 +#+floating-point-exceptions (test mix.0013.sleep-without-fpe (sleep 0.1) (let ((a 1.0)