Merge branch 'fpe-without-sigfpe' into 'develop'

Fix floating point exceptions for systems without working feenableexcept

See merge request embeddable-common-lisp/ecl!177
This commit is contained in:
Daniel Kochmański 2020-01-12 10:30:09 +00:00
commit 9cf6e774a4
17 changed files with 202 additions and 84 deletions

47
src/aclocal.m4 vendored
View file

@ -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 <fenv.h>
#include <signal.h>
#include <stdlib.h>
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 <fenv.h>])])
LIBS="${saved_libs}"
fi])
dnl ----------------------------------------------------------------------
dnl Configure libatomic-ops
dnl

View file

@ -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"),

View file

@ -13,8 +13,6 @@
*
*/
/* for ECL_MATHERR_* */
#define ECL_INCLUDE_MATH_H
#include <ecl/ecl.h>
#include <stdlib.h>
#include <string.h>

View file

@ -23,26 +23,38 @@
#include <ecl/impl/math_fenv.h>
#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;

View file

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

View file

@ -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

94
src/configure vendored
View file

@ -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 <fenv.h>
"
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 <fenv.h>
"
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 <fenv.h>
#include <signal.h>
#include <stdlib.h>
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}

View file

@ -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 <fenv.h>])
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

View file

@ -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

View file

@ -263,4 +263,8 @@ will output
@verbatim
inf 0
@end verbatim
@subsubheading See also
@code{ext:trap-fpe}
@end defmac

View file

@ -303,7 +303,7 @@
/* Define to 1 if you have the <fcntl.h> header file. */
#undef HAVE_FCNTL_H
/* feenableexcept is available */
/* feenableexcept works */
#undef HAVE_FEENABLEEXCEPT
/* Define to 1 if you have the <fenv.h> header file. */

View file

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

View file

@ -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 */

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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)