diff --git a/applications/clawpack/shallow/2d/radialdam/radialdam.cpp b/applications/clawpack/shallow/2d/radialdam/radialdam.cpp index bc9779ca8..1b6956e9c 100644 --- a/applications/clawpack/shallow/2d/radialdam/radialdam.cpp +++ b/applications/clawpack/shallow/2d/radialdam/radialdam.cpp @@ -112,6 +112,8 @@ void run_program(fclaw2d_global_t* glob) } radialdam_link_solvers(glob); + + fclaw_fpe_handling(glob); /* --------------------------------------------------------------- Run diff --git a/applications/clawpack/shallow/2d/radialdam/radialdam_user.cpp b/applications/clawpack/shallow/2d/radialdam/radialdam_user.cpp index 914cda8db..cc884e5ae 100644 --- a/applications/clawpack/shallow/2d/radialdam/radialdam_user.cpp +++ b/applications/clawpack/shallow/2d/radialdam/radialdam_user.cpp @@ -25,6 +25,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "radialdam_user.h" +#include + #include #include #include @@ -115,6 +117,7 @@ void radialdam_link_solvers(fclaw2d_global_t *glob) fclaw2d_vtable_t *vt = fclaw2d_vt(); vt->problem_setup = &radialdam_problem_setup; /* Version-independent */ + vt->fpe_enable = fclaw_fpe_handling_macos; const user_options_t* user = radialdam_get_options(glob); if (user->claw_version == 4) diff --git a/snippets/tst_fpe/Makefile b/snippets/tst_fpe/Makefile new file mode 100644 index 000000000..6878744dc --- /dev/null +++ b/snippets/tst_fpe/Makefile @@ -0,0 +1,8 @@ +TARGET=tst_fpe + +all: + gcc -g -c main_fpe.c + gcc -o ${TARGET} main_fpe.o + +clean: + rm -f *.o *~ ${TARGET} diff --git a/snippets/tst_fpe/README.txt b/snippets/tst_fpe/README.txt new file mode 100644 index 000000000..05511b599 --- /dev/null +++ b/snippets/tst_fpe/README.txt @@ -0,0 +1,32 @@ +This example implements DYI exception handling. It can be tested with + + $ tst_fpe + +where is an FPE type to trap. + +Valid types are indicated by integer 1-5 : + +1 : INVALID, e.g. sqrt(-1), log(-1), acos(2) etc. + +2 : OVERFLOW, e.g. 2^1024, exp(1000) + +3 : UNDERFLOW, e.g. denormalized numbers such as 2^(-1074), exp(-710) + +4 : DIVBYZERO, e.g. 1/0 + +5 : Quiet NAN : This is useful for detecting use of uninitialized data + +6 : Signaling NAN : This NAN will get trapped. + +Ideas for code taken from + + https://developer.apple.com/forums/thread/689159 + +and + + https://stackoverflow.com/questions/69059981/how-to-trap-floating-point-exceptions-on-m1-macs + + + + + diff --git a/snippets/tst_fpe/main_fpe.c b/snippets/tst_fpe/main_fpe.c new file mode 100644 index 000000000..82cc812ee --- /dev/null +++ b/snippets/tst_fpe/main_fpe.c @@ -0,0 +1,133 @@ +#include // for signal() +#include // for fegetenv(), fesetenv() +#include // for sqrt() + +#include +#include + +/* Needed for print_hexval, below */ +#include /* Needed for memcpy */ +#include /* Needed for PRIx64 */ + +/* This doesn't seem to do anything */ +void fpe_signal_handler(int sig) { + printf("Floating point exception!\n"); + return; +} + +void enable_floating_point_exceptions() +{ + fenv_t env; + fegetenv(&env); + env.__fpcr = env.__fpcr | __fpcr_trap_invalid | __fpcr_trap_overflow + | __fpcr_trap_divbyzero | __fpcr_trap_underflow; + fesetenv(&env); + signal(SIGFPE, fpe_signal_handler); +} + + +static +void set_qnan(double *f) +{ + /* + The quiet nan from math.h + */ + *f = NAN; +} + +static +void set_snan(double* f) +{ + /* From : + "NaNs, Uninitialized Variables, and C++" + http://codingcastles.blogspot.fr/2008/12/nans-in-c.html + */ + *((long long*)f) = 0x7ff0000000000001LL; +} + +static +void print_hexval(double x) +{ + /* Kind of cool - didn't know it was possible to do this */ + uint64_t xn; + memcpy(&xn, &x, sizeof x); + printf("x = %16f (%" PRIx64 ")\n", x, xn); +} + +static +double create_exception(int choice) +{ + double x,y; + switch(choice) + { + case 1: + x = -1; + y = sqrt(x); // Or acos(x-1), log(x) + print_hexval(y); + printf("0: INVALID : y = sqrt(-1)\n"); + break; + + case 2: + x = 1000; + y = exp(x); + print_hexval(y); + printf("1: OVERFLOW : y = exp(1000)\n"); + break; + + case 3: + y = pow(2,-1074); + print_hexval(y); + printf("1: UNDERFLOW : y = 2^(-1074)\n"); + break; + + case 4: + x = 0; + y = 1/x; + print_hexval(y); + printf("2: DIVBYZERO : y = 1/0\n"); + break; + + case 5: + set_qnan(&x); + print_hexval(x); + y = x + 1; + printf("3: Quiet NAN (not trapped) : x = NAN; y = x + 1;\n"); + break; + + case 6: + set_snan(&x); + print_hexval(x); + y = x + 1; + printf("3: Signaling NAN (trapped) : x = snan; y = x + 1;\n"); + break; + + default: + y = -1; + printf("Usage : tst_fpe \n"); + printf(" fpe_id in [1-5]\n\n"); + exit(0); + } + return y; +} + +int main(int argc, char** argv) +{ + int fpe_id = 1; + + if (argc > 1) + fpe_id = atoi(argv[1]); + + printf("Exception handling disabled : \n"); + + double y = create_exception(fpe_id); + + printf("Result : y = %g\n",y); + + printf("\n"); + printf("Enabling exception handling\n"); + enable_floating_point_exceptions(); + + y = create_exception(fpe_id); + printf("Result : y = %g\n",y); +} + diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 440a5486d..4fb7e1b9b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -9,7 +9,10 @@ add_library(forestclaw_c OBJECT fclaw_math.c fclaw_timer.c fclaw_mpi.c - fclaw2d_block.c + fclaw_fpe_default.c + fclaw_fpe_linux.c + fclaw_fpe_macos.c + fclaw2d_block.c fclaw2d_options.c fclaw2d_global.c fclaw2d_forestclaw.c diff --git a/src/fclaw2d_vtable.c b/src/fclaw2d_vtable.c index 595a07452..ae4e556a8 100644 --- a/src/fclaw2d_vtable.c +++ b/src/fclaw2d_vtable.c @@ -27,6 +27,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include +#include + #include static fclaw2d_vtable_t s_vt; @@ -64,6 +66,16 @@ void fclaw2d_after_regrid(fclaw2d_global_t *glob) } } +void fclaw_fpe_handling(fclaw2d_global_t *glob) +{ + fclaw2d_vtable_t *fclaw_vt = fclaw2d_vt(); + if (fclaw_vt->fpe_enable != NULL) + { + fclaw_vt->fpe_enable(glob); + } +} + + /* Initialize any settings that can be set here */ void fclaw2d_vtable_initialize() { @@ -86,5 +98,8 @@ void fclaw2d_vtable_initialize() /* Defaults for output */ vt->output_frame = NULL; + vt->fpe_enable = fclaw_fpe_handling_default; + vt->fpe_signal_handler = fclaw_fpe_signal_handler_default; + vt->is_set = 1; } diff --git a/src/fclaw2d_vtable.h b/src/fclaw2d_vtable.h index 273d1a5cd..aadade27f 100644 --- a/src/fclaw2d_vtable.h +++ b/src/fclaw2d_vtable.h @@ -29,9 +29,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifdef __cplusplus extern "C" { -#if 0 -} /* need this because indent is dumb */ -#endif #endif struct fclaw2d_global; @@ -42,6 +39,8 @@ void fclaw2d_after_regrid(struct fclaw2d_global *glob); void fclaw2d_after_init(struct fclaw2d_global *glob); +void fclaw_fpe_handling(struct fclaw2d_global *glob); + /* ---------------------------------- Typedefs ---------------------------------------- */ typedef void (*fclaw2d_vtable_initialize_t)(); @@ -54,19 +53,26 @@ typedef void (*fclaw2d_after_regrid_t)(struct fclaw2d_global *glob); typedef void (*fclaw2d_after_initialization_t)(struct fclaw2d_global *glob); +typedef void (*fclaw_fpe_handling_t)(struct fclaw2d_global *glob); + +typedef void (*fclaw_fpe_signal_handler_t)(int sig); + /* ------------------------------------ vtable ---------------------------------------- */ typedef struct fclaw2d_vtable { - fclaw2d_vtable_initialize_t vtable_init; - fclaw2d_problem_setup_t problem_setup; - fclaw2d_after_initialization_t after_init; + fclaw2d_vtable_initialize_t vtable_init; + fclaw2d_problem_setup_t problem_setup; + fclaw2d_after_initialization_t after_init; /* regridding functions */ - fclaw2d_after_regrid_t after_regrid; + fclaw2d_after_regrid_t after_regrid; /* Output functions */ - fclaw2d_output_frame_t output_frame; + fclaw2d_output_frame_t output_frame; + + fclaw_fpe_handling_t fpe_enable; + fclaw_fpe_signal_handler_t fpe_signal_handler; int is_set; @@ -80,9 +86,6 @@ void fclaw2d_vtable_initialize(); #ifdef __cplusplus -#if 0 -{ -#endif } #endif diff --git a/src/fclaw_fpe.h b/src/fclaw_fpe.h new file mode 100644 index 000000000..be6eb5d91 --- /dev/null +++ b/src/fclaw_fpe.h @@ -0,0 +1,57 @@ +/* +Copyright (c) 2012-2022 Carsten Burstedde, Donna Calhoun, Scott Aiton +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** \file + * + * Routines for virtualized exception handling + * + */ + +#ifndef FCLAW_FPE_H +#define FCLAW_FPE_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +struct fclaw2d_global; + +void fclaw_fpe_handling_default(struct fclaw2d_global *glob); + +void fclaw_fpe_signal_handler_default(int sig); + + +/* Thse files are only compiled in optionally */ +void fclaw_fpe_handling_macos(struct fclaw2d_global* glob); + +void fclaw_fpe_handling_linux(struct fclaw2d_global* glob); + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/src/fclaw_fpe_default.c b/src/fclaw_fpe_default.c new file mode 100644 index 000000000..47f8a8e1d --- /dev/null +++ b/src/fclaw_fpe_default.c @@ -0,0 +1,63 @@ +/* +Copyright (c) 2012-2022 Carsten Burstedde, Donna Calhoun, Scott Aiton +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include + +#include /* for signal() */ +#include /* for fegetenv(), fesetenv() */ + +void fclaw_fpe_signal_handler_default(int sig) +{ + fclaw_global_essentialf("Floating point exception encountered\n"); + switch (sig) + { + case FE_INVALID: + fclaw_global_essentialf("Invalid value detected\n"); + exit(0); + break; + case FE_DIVBYZERO: + fclaw_global_essentialf("Division by zero detected\n"); + exit(0); + break; + case FE_OVERFLOW: + fclaw_global_essentialf("Overflow detected\n"); + exit(0); + break; + case FE_UNDERFLOW: + case FE_INEXACT: + /* Ignore these - too many exceptions detected */ + break; + default : + break; + } + return; +} + + +void fclaw_fpe_handling_default(fclaw2d_global_t* glob) +{ + fclaw_global_essentialf("Floating point exception handling is disabled.\n"); +} diff --git a/src/fclaw_fpe_linux.c b/src/fclaw_fpe_linux.c new file mode 100644 index 000000000..a8e726e34 --- /dev/null +++ b/src/fclaw_fpe_linux.c @@ -0,0 +1,46 @@ +/* +Copyright (c) 2012-2022 Carsten Burstedde, Donna Calhoun, Scott Aiton +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include +#include + + +#include /* for signal() */ +#include /* for fegetenv(), fesetenv() */ + + +void fclaw_fpe_handling_linux(fclaw2d_global_t* glob) +{ + fclaw2d_vtable_t *vt = fclaw2d_vt(); + fclaw_global_essentialf("Enabling floating point traps (Linux)\n"); + + /* Underflow catches too many exceptions */ + feenableexcept(FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW | FE_INEXACT); + + //feenableexcept(FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW); + signal(SIGFPE, vt->fpe_signal_handler); +} + diff --git a/src/fclaw_fpe_macos.c b/src/fclaw_fpe_macos.c new file mode 100644 index 000000000..12706a151 --- /dev/null +++ b/src/fclaw_fpe_macos.c @@ -0,0 +1,47 @@ +/* +Copyright (c) 2012-2022 Carsten Burstedde, Donna Calhoun, Scott Aiton +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include +#include + +#include /* for signal() */ +#include /* for fegetenv(), fesetenv() */ + + +void fclaw_fpe_handling_macos(fclaw2d_global_t* glob) +{ + fclaw_global_essentialf("Enabling floating point traps (MacOS)\n"); + fenv_t env; + fegetenv(&env); + env.__fpcr = env.__fpcr | FE_INVALID | FE_OVERFLOW + | FE_DIVBYZERO | FE_UNDERFLOW; + fesetenv(&env); + + /* This doesn't appear to actually do anything */ + fclaw2d_vtable_t *vt = fclaw2d_vt(); + signal(SIGFPE, vt->fpe_signal_handler); +} + diff --git a/src/fclaw_options.c b/src/fclaw_options.c index cb2f465c2..6ae58fcac 100644 --- a/src/fclaw_options.c +++ b/src/fclaw_options.c @@ -27,6 +27,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include +#if 0 /* Get whatever definitions exist already */ #ifdef FCLAW_HAVE_FENV_H #ifndef __USE_GNU @@ -43,6 +44,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifdef FCLAW_HAVE_SIGNAL_H #include #endif +#endif + +#if 0 +/* Nothing */ +#endif #ifdef FCLAW_HAVE_UNISTD_H #include /* To get process ids */ @@ -369,14 +375,17 @@ fclaw_options_check (fclaw_options_t * fclaw_opt) fclaw_global_infof("Entering mpi_debug session"); fclaw_mpi_debug (); } -#ifdef FCLAW_HAVE_FEENABLEEXCEPT + +#if 0 +#ifdef FCLAW_HAVE_FEENABLEEXCEPT if (fclaw_opt->trapfpe) { fclaw_global_infof("Enabling floating point traps\n"); - // feenableexcept(FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW); + //feenableexcept(FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW); feenableexcept(FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW); } #endif +#endif #if FCLAW2D_PATCHDIM == 3 if (fclaw_opt->manifold) diff --git a/src/fp_exception_glibc_extension.c b/src/fp_exception_glibc_extension.c deleted file mode 100644 index d4c57f788..000000000 --- a/src/fp_exception_glibc_extension.c +++ /dev/null @@ -1,375 +0,0 @@ -/* Title: Floating-point exception handling example - Author: David N. Williams - File: fe-handlng-example.c - License: Public Domain - Version: 0.5.0 - Started: 21-Sep-09 - Revised: 22-Sep-09 - Revised: 30-Sep-09 (comment typo) - Revised: 18 Oct-12 (chnaged char* to const char * on line 228, by Richard Booth) - -This code is an example of alternate, nondefault handling of -IEEE 754 floating-point exceptions in OS X and Linux, based on -the GNU functions feenableexcept(), fedisableeexcept(), and -fegetexcept() [in libm], plus POSIX sigaction(). - -The GNU functions above are not implemented in OS X Leopard, -gcc 4.x, but are present in Linux. We implement them here for -OS X, at least until the underlying mechanism is no longer -supported by Apple. - -The mechanism is to use the POSIX functions fegetenv() and -fesetenv(), which *are* present in OS X, to manipulate the ppc -and intel floating-point control registers, after changing bits -in fields corresponding to those registers in the fenv_t data -type. - -Assembly language code to directly access the floating-point -status and control registers for ppc and intel is also included. - -This example grew out of an update to legacy code for Apple -ppc's. The original legacy code is in Listing 7-1 in "PowerPC -Numerics", 2004: - -http://lists.apple.com/archives/unix-porting/2003/May/msg00026.html - -Another version of the ppc legacy code is here: - -http://developer.apple.com/documentation/Performance/Conceptual/Mac_OSX_Numerics/Mac_OSX_Numerics.pdf - -Terry Lambert pointed out that our naive update of the legacy -example to Mac OS X Leopard made egregious unsupported use of -system context structures in the handler. See his reply to - -http://lists.apple.com/archives/Darwin-dev/2009/Sep/msg00091.html - -The example in this file is more plain vanilla, and aims at -alternate handling that does not return to the application, but -rather aborts with a diagnostic message. - -To compile it under Mac OS X, execute: - - cc -o fe-handling fe-handling-example.c - -To compile it under Linux, execute: - - cc -DLINUX -lm -o fe-handling fe-handling-example.c -*/ - -/* Need this to evaluate the FCLAW_HAVE_ definitions */ -#include - -/* We only do something if we need the feenableexcept replacement. - Otherwise this file noops. */ -#ifndef FCLAW_HAVE_FEENABLEEXCEPT - -/* Added this ifdef to compile the file conditionally */ -/* Question: why does this file not include fp_exception_glibc_extension.h? */ -/* Answer: now it does -- is this how we like it? */ -#include - -#ifdef FCLAW_HAVE_SIGNAL_H -#include -#endif - -#ifdef LINUX -/* BEGIN quote -http://graphviz.sourcearchive.com/documentation/2.16/gvrender__pango_8c-source.html -*/ -/* _GNU_SOURCE is needed (supposedly) for the feenableexcept - * prototype to be defined in fenv.h on GNU systems. - * Presumably it will do no harm on other systems. - */ -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif - -/* We are not supposed to need __USE_GNU, but I can't see - * how to get the prototype for fedisableexcept from - * /usr/include/fenv.h without it. - */ -#ifndef __USE_GNU -#define __USE_GNU -#endif -/* END quote */ -#endif // LINUX - -#ifdef FCLAW_HAVE_FENV_H -#include -#endif - -#define DEFINED_PPC (defined(__ppc__) || defined(__ppc64__)) -#define DEFINED_INTEL (defined(__i386__) || defined(__x86_64__)) - -#ifndef LINUX -#if DEFINED_PPC - -#define FE_EXCEPT_SHIFT 22 // shift flags right to get masks -#define FM_ALL_EXCEPT FE_ALL_EXCEPT >> FE_EXCEPT_SHIFT - -/* GNU C Library: -http://www.gnu.org/software/libc/manual/html_node/Control-Functions.html - - - Function: int fegetexcept (int excepts) - - The function returns a bitmask of all currently enabled - exceptions. It returns -1 in case of failure. - - The excepts argument appears in other functions in fenv.h, - and corresponds to the FE_xxx exception flag constants. It - is unclear whether the bitmask is for the flags or the masks. - We return that for the flags, which corresponds to the - excepts argument in feenableexcept(excepts) and - fedisableexcept(excepts). In GNU/Linux the argument is void, - and that's what we implement. Linux "man fegetenv" appears - to suggest that it's the mask corresponding to bits in - excepts that is returned. -*/ -int -fegetexcept (void) -{ - static fenv_t fenv; - - return ( fegetenv (&fenv) ? -1 : - ( - ( fenv & (FM_ALL_EXCEPT) ) << FE_EXCEPT_SHIFT ) - ); -} - -int -feenableexcept (int excepts) -{ - static fenv_t fenv; - int new_excepts = (excepts & FE_ALL_EXCEPT) >> FE_EXCEPT_SHIFT, - old_excepts; // all previous masks - - if ( fegetenv (&fenv) ) return -1; - old_excepts = (fenv & FM_ALL_EXCEPT) << FE_EXCEPT_SHIFT; - - fenv = (fenv & ~new_excepts) | new_excepts; - return ( fesetenv (&fenv) ? -1 : old_excepts ); -} - -int -fedisableexcept (int excepts) -{ - static fenv_t fenv; - int still_on = ~( (excepts & FE_ALL_EXCEPT) >> FE_EXCEPT_SHIFT ), - old_excepts; // previous masks - - if ( fegetenv (&fenv) ) return -1; - old_excepts = (fenv & FM_ALL_EXCEPT) << FE_EXCEPT_SHIFT; - - fenv &= still_on; - return ( fesetenv (&fenv) ? -1 : old_excepts ); -} - -#elif DEFINED_INTEL - -int -fegetexcept (void) -{ - static fenv_t fenv; - -#if defined(__MINGW64__) || defined(__MINGW32__) - return fegetenv (&fenv) ? -1 : (fenv.__control_word & FE_ALL_EXCEPT); -#else - return fegetenv (&fenv) ? -1 : (fenv.__control & FE_ALL_EXCEPT); -#endif -} - -int -feenableexcept (int excepts) -{ - static fenv_t fenv; - int new_excepts = excepts & FE_ALL_EXCEPT, - old_excepts; // previous masks - - if ( fegetenv (&fenv) ) return -1; -#if defined(__MINGW64__) || defined(__MINGW32__) - old_excepts = fenv.__control_word & FE_ALL_EXCEPT; -#else - old_excepts = fenv.__control & FE_ALL_EXCEPT; -#endif - // unmask -#if defined(__MINGW64__) || defined(__MINGW32__) - fenv.__control_word &= ~new_excepts; -#else - fenv.__control &= ~new_excepts; -#endif - fenv.__mxcsr &= ~(new_excepts << 7); - - return ( fesetenv (&fenv) ? -1 : old_excepts ); -} - -int -fedisableexcept (int excepts) -{ - static fenv_t fenv; - int new_excepts = excepts & FE_ALL_EXCEPT, - old_excepts; // all previous masks - - if ( fegetenv (&fenv) ) return -1; -#if defined(__MINGW64__) || defined(__MINGW32__) - old_excepts = fenv.__control_word & FE_ALL_EXCEPT; -#else - old_excepts = fenv.__control & FE_ALL_EXCEPT; -#endif - - // mask -#if defined(__MINGW64__) || defined(__MINGW32__) - fenv.__control_word |= new_excepts; -#else - fenv.__control |= new_excepts; -#endif - fenv.__mxcsr |= new_excepts << 7; - - return ( fesetenv (&fenv) ? -1 : old_excepts ); -} - -#endif // PPC or INTEL enabling -#endif // not LINUX - -#if DEFINED_PPC - -#define getfpscr(x) asm volatile ("mffs %0" : "=f" (x)); -#define setfpscr(x) asm volatile ("mtfsf 255,%0" : : "f" (x)); - -typedef union { - struct { - unsigned long hi; - unsigned long lo; - } i; - double d; -} hexdouble; - -#endif // DEFINED_PPC - -#if DEFINED_INTEL - -// x87 fpu -/* DAC (9/26/2016) : Changed 'asm' to '__asm__ volatile' so that macro expansion - passed -std=c99 -pedentic compiler flags */ - -#define getx87cr(x) __asm__ volatile ("fnstcw %0" : "=m" (x)); -#define setx87cr(x) __asm__ volatile ("fldcw %0" : "=m" (x)); -#define getx87sr(x) __asm__ volatile ("fnstsw %0" : "=m" (x)); - -// SIMD, gcc with Intel Core 2 Duo uses SSE2(4) -#define getmxcsr(x) __asm__ volatile ("stmxcsr %0" : "=m" (x)); -#define setmxcsr(x) __asm__ volatile ("ldmxcsr %0" : "=m" (x)); - -#endif // DEFINED_INTEL - -#ifdef FCLAW_HAVE_SIGNAL_H -#include -#endif - -#include // printf() -#include // abort(), exit() - -#if 0 - -static const char *fe_code_name[] = { - "FPE_NOOP", - "FPE_FLTDIV", "FPE_FLTINV", "FPE_FLTOVF", "FPE_FLTUND", - "FPE_FLTRES", "FPE_FLTSUB", "FPE_INTDIV", "FPE_INTOVF" - "FPE_UNKNOWN" -}; - -/* SAMPLE ALTERNATE FP EXCEPTION HANDLER - - The sample handler just reports information about the - exception that invoked it, and aborts. It makes no attempt - to restore state and return to the application. - - More sophisticated handling would have to confront at least - these issues: - - * interface to the system context for restoring state - * imprecision of interrupts from hardware for the intel x87 - fpu (but not the SIMD unit, nor the ppc) - * imprecision of interrupts from system software -*/ -void -fhdl ( int sig, siginfo_t *sip, ucontext_t *scp ) -{ - int fe_code = sip->si_code; - int excepts = fetestexcept (FE_ALL_EXCEPT); - - switch (fe_code) - { -#ifdef FPE_NOOP // occurs in OS X - case FPE_NOOP: fe_code = 0; break; -#endif - case FPE_FLTDIV: fe_code = 1; break; // divideByZero - case FPE_FLTINV: fe_code = 2; break; // invalid - case FPE_FLTOVF: fe_code = 3; break; // overflow - case FPE_FLTUND: fe_code = 4; break; // underflow - case FPE_FLTRES: fe_code = 5; break; // inexact - case FPE_FLTSUB: fe_code = 6; break; // invalid - case FPE_INTDIV: fe_code = 7; break; // overflow - case FPE_INTOVF: fe_code = 8; break; // underflow - default: fe_code = 9; - } - - if ( sig == SIGFPE ) - { -#if DEFINED_INTEL - unsigned short x87cr,x87sr; - unsigned int mxcsr; - - getx87cr (x87cr); - getx87sr (x87sr); - getmxcsr (mxcsr); - printf ("X87CR: 0x%04X\n", x87cr); - printf ("X87SR: 0x%04X\n", x87sr); - printf ("MXCSR: 0x%08X\n", mxcsr); -#endif - -#if DEFINED_PPC - hexdouble t; - - getfpscr (t.d); - printf ("FPSCR: 0x%08X\n", t.i.lo); -#endif - - printf ("signal: SIGFPE with code %s\n", fe_code_name[fe_code]); - printf ("invalid flag: 0x%04X\n", excepts & FE_INVALID); - printf ("divByZero flag: 0x%04X\n", excepts & FE_DIVBYZERO); - } - else printf ("Signal is not SIGFPE, it's %i.\n", sig); - - abort(); -} -#endif - -#if 0 -int main (int argc, char **argv) -{ - double s; - struct sigaction act; - - act.sa_sigaction = (void(*))fhdl; - sigemptyset (&act.sa_mask); - act.sa_flags = SA_SIGINFO; - - -// printf ("Old divByZero exception: 0x%08X\n", feenableexcept (FE_DIVBYZERO)); - printf ("Old invalid exception: 0x%08X\n", feenableexcept (FE_INVALID)); - printf ("New fp exception: 0x%08X\n", fegetexcept ()); - - // set handler - if (sigaction(SIGFPE, &act, (struct sigaction *)0) != 0) - { - perror("Yikes"); - exit(-1); - } - -// s = 1.0 / 0.0; // FE_DIVBYZERO - s = 0.0 / 0.0; // FE_INVALID - return 0; -} -#endif - -#endif /* !FCLAW_HAVE_FEENABLEEXCEPT */ diff --git a/src/fp_exception_glibc_extension.h b/src/fp_exception_glibc_extension.h deleted file mode 100644 index e4d83f2d0..000000000 --- a/src/fp_exception_glibc_extension.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - glibc floating point extension replacement for OS X. - - Title: Floating-point exception handling example - Author: David N. Williams - File: fe-handlng-example.c - License: Public Domain - Version: 0.5.0 - -*/ - -#ifndef FENV_H_LINUX_REPLACEMENT -#define FENV_H_LINUX_REPLACEMENT - -/* We are replacing the declarations from this header file. -#include -*/ - -#ifdef __cplusplus -extern "C" { -#endif - - /* GNU C Library: - http://www.gnu.org/software/libc/manual/html_node/Control-Functions.html - - - Function: int fegetexcept (int excepts) - - The function returns a bitmask of all currently enabled - exceptions. It returns -1 in case of failure. - - The excepts argument appears in other functions in fenv.h, - and corresponds to the FE_xxx exception flag constants. It - is unclear whether the bitmask is for the flags or the masks. - We return that for the flags, which corresponds to the - excepts argument in feenableexcept(excepts) and - fedisableexcept(excepts). In GNU/Linux the argument is void, - and that's what we implement. Linux "man fegetenv" appears - to suggest that it's the mask corresponding to bits in - excepts that is returned. - */ - int fegetexcept (void); - int feenableexcept (int excepts); - int fedisableexcept (int excepts); - - /* SAMPLE ALTERNATE FP EXCEPTION HANDLER - - The sample handler just reports information about the - exception that invoked it, and aborts. It makes no attempt - to restore state and return to the application. - - More sophisticated handling would have to confront at least - these issues: - - * interface to the system context for restoring state - * imprecision of interrupts from hardware for the intel x87 - fpu (but not the SIMD unit, nor the ppc) - * imprecision of interrupts from system software - */ -#if 0 - void fhdl ( int sig, siginfo_t *sip, ucontext_t *scp ) ; -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* !FENV_H_LINUX_REPLACEMENT */