diff --git a/src/c/print.d b/src/c/print.d index cfc4a69bc..6548310e3 100644 --- a/src/c/print.d +++ b/src/c/print.d @@ -483,6 +483,10 @@ edit_double(int n, double d, int *sp, char *s, int *ep) { char *exponent, *p, buff[DBL_SIZE + 1]; int length; +#if defined(HAVE_FENV_H) || defined(_MSC_VER) || defined(mingw32) + fenv_t env; + feholdexcept(&env); +#endif if (isnan(d) || !finite(d)) FEerror("Can't print a non-number.", 0); @@ -530,6 +534,9 @@ edit_double(int n, double d, int *sp, char *s, int *ep) s[i] = '0'; } s[n] = '\0'; +#if defined(HAVE_FENV_H) || defined(_MSC_VER) || defined(mingw32) + fesetenv(&env); +#endif return length; } diff --git a/src/c/unixint.d b/src/c/unixint.d index b540c566a..072cd1979 100644 --- a/src/c/unixint.d +++ b/src/c/unixint.d @@ -15,7 +15,7 @@ */ #include -#ifdef HAVE_FENV_H +#if defined(HAVE_FENV_H) # define _GNU_SOURCE # include # ifndef FE_UNDERFLOW @@ -39,6 +39,7 @@ #include #if defined(mingw32) || defined(_MSC_VER) # include +void handle_fpe_signal(int,int); #endif #if !defined(_MSC_VER) # include @@ -129,7 +130,7 @@ signal_catcher(int sig) { if (!ecl_interrupt_enable || symbol_value(@'si::*interrupt-enable*') == Cnil) { - signal(sig, signal_catcher); + mysignal(sig, signal_catcher); cl_env.interrupt_pending = sig; return; } @@ -148,6 +149,11 @@ signal_catcher(int sig) #endif } CL_UNWIND_PROTECT_END; #else +#if defined (_MSC_VER) + if (sig == SIGFPE) { + handle_fpe_signal(sig, _fpecode); + } +#endif handle_signal(sig); #endif } @@ -242,6 +248,26 @@ LONG WINAPI W32_exception_filter(struct _EXCEPTION_POINTERS* ep) return excpt_result; } +void handle_fpe_signal(int sig, int num) +{ + cl_object condition = @'arithmetic-error'; + + switch (num) { + case _FPE_OVERFLOW: + condition = @'floating-point-overflow'; + break; + case _FPE_UNDERFLOW: + condition = @'floating-point-underflow'; + break; + case _FPE_ZERODIVIDE: + condition = @'division-by-zero'; + break; + } + + si_trap_fpe(@'last', Ct); + cl_error(1, condition); +} + BOOL WINAPI W32_console_ctrl_handler(DWORD type) { switch (type) @@ -258,7 +284,7 @@ BOOL WINAPI W32_console_ctrl_handler(DWORD type) cl_object si_trap_fpe(cl_object condition, cl_object flag) { -#if defined(HAVE_FENV_H) && defined(HAVE_FEENABLEEXCEPT) +#if (defined(HAVE_FENV_H) && defined(HAVE_FEENABLEEXCEPT)) || defined(_MSC_VER) || defined(mingw32) static int last_bits = 0; int bits = 0; if (condition == @'division-by-zero') @@ -271,6 +297,9 @@ si_trap_fpe(cl_object condition, cl_object flag) bits = FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW; else if (condition == @'last') bits = last_bits; +#if defined(_MSC_VER) || defined (mingw32) + _fpreset(); +#endif if (bits) { if (flag == Cnil) { fedisableexcept(bits); diff --git a/src/h/internal.h b/src/h/internal.h index 89fea06e6..42463fea1 100644 --- a/src/h/internal.h +++ b/src/h/internal.h @@ -217,6 +217,18 @@ extern cl_fixnum ecl_runtime(void); extern bool ecl_interrupt_enable; +#if defined(_MSC_VER) || defined(mingw32) +# include +# define FE_DIVBYZERO EM_ZERODIVIDE +# define FE_OVERFLOW EM_OVERFLOW +# define FE_UNDERFLOW EM_UNDERFLOW +# define feenableexcept(bits) { int cw = _controlfp(0,0); cw &= ~(bits); _controlfp(cw,MCW_EM); } +# define fedisableexcept(bits) { int cw = _controlfp(0,0); cw |= (bits); _controlfp(cw,MCW_EM); } +# define feholdexcept(bits) { *(bits) = _controlfp(0,0); _controlfp(0xffffffff, MCW_EM); } +# define fesetenv(bits) _controlfp(*(bits), MCW_EM) +typedef int fenv_t; +#endif + /* unixfsys.d */ #if defined(_MSC_VER) || defined(mingw32)