xref: /petsc/src/sys/error/fp.c (revision 03047865b8d8757cf1cf9cda45785c1537b01dc1)
1e5c89e4eSSatish Balay /*
20e3d61c9SBarry Smith    IEEE error handler for all machines. Since each OS has
30e3d61c9SBarry Smith    enough slight differences we have completely separate codes for each one.
4e5c89e4eSSatish Balay */
5b014e56cSJed Brown 
6b014e56cSJed Brown /*
7b014e56cSJed Brown   This feature test macro provides FE_NOMASK_ENV on GNU.  It must be defined
8b014e56cSJed Brown   at the top of the file because other headers may pull in fenv.h even when
9b014e56cSJed Brown   not strictly necessary.  Strictly speaking, we could include ONLY petscconf.h,
10b014e56cSJed Brown   check PETSC_HAVE_FENV_H, and only define _GNU_SOURCE in that case, but such
11b014e56cSJed Brown   shenanigans ought to be unnecessary.
12b014e56cSJed Brown */
13519f805aSKarl Rupp #if !defined(_GNU_SOURCE)
14b014e56cSJed Brown   #define _GNU_SOURCE
1576a6984eSJed Brown #endif
16b014e56cSJed Brown 
1727104ee2SJacob Faibussowitsch #include <petsc/private/petscimpl.h> /*I  "petscsys.h"  I*/
18e5c89e4eSSatish Balay #include <signal.h>
19fb56d528SJed Brown #if defined(PETSC_HAVE_XMMINTRIN_H)
20fb56d528SJed Brown   #include <xmmintrin.h>
21fb56d528SJed Brown #endif
22e5c89e4eSSatish Balay 
23670f3ff9SJed Brown struct PetscFPTrapLink {
24670f3ff9SJed Brown   PetscFPTrap             trapmode;
25670f3ff9SJed Brown   struct PetscFPTrapLink *next;
26670f3ff9SJed Brown };
27aba4c478SBarry Smith static PetscFPTrap             _trapmode = PETSC_FP_TRAP_OFF; /* Current trapping mode; see PetscDetermineInitialFPTrap() */
28670f3ff9SJed Brown static struct PetscFPTrapLink *_trapstack;                    /* Any pushed states of _trapmode */
29670f3ff9SJed Brown 
30670f3ff9SJed Brown /*@
31811af0c4SBarry Smith   PetscFPTrapPush - push a floating point trapping mode, restored using `PetscFPTrapPop()`
32670f3ff9SJed Brown 
33670f3ff9SJed Brown   Not Collective
34670f3ff9SJed Brown 
354165533cSJose E. Roman   Input Parameter:
36811af0c4SBarry Smith . trap - `PETSC_FP_TRAP_ON` or `PETSC_FP_TRAP_OFF` or any of the values passable to `PetscSetFPTrap()`
37670f3ff9SJed Brown 
38670f3ff9SJed Brown   Level: advanced
39670f3ff9SJed Brown 
40cc9df77eSBarry Smith   Notes:
41cc9df77eSBarry Smith   This only changes the trapping if the new mode is different than the current mode.
42cc9df77eSBarry Smith 
43cc9df77eSBarry Smith   This routine is called to turn off trapping for certain LAPACK routines that assume that dividing
44cc9df77eSBarry Smith   by zero is acceptable. In particular the routine ieeeck().
45cc9df77eSBarry Smith 
46cc9df77eSBarry Smith   Most systems by default have all trapping turned off, but certain Fortran compilers have
47cc9df77eSBarry Smith   link flags that turn on trapping before the program begins.
487de69702SBarry Smith .vb
497de69702SBarry Smith        gfortran -ffpe-trap=invalid,zero,overflow,underflow,denormal
507de69702SBarry Smith        ifort -fpe0
517de69702SBarry Smith .ve
52cc9df77eSBarry Smith 
53db781477SPatrick Sanan .seealso: `PetscFPTrapPop()`, `PetscSetFPTrap()`, `PetscDetermineInitialFPTrap()`
54670f3ff9SJed Brown @*/
PetscFPTrapPush(PetscFPTrap trap)55d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscFPTrapPush(PetscFPTrap trap)
56d71ae5a4SJacob Faibussowitsch {
57670f3ff9SJed Brown   struct PetscFPTrapLink *link;
58670f3ff9SJed Brown 
59670f3ff9SJed Brown   PetscFunctionBegin;
609566063dSJacob Faibussowitsch   PetscCall(PetscNew(&link));
611f006be4SPierre Jolivet #if defined(PETSC_HAVE_THREADSAFETY) && defined(PETSC_HAVE_OPENMP)
62ed6c4ed2SJacob Faibussowitsch   PetscPragmaOMP(critical)
631f006be4SPierre Jolivet #endif
641f006be4SPierre Jolivet   {
65670f3ff9SJed Brown     link->trapmode = _trapmode;
66670f3ff9SJed Brown     link->next     = _trapstack;
67670f3ff9SJed Brown     _trapstack     = link;
681f006be4SPierre Jolivet   }
699566063dSJacob Faibussowitsch   if (trap != _trapmode) PetscCall(PetscSetFPTrap(trap));
703ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
71670f3ff9SJed Brown }
72670f3ff9SJed Brown 
73670f3ff9SJed Brown /*@
74811af0c4SBarry Smith   PetscFPTrapPop - push a floating point trapping mode, to be restored using `PetscFPTrapPop()`
75670f3ff9SJed Brown 
76670f3ff9SJed Brown   Not Collective
77670f3ff9SJed Brown 
78670f3ff9SJed Brown   Level: advanced
79670f3ff9SJed Brown 
80db781477SPatrick Sanan .seealso: `PetscFPTrapPush()`, `PetscSetFPTrap()`, `PetscDetermineInitialFPTrap()`
81670f3ff9SJed Brown @*/
PetscFPTrapPop(void)82d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscFPTrapPop(void)
83d71ae5a4SJacob Faibussowitsch {
84670f3ff9SJed Brown   struct PetscFPTrapLink *link;
85670f3ff9SJed Brown 
86670f3ff9SJed Brown   PetscFunctionBegin;
879566063dSJacob Faibussowitsch   if (_trapstack->trapmode != _trapmode) PetscCall(PetscSetFPTrap(_trapstack->trapmode));
881f006be4SPierre Jolivet #if defined(PETSC_HAVE_THREADSAFETY) && defined(PETSC_HAVE_OPENMP)
89ed6c4ed2SJacob Faibussowitsch   PetscPragmaOMP(critical)
901f006be4SPierre Jolivet #endif
911f006be4SPierre Jolivet   {
92670f3ff9SJed Brown     link       = _trapstack;
93670f3ff9SJed Brown     _trapstack = _trapstack->next;
941f006be4SPierre Jolivet   }
959566063dSJacob Faibussowitsch   PetscCall(PetscFree(link));
963ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
97670f3ff9SJed Brown }
98670f3ff9SJed Brown 
99e5c89e4eSSatish Balay #if defined(PETSC_HAVE_SUN4_STYLE_FPTRAP)
100e5c89e4eSSatish Balay   #include <floatingpoint.h>
101e5c89e4eSSatish Balay 
1028cc058d9SJed Brown PETSC_EXTERN PetscErrorCode ieee_flags(char *, char *, char *, char **);
1038cc058d9SJed Brown PETSC_EXTERN PetscErrorCode ieee_handler(char *, char *, sigfpe_handler_type(int, int, struct sigcontext *, char *));
104e5c89e4eSSatish Balay 
1059371c9d4SSatish Balay static struct {
1069371c9d4SSatish Balay   int   code_no;
1079371c9d4SSatish Balay   char *name;
1089371c9d4SSatish Balay } error_codes[] = {
109e5c89e4eSSatish Balay   {FPE_INTDIV_TRAP,   "integer divide"               },
110e5c89e4eSSatish Balay   {FPE_FLTOPERR_TRAP, "IEEE operand error"           },
111e5c89e4eSSatish Balay   {FPE_FLTOVF_TRAP,   "floating point overflow"      },
112e5c89e4eSSatish Balay   {FPE_FLTUND_TRAP,   "floating point underflow"     },
113e5c89e4eSSatish Balay   {FPE_FLTDIV_TRAP,   "floating pointing divide"     },
114e5c89e4eSSatish Balay   {FPE_FLTINEX_TRAP,  "inexact floating point result"},
115e5c89e4eSSatish Balay   {0,                 "unknown error"                }
116e5c89e4eSSatish Balay };
117e5c89e4eSSatish Balay   #define SIGPC(scp) (scp->sc_pc)
118e5c89e4eSSatish Balay 
119cf0818bdSBarry Smith /* this function gets called if a trap has occurred and been caught */
PetscDefaultFPTrap(int sig,int code,struct sigcontext * scp,char * addr)120d71ae5a4SJacob Faibussowitsch sigfpe_handler_type PetscDefaultFPTrap(int sig, int code, struct sigcontext *scp, char *addr)
121d71ae5a4SJacob Faibussowitsch {
1225f80ce2aSJacob Faibussowitsch   int err_ind = -1;
123e5c89e4eSSatish Balay 
124e5c89e4eSSatish Balay   PetscFunctionBegin;
1255f80ce2aSJacob Faibussowitsch   for (int j = 0; error_codes[j].code_no; j++) {
126e5c89e4eSSatish Balay     if (error_codes[j].code_no == code) err_ind = j;
127e5c89e4eSSatish Balay   }
128e5c89e4eSSatish Balay 
129dd460d27SBarry Smith   if (err_ind >= 0) (void)(*PetscErrorPrintf)("*** %s occurred at pc=%X ***\n", error_codes[err_ind].name, SIGPC(scp));
130dd460d27SBarry Smith   else (void)(*PetscErrorPrintf)("*** floating point error 0x%x occurred at pc=%X ***\n", code, SIGPC(scp));
131a297a907SKarl Rupp 
132dd460d27SBarry Smith   (void)PetscError(PETSC_COMM_SELF, PETSC_ERR_FP, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_REPEAT, "floating point error");
13341e02c4dSJunchao Zhang   PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP);
1343ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
135e5c89e4eSSatish Balay }
136e5c89e4eSSatish Balay 
137e30d2299SSatish Balay /*@
138cf0818bdSBarry Smith    PetscSetFPTrap - Enables traps/exceptions on common floating point errors. This option may not work on certain systems or only a
139cf0818bdSBarry Smith    subset of exceptions may be trapable.
140e5c89e4eSSatish Balay 
141e5c89e4eSSatish Balay    Not Collective
142e5c89e4eSSatish Balay 
1432fe279fdSBarry Smith    Input Parameter:
144cf0818bdSBarry Smith .  flag - values are
145cf0818bdSBarry Smith .vb
146cf0818bdSBarry Smith     PETSC_FP_TRAP_OFF   - do not trap any exceptions
147cf0818bdSBarry Smith     PETSC_FP_TRAP_ON - all exceptions that are possible on the system except underflow
148cf0818bdSBarry Smith     PETSC_FP_TRAP_INDIV - integer divide by zero
149cf0818bdSBarry Smith     PETSC_FP_TRAP_FLTOPERR - improper argument to function, for example with real numbers, the square root of a negative number
150cf0818bdSBarry Smith     PETSC_FP_TRAP_FLTOVF - overflow
151cf0818bdSBarry Smith     PETSC_FP_TRAP_FLTUND - underflow - not trapped by default on most systems
152cf0818bdSBarry Smith     PETSC_FP_TRAP_FLTDIV - floating point divide by zero
153cf0818bdSBarry Smith     PETSC_FP_TRAP_FLTINEX - inexact floating point result
154cf0818bdSBarry Smith .ve
155e5c89e4eSSatish Balay 
1562fe279fdSBarry Smith    Options Database Key:
157cf0818bdSBarry Smith .  -fp_trap <off,on> - turn on or off trapping of floating point exceptions
158e5c89e4eSSatish Balay 
159e5c89e4eSSatish Balay    Level: advanced
160e5c89e4eSSatish Balay 
161cf0818bdSBarry Smith    Notes:
1627de69702SBarry Smith    Preferred usage is `PetscFPTrapPush()` and `PetscFPTrapPop()` instead of this routine
1637de69702SBarry Smith 
164811af0c4SBarry Smith    Currently only `PETSC_FP_TRAP_OFF` and `PETSC_FP_TRAP_ON` are handled. All others are treated as `PETSC_FP_TRAP_ON`.
165cf0818bdSBarry Smith 
166cf0818bdSBarry Smith    The values are bit values and may be |ed together in the function call
167cf0818bdSBarry Smith 
168cf0818bdSBarry Smith    On systems that support it this routine causes floating point
169cf0818bdSBarry Smith    overflow, divide-by-zero, and invalid-operand (e.g., a NaN), but not underflow, to
170e5c89e4eSSatish Balay    cause a message to be printed and the program to exit.
171e5c89e4eSSatish Balay 
172cc9df77eSBarry Smith    On many common systems, the floating
1737d125cddSJed Brown    point exception state is not preserved from the location where the trap
1747d125cddSJed Brown    occurred through to the signal handler.  In this case, the signal handler
1757d125cddSJed Brown    will just say that an unknown floating point exception occurred and which
1767d125cddSJed Brown    function it occurred in.  If you run with -fp_trap in a debugger, it will
177cc9df77eSBarry Smith    break on the line where the error occurred.  On systems that support C99
178cc9df77eSBarry Smith    floating point exception handling You can check which
1797d125cddSJed Brown    exception occurred using fetestexcept(FE_ALL_EXCEPT).  See fenv.h
1807d125cddSJed Brown    (usually at /usr/include/bits/fenv.h) for the enum values on your system.
1817d125cddSJed Brown 
182db781477SPatrick Sanan .seealso: `PetscFPTrapPush()`, `PetscFPTrapPop()`, `PetscDetermineInitialFPTrap()`
183e5c89e4eSSatish Balay @*/
PetscSetFPTrap(PetscFPTrap flag)184d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSetFPTrap(PetscFPTrap flag)
185d71ae5a4SJacob Faibussowitsch {
186e5c89e4eSSatish Balay   char *out;
187e5c89e4eSSatish Balay 
188e5c89e4eSSatish Balay   PetscFunctionBegin;
189e5c89e4eSSatish Balay   /* Clear accumulated exceptions.  Used to suppress meaningless messages from f77 programs */
190e5c89e4eSSatish Balay   (void)ieee_flags("clear", "exception", "all", &out);
191bd2b07b1SBarry Smith   if (flag == PETSC_FP_TRAP_ON) {
192e5c89e4eSSatish Balay     /*
193a297a907SKarl Rupp       To trap more fp exceptions, including underflow, change the line below to
194e5c89e4eSSatish Balay       if (ieee_handler("set","all",PetscDefaultFPTrap)) {
195e5c89e4eSSatish Balay     */
196a297a907SKarl Rupp     if (ieee_handler("set", "common", PetscDefaultFPTrap)) (*PetscErrorPrintf)("Can't set floatingpoint handler\n");
197a297a907SKarl Rupp   } else if (ieee_handler("clear", "common", PetscDefaultFPTrap)) (*PetscErrorPrintf)("Can't clear floatingpoint handler\n");
198a297a907SKarl Rupp 
199670f3ff9SJed Brown   _trapmode = flag;
200bd2b07b1SBarry Smith   PetscCall(PetscInfo(NULL, "Using PETSC_HAVE_SUN4_STYLE_FPTRAP\n"));
2013ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
202e5c89e4eSSatish Balay }
203e5c89e4eSSatish Balay 
204cc9df77eSBarry Smith /*@
205811af0c4SBarry Smith    PetscDetermineInitialFPTrap - Attempts to determine the floating point trapping that exists when `PetscInitialize()` is called
206cc9df77eSBarry Smith 
207cc9df77eSBarry Smith    Not Collective
208cc9df77eSBarry Smith 
209811af0c4SBarry Smith    Note:
210337bb527SBarry Smith    Currently only supported on Linux and macOS. Checks if divide by zero is enable and if so declares that trapping is on.
211cc9df77eSBarry Smith 
212ee300463SSatish Balay    Level: advanced
213cc9df77eSBarry Smith 
214db781477SPatrick Sanan .seealso: `PetscFPTrapPush()`, `PetscFPTrapPop()`, `PetscDetermineInitialFPTrap()`
215cc9df77eSBarry Smith @*/
PetscDetermineInitialFPTrap(void)216d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDetermineInitialFPTrap(void)
217d71ae5a4SJacob Faibussowitsch {
218cc9df77eSBarry Smith   PetscFunctionBegin;
2199566063dSJacob Faibussowitsch   PetscCall(PetscInfo(NULL, "Unable to determine initial floating point trapping. Assuming it is off\n"));
2203ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
221cc9df77eSBarry Smith }
222cc9df77eSBarry Smith 
223e5c89e4eSSatish Balay #elif defined(PETSC_HAVE_SOLARIS_STYLE_FPTRAP)
224e5c89e4eSSatish Balay   #include <sunmath.h>
225e5c89e4eSSatish Balay   #include <floatingpoint.h>
226e5c89e4eSSatish Balay   #include <siginfo.h>
227e5c89e4eSSatish Balay   #include <ucontext.h>
228e5c89e4eSSatish Balay 
2299371c9d4SSatish Balay static struct {
2309371c9d4SSatish Balay   int   code_no;
2319371c9d4SSatish Balay   char *name;
2329371c9d4SSatish Balay } error_codes[] = {
233e5c89e4eSSatish Balay   {FPE_FLTINV, "invalid floating point operand"},
234e5c89e4eSSatish Balay   {FPE_FLTRES, "inexact floating point result" },
235e5c89e4eSSatish Balay   {FPE_FLTDIV, "division-by-zero"              },
236e5c89e4eSSatish Balay   {FPE_FLTUND, "floating point underflow"      },
237e5c89e4eSSatish Balay   {FPE_FLTOVF, "floating point overflow"       },
238e5c89e4eSSatish Balay   {0,          "unknown error"                 }
239e5c89e4eSSatish Balay };
240e5c89e4eSSatish Balay   #define SIGPC(scp) (scp->si_addr)
241e5c89e4eSSatish Balay 
PetscDefaultFPTrap(int sig,siginfo_t * scp,ucontext_t * uap)242d71ae5a4SJacob Faibussowitsch void PetscDefaultFPTrap(int sig, siginfo_t *scp, ucontext_t *uap)
243d71ae5a4SJacob Faibussowitsch {
2445f80ce2aSJacob Faibussowitsch   int err_ind = -1, code = scp->si_code;
245e5c89e4eSSatish Balay 
246e5c89e4eSSatish Balay   PetscFunctionBegin;
2475f80ce2aSJacob Faibussowitsch   for (int j = 0; error_codes[j].code_no; j++) {
248e5c89e4eSSatish Balay     if (error_codes[j].code_no == code) err_ind = j;
249e5c89e4eSSatish Balay   }
250e5c89e4eSSatish Balay 
251dd460d27SBarry Smith   if (err_ind >= 0) (void)(*PetscErrorPrintf)("*** %s occurred at pc=%X ***\n", error_codes[err_ind].name, SIGPC(scp));
252dd460d27SBarry Smith   else (*PetscErrorPrintf)("*** floating point error 0x%x occurred at pc=%X ***\n", code, SIGPC(scp));
253a297a907SKarl Rupp 
254dd460d27SBarry Smith   PetscError(PETSC_COMM_SELF, 0, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_REPEAT, "floating point error");
25541e02c4dSJunchao Zhang   PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP);
256e5c89e4eSSatish Balay }
257e5c89e4eSSatish Balay 
PetscSetFPTrap(PetscFPTrap flag)258d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSetFPTrap(PetscFPTrap flag)
259d71ae5a4SJacob Faibussowitsch {
260e5c89e4eSSatish Balay   char *out;
261e5c89e4eSSatish Balay 
262e5c89e4eSSatish Balay   PetscFunctionBegin;
263e5c89e4eSSatish Balay   /* Clear accumulated exceptions.  Used to suppress meaningless messages from f77 programs */
264e5c89e4eSSatish Balay   (void)ieee_flags("clear", "exception", "all", &out);
265e5c89e4eSSatish Balay   if (flag == PETSC_FP_TRAP_ON) {
266a297a907SKarl Rupp     if (ieee_handler("set", "common", (sigfpe_handler_type)PetscDefaultFPTrap)) (*PetscErrorPrintf)("Can't set floating point handler\n");
267cc9df77eSBarry Smith   } else {
268cc9df77eSBarry Smith     if (ieee_handler("clear", "common", (sigfpe_handler_type)PetscDefaultFPTrap)) (*PetscErrorPrintf)("Can't clear floatingpoint handler\n");
269cc9df77eSBarry Smith   }
270670f3ff9SJed Brown   _trapmode = flag;
271bd2b07b1SBarry Smith   PetscCall(PetscInfo(NULL,"Using PETSC_HAVE_SOLARIS_STYLE_FPTRAP\n");
2723ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
273e5c89e4eSSatish Balay }
274e5c89e4eSSatish Balay 
275d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDetermineInitialFPTrap(void)
276d71ae5a4SJacob Faibussowitsch {
277cc9df77eSBarry Smith   PetscFunctionBegin;
2789566063dSJacob Faibussowitsch   PetscCall(PetscInfo(NULL, "Unable to determine initial floating point trapping. Assuming it is off\n"));
2793ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
280cc9df77eSBarry Smith }
281cc9df77eSBarry Smith 
282e5c89e4eSSatish Balay #elif defined(PETSC_HAVE_IRIX_STYLE_FPTRAP)
283e5c89e4eSSatish Balay   #include <sigfpe.h>
2849371c9d4SSatish Balay static struct {
2859371c9d4SSatish Balay   int   code_no;
2869371c9d4SSatish Balay   char *name;
2879371c9d4SSatish Balay } error_codes[] = {
288e5c89e4eSSatish Balay   {_INVALID, "IEEE operand error"      },
289e5c89e4eSSatish Balay   {_OVERFL,  "floating point overflow" },
290e5c89e4eSSatish Balay   {_UNDERFL, "floating point underflow"},
291e5c89e4eSSatish Balay   {_DIVZERO, "floating point divide"   },
292e5c89e4eSSatish Balay   {0,        "unknown error"           }
293e5c89e4eSSatish Balay };
294d71ae5a4SJacob Faibussowitsch void PetscDefaultFPTrap(unsigned exception[], int val[])
295d71ae5a4SJacob Faibussowitsch {
2965f80ce2aSJacob Faibussowitsch   int err_ind = -1, code = exception[0];
297e5c89e4eSSatish Balay 
298e5c89e4eSSatish Balay   PetscFunctionBegin;
2995f80ce2aSJacob Faibussowitsch   for (int j = 0; error_codes[j].code_no; j++) {
300e5c89e4eSSatish Balay     if (error_codes[j].code_no == code) err_ind = j;
301e5c89e4eSSatish Balay   }
302dd460d27SBarry Smith   if (err_ind >= 0) (void)(*PetscErrorPrintf)("*** %s occurred ***\n", error_codes[err_ind].name);
303dd460d27SBarry Smith   else (void)(*PetscErrorPrintf)("*** floating point error 0x%x occurred ***\n", code);
304a297a907SKarl Rupp 
305dd460d27SBarry Smith   (void)PetscError(PETSC_COMM_SELF, 0, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_REPEAT, "floating point error");
30641e02c4dSJunchao Zhang   PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP);
307e5c89e4eSSatish Balay }
308e5c89e4eSSatish Balay 
309d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSetFPTrap(PetscFPTrap flag)
310d71ae5a4SJacob Faibussowitsch {
311e5c89e4eSSatish Balay   PetscFunctionBegin;
312bd2b07b1SBarry Smith   if (flag == PETSC_FP_TRAP_ON) handle_sigfpes(_ON, , _EN_UNDERFL | _EN_OVERFL | _EN_DIVZERO | _EN_INVALID, PetscDefaultFPTrap, _ABORT_ON_ERROR, 0);
313cc9df77eSBarry Smith   else handle_sigfpes(_OFF, _EN_UNDERFL | _EN_OVERFL | _EN_DIVZERO | _EN_INVALID, 0, _ABORT_ON_ERROR, 0);
314670f3ff9SJed Brown   _trapmode = flag;
315bd2b07b1SBarry Smith   PetscCall(PetscInfo(NULL, "Using PETSC_HAVE_IRIX_STYLE_FPTRAP\n"));
3163ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
317cc9df77eSBarry Smith }
318cc9df77eSBarry Smith 
319d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDetermineInitialFPTrap(void)
320d71ae5a4SJacob Faibussowitsch {
321cc9df77eSBarry Smith   PetscFunctionBegin;
3229566063dSJacob Faibussowitsch   PetscCall(PetscInfo(NULL, "Unable to determine initial floating point trapping. Assuming it is off\n"));
3233ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
324cc9df77eSBarry Smith }
325cc9df77eSBarry Smith 
326cc9df77eSBarry Smith #elif defined(PETSC_HAVE_RS6000_STYLE_FPTRAP)
327e5c89e4eSSatish Balay /* In "fast" mode, floating point traps are imprecise and ignored.
328e5c89e4eSSatish Balay    This is the reason for the fptrap(FP_TRAP_SYNC) call */
329e5c89e4eSSatish Balay struct sigcontext;
330e5c89e4eSSatish Balay   #include <fpxcp.h>
331e5c89e4eSSatish Balay   #include <fptrap.h>
332e5c89e4eSSatish Balay   #define FPE_FLTOPERR_TRAP (fptrap_t)(0x20000000)
333e5c89e4eSSatish Balay   #define FPE_FLTOVF_TRAP   (fptrap_t)(0x10000000)
334e5c89e4eSSatish Balay   #define FPE_FLTUND_TRAP   (fptrap_t)(0x08000000)
335e5c89e4eSSatish Balay   #define FPE_FLTDIV_TRAP   (fptrap_t)(0x04000000)
336e5c89e4eSSatish Balay   #define FPE_FLTINEX_TRAP  (fptrap_t)(0x02000000)
337e5c89e4eSSatish Balay 
3389371c9d4SSatish Balay static struct {
3399371c9d4SSatish Balay   int   code_no;
3409371c9d4SSatish Balay   char *name;
3419371c9d4SSatish Balay } error_codes[] = {
342e5c89e4eSSatish Balay   {FPE_FLTOPERR_TRAP, "IEEE operand error"           },
343e5c89e4eSSatish Balay   {FPE_FLTOVF_TRAP,   "floating point overflow"      },
344e5c89e4eSSatish Balay   {FPE_FLTUND_TRAP,   "floating point underflow"     },
345e5c89e4eSSatish Balay   {FPE_FLTDIV_TRAP,   "floating point divide"        },
346e5c89e4eSSatish Balay   {FPE_FLTINEX_TRAP,  "inexact floating point result"},
347bd2b07b1SBarry Smith   < {0,                 "unknown error"                }
348e5c89e4eSSatish Balay };
349e5c89e4eSSatish Balay   #define SIGPC(scp)        (0) /* Info MIGHT be in scp->sc_jmpbuf.jmp_context.iar */
350e5c89e4eSSatish Balay /*
351e5c89e4eSSatish Balay    For some reason, scp->sc_jmpbuf does not work on the RS6000, even though
352e5c89e4eSSatish Balay    it looks like it should from the include definitions.  It is probably
353e5c89e4eSSatish Balay    some strange interaction with the "POSIX_SOURCE" that we require.
354e5c89e4eSSatish Balay */
355e5c89e4eSSatish Balay 
356d71ae5a4SJacob Faibussowitsch void PetscDefaultFPTrap(int sig, int code, struct sigcontext *scp)
357d71ae5a4SJacob Faibussowitsch {
358e5c89e4eSSatish Balay   int      err_ind, j;
359e5c89e4eSSatish Balay   fp_ctx_t flt_context;
360e5c89e4eSSatish Balay 
361e5c89e4eSSatish Balay   PetscFunctionBegin;
362e5c89e4eSSatish Balay   fp_sh_trap_info(scp, &flt_context);
363e5c89e4eSSatish Balay 
364e5c89e4eSSatish Balay   err_ind = -1;
365e5c89e4eSSatish Balay   for (j = 0; error_codes[j].code_no; j++) {
366e5c89e4eSSatish Balay     if (error_codes[j].code_no == flt_context.trap) err_ind = j;
367e5c89e4eSSatish Balay   }
368e5c89e4eSSatish Balay 
369dd460d27SBarry Smith   if (err_ind >= 0) (void)(*PetscErrorPrintf)("*** %s occurred ***\n", error_codes[err_ind].name);
370dd460d27SBarry Smith   else (void)(*PetscErrorPrintf)("*** floating point error 0x%x occurred ***\n", flt_context.trap);
371a297a907SKarl Rupp 
372dd460d27SBarry Smith   (void)PetscError(PETSC_COMM_SELF, 0, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_REPEAT, "floating point error");
37341e02c4dSJunchao Zhang   PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP);
374e5c89e4eSSatish Balay }
375e5c89e4eSSatish Balay 
376d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSetFPTrap(PetscFPTrap flag)
377d71ae5a4SJacob Faibussowitsch {
378e5c89e4eSSatish Balay   PetscFunctionBegin;
379bd2b07b1SBarry Smith   if (flag == PETSC_FP_TRAP_ON) {
380e5c89e4eSSatish Balay     signal(SIGFPE, (void (*)(int))PetscDefaultFPTrap);
381e5c89e4eSSatish Balay     fp_trap(FP_TRAP_SYNC);
382bd2b07b1SBarry Smith     /* fp_enable(TRP_INVALID | TRP_DIV_BY_ZERO | TRP_OVERFLOW | TRP_UNDERFLOW); */
383bd2b07b1SBarry Smith     fp_enable(TRP_INVALID | TRP_DIV_BY_ZERO | TRP_OVERFLOW);
384e5c89e4eSSatish Balay   } else {
385e5c89e4eSSatish Balay     signal(SIGFPE, SIG_DFL);
386cc9df77eSBarry Smith     fp_disable(TRP_INVALID | TRP_DIV_BY_ZERO | TRP_OVERFLOW | TRP_UNDERFLOW);
387e5c89e4eSSatish Balay     fp_trap(FP_TRAP_OFF);
388e5c89e4eSSatish Balay   }
389cf0818bdSBarry Smith   _trapmode = flag;
390bd2b07b1SBarry Smith   PetscCall(PetscInfo(NULL, "Using PETSC_HAVE_RS6000_STYLE_FPTRAP\n"));
3913ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
392e5c89e4eSSatish Balay }
393e5c89e4eSSatish Balay 
394d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDetermineInitialFPTrap(void)
395d71ae5a4SJacob Faibussowitsch {
396cc9df77eSBarry Smith   PetscFunctionBegin;
3979566063dSJacob Faibussowitsch   PetscCall(PetscInfo(NULL, "Unable to determine initial floating point trapping. Assuming it is off\n"));
3983ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
399cc9df77eSBarry Smith }
400cc9df77eSBarry Smith 
401cc9df77eSBarry Smith #elif defined(PETSC_HAVE_WINDOWS_COMPILERS)
402cc9df77eSBarry Smith   #include <float.h>
403d71ae5a4SJacob Faibussowitsch void PetscDefaultFPTrap(int sig)
404d71ae5a4SJacob Faibussowitsch {
405cc9df77eSBarry Smith   PetscFunctionBegin;
406dd460d27SBarry Smith   (void)(*PetscErrorPrintf)("*** floating point error occurred ***\n");
407dd460d27SBarry Smith   (void)PetscError(PETSC_COMM_SELF, 0, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_REPEAT, "floating point error");
408cc9df77eSBarry Smith   PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP);
409cc9df77eSBarry Smith }
410cc9df77eSBarry Smith 
411d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSetFPTrap(PetscFPTrap flag)
412d71ae5a4SJacob Faibussowitsch {
413cc9df77eSBarry Smith   unsigned int cw;
414cc9df77eSBarry Smith 
415cc9df77eSBarry Smith   PetscFunctionBegin;
416bd2b07b1SBarry Smith   if (flag == PETSC_FP_TRAP_ON) {
417bd2b07b1SBarry Smith     /* cw = _EM_INVALID | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW; */
418bd2b07b1SBarry Smith     cw = _EM_INVALID | _EM_ZERODIVIDE | _EM_OVERFLOW;
41908401ef6SPierre Jolivet     PetscCheck(SIG_ERR != signal(SIGFPE, PetscDefaultFPTrap), PETSC_COMM_SELF, PETSC_ERR_LIB, "Can't set floating point handler");
420cc9df77eSBarry Smith   } else {
421cc9df77eSBarry Smith     cw = 0;
42208401ef6SPierre Jolivet     PetscCheck(SIG_ERR != signal(SIGFPE, SIG_DFL), PETSC_COMM_SELF, PETSC_ERR_LIB, "Can't clear floating point handler");
423cc9df77eSBarry Smith   }
424cc9df77eSBarry Smith   (void)_controlfp(0, cw);
425cf0818bdSBarry Smith   _trapmode = flag;
426bd2b07b1SBarry Smith   PetscCall(PetscInfo(NULL, "Using PETSC_HAVE_WINDOWS_COMPILERS FPTRAP\n"));
4273ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
428cc9df77eSBarry Smith }
429cc9df77eSBarry Smith 
430d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDetermineInitialFPTrap(void)
431d71ae5a4SJacob Faibussowitsch {
432cc9df77eSBarry Smith   PetscFunctionBegin;
4339566063dSJacob Faibussowitsch   PetscCall(PetscInfo(NULL, "Unable to determine initial floating point trapping. Assuming it is off\n"));
4343ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
435cc9df77eSBarry Smith }
436cc9df77eSBarry Smith 
4379a2402e9SBarry Smith #elif defined(PETSC_HAVE_FENV_H) && !defined(__cplusplus)
438b014e56cSJed Brown   /*
439b014e56cSJed Brown    C99 style floating point environment.
440b014e56cSJed Brown 
441b014e56cSJed Brown    Note that C99 merely specifies how to save, restore, and clear the floating
442b014e56cSJed Brown    point environment as well as defining an enumeration of exception codes.  In
443b014e56cSJed Brown    particular, C99 does not specify how to make floating point exceptions raise
444b014e56cSJed Brown    a signal.  Glibc offers this capability through FE_NOMASK_ENV (or with finer
445b014e56cSJed Brown    granularity, feenableexcept()), xmmintrin.h offers _MM_SET_EXCEPTION_MASK().
446b014e56cSJed Brown */
447b014e56cSJed Brown   #include <fenv.h>
448accbd18bSBarry Smith   #if defined(PETSC_HAVE_FE_VALUES)
4499371c9d4SSatish Balay typedef struct {
4509371c9d4SSatish Balay   int         code;
4519371c9d4SSatish Balay   const char *name;
4529371c9d4SSatish Balay } FPNode;
453b014e56cSJed Brown static const FPNode error_codes[] = {
454b014e56cSJed Brown   {FE_DIVBYZERO, "divide by zero"                                 },
455b014e56cSJed Brown   {FE_INEXACT,   "inexact floating point result"                  },
456b014e56cSJed Brown   {FE_INVALID,   "invalid floating point arguments (domain error)"},
457b014e56cSJed Brown   {FE_OVERFLOW,  "floating point overflow"                        },
458b014e56cSJed Brown   {FE_UNDERFLOW, "floating point underflow"                       },
459b014e56cSJed Brown   {0,            "unknown error"                                  }
460b014e56cSJed Brown };
461accbd18bSBarry Smith   #endif
46299e0435eSBarry Smith 
463d71ae5a4SJacob Faibussowitsch void PetscDefaultFPTrap(int sig)
464d71ae5a4SJacob Faibussowitsch {
465accbd18bSBarry Smith   #if defined(PETSC_HAVE_FE_VALUES)
466b014e56cSJed Brown   const FPNode *node;
467b014e56cSJed Brown   int           code;
468ace3abfcSBarry Smith   PetscBool     matched = PETSC_FALSE;
469accbd18bSBarry Smith   #endif
470b014e56cSJed Brown 
471b014e56cSJed Brown   PetscFunctionBegin;
472b014e56cSJed Brown   /* Note: While it is possible for the exception state to be preserved by the
473b014e56cSJed Brown    * kernel, this seems to be rare which makes the following flag testing almost
474b014e56cSJed Brown    * useless.  But on a system where the flags can be preserved, it would provide
4757d125cddSJed Brown    * more detail.
476b014e56cSJed Brown    */
477accbd18bSBarry Smith   #if defined(PETSC_HAVE_FE_VALUES)
478b014e56cSJed Brown   code = fetestexcept(FE_ALL_EXCEPT);
479b014e56cSJed Brown   for (node = &error_codes[0]; node->code; node++) {
480b014e56cSJed Brown     if (code & node->code) {
481b014e56cSJed Brown       matched = PETSC_TRUE;
482dd460d27SBarry Smith       (void)(*PetscErrorPrintf)("*** floating point error \"%s\" occurred ***\n", node->name);
483b014e56cSJed Brown       code &= ~node->code; /* Unset this flag since it has been processed */
484b014e56cSJed Brown     }
485b014e56cSJed Brown   }
486b014e56cSJed Brown   if (!matched || code) { /* If any remaining flags are set, or we didn't process any flags */
487dd460d27SBarry Smith     (void)(*PetscErrorPrintf)("*** unknown floating point error occurred ***\n");
488dd460d27SBarry Smith     (void)(*PetscErrorPrintf)("The specific exception can be determined by running in a debugger.  When the\n");
489dd460d27SBarry Smith     (void)(*PetscErrorPrintf)("debugger traps the signal, the exception can be found with fetestexcept(0x%x)\n", FE_ALL_EXCEPT);
490dd460d27SBarry Smith     (void)(*PetscErrorPrintf)("where the result is a bitwise OR of the following flags:\n");
491dd460d27SBarry Smith     (void)(*PetscErrorPrintf)("FE_INVALID=0x%x FE_DIVBYZERO=0x%x FE_OVERFLOW=0x%x FE_UNDERFLOW=0x%x FE_INEXACT=0x%x\n", FE_INVALID, FE_DIVBYZERO, FE_OVERFLOW, FE_UNDERFLOW, FE_INEXACT);
492b014e56cSJed Brown   }
493accbd18bSBarry Smith   #else
494dd460d27SBarry Smith   (void)(*PetscErrorPrintf)("*** unknown floating point error occurred ***\n");
495accbd18bSBarry Smith   #endif
4967d125cddSJed Brown 
497dd460d27SBarry Smith   (void)(*PetscErrorPrintf)("Try option -start_in_debugger\n");
49827104ee2SJacob Faibussowitsch   #if PetscDefined(USE_DEBUG)
499dfb7d7afSStefano Zampini     #if !PetscDefined(HAVE_THREADSAFETY)
500dd460d27SBarry Smith   (void)(*PetscErrorPrintf)("likely location of problem given in stack below\n");
501dd460d27SBarry Smith   (void)(*PetscErrorPrintf)("---------------------  Stack Frames ------------------------------------\n");
502dd460d27SBarry Smith   (void)PetscStackView(PETSC_STDOUT);
503dfb7d7afSStefano Zampini     #endif
50427104ee2SJacob Faibussowitsch   #else
505dd460d27SBarry Smith   (void)(*PetscErrorPrintf)("configure using --with-debugging=yes, recompile, link, and run \n");
506dd460d27SBarry Smith   (void)(*PetscErrorPrintf)("with -start_in_debugger to get more information on the crash.\n");
50727104ee2SJacob Faibussowitsch   #endif
508dd460d27SBarry Smith   (void)PetscError(PETSC_COMM_SELF, 0, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_INITIAL, "trapped floating point error");
50941e02c4dSJunchao Zhang   PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP);
510b014e56cSJed Brown }
511b014e56cSJed Brown 
512d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSetFPTrap(PetscFPTrap flag)
513d71ae5a4SJacob Faibussowitsch {
514b014e56cSJed Brown   PetscFunctionBegin;
515bd2b07b1SBarry Smith   if (flag == PETSC_FP_TRAP_ON) {
516b014e56cSJed Brown     /* Clear any flags that are currently set so that activating trapping will not immediately call the signal handler. */
517cc73adaaSBarry Smith     PetscCheck(!feclearexcept(FE_ALL_EXCEPT), PETSC_COMM_SELF, PETSC_ERR_LIB, "Cannot clear floating point exception flags");
518accbd18bSBarry Smith   #if defined(FE_NOMASK_ENV) && defined(PETSC_HAVE_FE_VALUES)
519cc9df77eSBarry Smith     /* Could use fesetenv(FE_NOMASK_ENV), but that causes spurious exceptions (like gettimeofday() -> PetscLogDouble). */
520cf0818bdSBarry Smith     /* PetscCheck(feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW) != -1,PETSC_COMM_SELF,PETSC_ERR_LIB,"Cannot activate floating point exceptions"); */
521bd2b07b1SBarry Smith     /* Doesn't work on AArch64 targets. There's a known hardware limitation. Need to detect hardware at configure time? */
522cf0818bdSBarry Smith     PetscCheck(feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW) != -1, PETSC_COMM_SELF, PETSC_ERR_LIB, "Cannot activate floating point exceptions");
523bd2b07b1SBarry Smith     PetscCall(PetscInfo(NULL, "Using PETSC_HAVE_FENV_H FPTRAP with FE_NOMASK_ENV\n"));
524b014e56cSJed Brown   #elif defined PETSC_HAVE_XMMINTRIN_H
525cc9df77eSBarry Smith     _MM_SET_EXCEPTION_MASK(_MM_GET_EXCEPTION_MASK() & ~_MM_MASK_DIV_ZERO);
526bd2b07b1SBarry Smith     /* _MM_SET_EXCEPTION_MASK(_MM_GET_EXCEPTION_MASK() & ~_MM_MASK_UNDERFLOW); */
527cc9df77eSBarry Smith     _MM_SET_EXCEPTION_MASK(_MM_GET_EXCEPTION_MASK() & ~_MM_MASK_OVERFLOW);
528cc9df77eSBarry Smith     _MM_SET_EXCEPTION_MASK(_MM_GET_EXCEPTION_MASK() & ~_MM_MASK_INVALID);
529bd2b07b1SBarry Smith     PetscCall(PetscInfo(NULL, "Using PETSC_HAVE_FENV_H FPTRAP with PETSC_HAVE_XMMINTRIN_H\n"));
530b014e56cSJed Brown   #else
531b014e56cSJed Brown     /* C99 does not provide a way to modify the environment so there is no portable way to activate trapping. */
532bd2b07b1SBarry Smith     PetscCall(PetscInfo(NULL, "Using PETSC_HAVE_FENV_H FPTRAP\n"));
533b014e56cSJed Brown   #endif
53408401ef6SPierre Jolivet     PetscCheck(SIG_ERR != signal(SIGFPE, PetscDefaultFPTrap), PETSC_COMM_SELF, PETSC_ERR_LIB, "Can't set floating point handler");
535b014e56cSJed Brown   } else {
536cc73adaaSBarry Smith     PetscCheck(!fesetenv(FE_DFL_ENV), PETSC_COMM_SELF, PETSC_ERR_LIB, "Cannot disable floating point exceptions");
537cc9df77eSBarry Smith     /* can use _MM_SET_EXCEPTION_MASK(_MM_GET_EXCEPTION_MASK() | _MM_MASK_UNDERFLOW); if PETSC_HAVE_XMMINTRIN_H exists */
53808401ef6SPierre Jolivet     PetscCheck(SIG_ERR != signal(SIGFPE, SIG_DFL), PETSC_COMM_SELF, PETSC_ERR_LIB, "Can't clear floating point handler");
539b014e56cSJed Brown   }
540cf0818bdSBarry Smith   _trapmode = flag;
5413ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
542b014e56cSJed Brown }
543b014e56cSJed Brown 
544d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDetermineInitialFPTrap(void)
545d71ae5a4SJacob Faibussowitsch {
546cc9df77eSBarry Smith   #if defined(FE_NOMASK_ENV) || defined PETSC_HAVE_XMMINTRIN_H
547cc9df77eSBarry Smith   unsigned int flags;
548cc9df77eSBarry Smith   #endif
549cc9df77eSBarry Smith 
550cc9df77eSBarry Smith   PetscFunctionBegin;
551cc9df77eSBarry Smith   #if defined(FE_NOMASK_ENV)
552cc9df77eSBarry Smith   flags = fegetexcept();
553cc9df77eSBarry Smith   if (flags & FE_DIVBYZERO) {
554cc9df77eSBarry Smith   #elif defined PETSC_HAVE_XMMINTRIN_H
555cc9df77eSBarry Smith   flags = _MM_GET_EXCEPTION_MASK();
556cc9df77eSBarry Smith   if (!(flags & _MM_MASK_DIV_ZERO)) {
557cc9df77eSBarry Smith   #else
5589566063dSJacob Faibussowitsch   PetscCall(PetscInfo(NULL, "Floating point trapping unknown, assuming off\n"));
5593ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
560cc9df77eSBarry Smith   #endif
561cc9df77eSBarry Smith   #if defined(FE_NOMASK_ENV) || defined PETSC_HAVE_XMMINTRIN_H
562cc9df77eSBarry Smith     _trapmode = PETSC_FP_TRAP_ON;
5639566063dSJacob Faibussowitsch     PetscCall(PetscInfo(NULL, "Floating point trapping is on by default %d\n", flags));
564cc9df77eSBarry Smith   } else {
565cc9df77eSBarry Smith     _trapmode = PETSC_FP_TRAP_OFF;
5669566063dSJacob Faibussowitsch     PetscCall(PetscInfo(NULL, "Floating point trapping is off by default %d\n", flags));
567cc9df77eSBarry Smith   }
5683ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
569cc9df77eSBarry Smith   #endif
570cc9df77eSBarry Smith }
571cc9df77eSBarry Smith 
572cc9df77eSBarry Smith #elif defined(PETSC_HAVE_IEEEFP_H)
573cc9df77eSBarry Smith   #include <ieeefp.h>
574d71ae5a4SJacob Faibussowitsch void PetscDefaultFPTrap(int sig)
575d71ae5a4SJacob Faibussowitsch {
576cc9df77eSBarry Smith   PetscFunctionBegin;
577dd460d27SBarry Smith   (void)(*PetscErrorPrintf)("*** floating point error occurred ***\n");
578dd460d27SBarry Smith   (void)PetscError(PETSC_COMM_SELF, 0, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_REPEAT, "floating point error");
579cc9df77eSBarry Smith   PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP);
580cc9df77eSBarry Smith }
581cc9df77eSBarry Smith 
582d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSetFPTrap(PetscFPTrap flag)
583d71ae5a4SJacob Faibussowitsch {
584cc9df77eSBarry Smith   PetscFunctionBegin;
585cf0818bdSBarry Smith   if (flag == PETSC_FP_TRAP_ON) {
58618da0197SPierre Jolivet   #if defined(PETSC_HAVE_FPRESETSTICKY)
587cc9df77eSBarry Smith     fpresetsticky(fpgetsticky());
588cc9df77eSBarry Smith   #elif defined(PETSC_HAVE_FPSETSTICKY)
589cc9df77eSBarry Smith     fpsetsticky(fpgetsticky());
590cc9df77eSBarry Smith   #endif
591cc9df77eSBarry Smith     fpsetmask(FP_X_INV | FP_X_DZ | FP_X_OFL | FP_X_OFL);
59208401ef6SPierre Jolivet     PetscCheck(SIG_ERR != signal(SIGFPE, PetscDefaultFPTrap), PETSC_COMM_SELF, PETSC_ERR_LIB, "Can't set floating point handler");
593cc9df77eSBarry Smith   } else {
59418da0197SPierre Jolivet   #if defined(PETSC_HAVE_FPRESETSTICKY)
595cc9df77eSBarry Smith     fpresetsticky(fpgetsticky());
596cc9df77eSBarry Smith   #elif defined(PETSC_HAVE_FPSETSTICKY)
597cc9df77eSBarry Smith     fpsetsticky(fpgetsticky());
598cc9df77eSBarry Smith   #endif
599cc9df77eSBarry Smith     fpsetmask(0);
60008401ef6SPierre Jolivet     PetscCheck(SIG_ERR != signal(SIGFPE, SIG_DFL), PETSC_COMM_SELF, PETSC_ERR_LIB, "Can't clear floating point handler");
601cc9df77eSBarry Smith   }
602cf0818bdSBarry Smith   _trapmode = flag;
603bd2b07b1SBarry Smith   PetscCall(PetscInfo(NULL, "Using PETSC_HAVE_IEEEFP_H FPTRAP\n"));
6043ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
605cc9df77eSBarry Smith }
606cc9df77eSBarry Smith 
607d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDetermineInitialFPTrap(void)
608d71ae5a4SJacob Faibussowitsch {
609cc9df77eSBarry Smith   PetscFunctionBegin;
6109566063dSJacob Faibussowitsch   PetscCall(PetscInfo(NULL, "Unable to determine initial floating point trapping. Assuming it is off\n"));
6113ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
612cc9df77eSBarry Smith }
613cc9df77eSBarry Smith 
614*21789920SBarry Smith /* Default */
615e5c89e4eSSatish Balay #else
61699e0435eSBarry Smith 
61766976f2fSJacob Faibussowitsch static void PetscDefaultFPTrap(int sig)
618d71ae5a4SJacob Faibussowitsch {
619e5c89e4eSSatish Balay   PetscFunctionBegin;
620dd460d27SBarry Smith   (void)(*PetscErrorPrintf)("*** floating point error occurred ***\n");
621dd460d27SBarry Smith   (void)PetscError(PETSC_COMM_SELF, 0, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_REPEAT, "floating point error");
62241e02c4dSJunchao Zhang   PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP);
623e5c89e4eSSatish Balay }
62499e0435eSBarry Smith 
625d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSetFPTrap(PetscFPTrap flag)
626d71ae5a4SJacob Faibussowitsch {
627e5c89e4eSSatish Balay   PetscFunctionBegin;
628bd2b07b1SBarry Smith   if (flag == PETSC_FP_TRAP_ON) {
6293ba16761SJacob Faibussowitsch     if (SIG_ERR == signal(SIGFPE, PetscDefaultFPTrap)) PetscCall((*PetscErrorPrintf)("Can't set floatingpoint handler\n"));
6303ba16761SJacob Faibussowitsch   } else if (SIG_ERR == signal(SIGFPE, SIG_DFL)) PetscCall((*PetscErrorPrintf)("Can't clear floatingpoint handler\n"));
631a297a907SKarl Rupp 
632cf0818bdSBarry Smith   _trapmode = flag;
633bd2b07b1SBarry Smith   PetscCall(PetscInfo(NULL, "Using default FPTRAP\n"));
6343ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
635e5c89e4eSSatish Balay }
636cc9df77eSBarry Smith 
637d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDetermineInitialFPTrap(void)
638d71ae5a4SJacob Faibussowitsch {
639cc9df77eSBarry Smith   PetscFunctionBegin;
6409566063dSJacob Faibussowitsch   PetscCall(PetscInfo(NULL, "Unable to determine initial floating point trapping. Assuming it is off\n"));
6413ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
642cc9df77eSBarry Smith }
643e5c89e4eSSatish Balay #endif
644