xref: /petsc/src/sys/error/fp.c (revision dd460d279d400be05a060420ac00c7301eb4da3f)
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 @*/
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 @*/
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 /*--------------------------------------- ---------------------------------------------------*/
100e5c89e4eSSatish Balay #if defined(PETSC_HAVE_SUN4_STYLE_FPTRAP)
101e5c89e4eSSatish Balay   #include <floatingpoint.h>
102e5c89e4eSSatish Balay 
1038cc058d9SJed Brown PETSC_EXTERN PetscErrorCode ieee_flags(char *, char *, char *, char **);
1048cc058d9SJed Brown PETSC_EXTERN PetscErrorCode ieee_handler(char *, char *, sigfpe_handler_type(int, int, struct sigcontext *, char *));
105e5c89e4eSSatish Balay 
1069371c9d4SSatish Balay static struct {
1079371c9d4SSatish Balay   int   code_no;
1089371c9d4SSatish Balay   char *name;
1099371c9d4SSatish Balay } error_codes[] = {
110e5c89e4eSSatish Balay   {FPE_INTDIV_TRAP,   "integer divide"               },
111e5c89e4eSSatish Balay   {FPE_FLTOPERR_TRAP, "IEEE operand error"           },
112e5c89e4eSSatish Balay   {FPE_FLTOVF_TRAP,   "floating point overflow"      },
113e5c89e4eSSatish Balay   {FPE_FLTUND_TRAP,   "floating point underflow"     },
114e5c89e4eSSatish Balay   {FPE_FLTDIV_TRAP,   "floating pointing divide"     },
115e5c89e4eSSatish Balay   {FPE_FLTINEX_TRAP,  "inexact floating point result"},
116e5c89e4eSSatish Balay   {0,                 "unknown error"                }
117e5c89e4eSSatish Balay };
118e5c89e4eSSatish Balay   #define SIGPC(scp) (scp->sc_pc)
119e5c89e4eSSatish Balay 
120cf0818bdSBarry Smith /* this function gets called if a trap has occurred and been caught */
121d71ae5a4SJacob Faibussowitsch sigfpe_handler_type PetscDefaultFPTrap(int sig, int code, struct sigcontext *scp, char *addr)
122d71ae5a4SJacob Faibussowitsch {
1235f80ce2aSJacob Faibussowitsch   int err_ind = -1;
124e5c89e4eSSatish Balay 
125e5c89e4eSSatish Balay   PetscFunctionBegin;
1265f80ce2aSJacob Faibussowitsch   for (int j = 0; error_codes[j].code_no; j++) {
127e5c89e4eSSatish Balay     if (error_codes[j].code_no == code) err_ind = j;
128e5c89e4eSSatish Balay   }
129e5c89e4eSSatish Balay 
130*dd460d27SBarry Smith   if (err_ind >= 0) (void)(*PetscErrorPrintf)("*** %s occurred at pc=%X ***\n", error_codes[err_ind].name, SIGPC(scp));
131*dd460d27SBarry Smith   else (void)(*PetscErrorPrintf)("*** floating point error 0x%x occurred at pc=%X ***\n", code, SIGPC(scp));
132a297a907SKarl Rupp 
133*dd460d27SBarry Smith   (void)PetscError(PETSC_COMM_SELF, PETSC_ERR_FP, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_REPEAT, "floating point error");
13441e02c4dSJunchao Zhang   PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP);
1353ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
136e5c89e4eSSatish Balay }
137e5c89e4eSSatish Balay 
138e30d2299SSatish Balay /*@
139cf0818bdSBarry Smith    PetscSetFPTrap - Enables traps/exceptions on common floating point errors. This option may not work on certain systems or only a
140cf0818bdSBarry Smith    subset of exceptions may be trapable.
141e5c89e4eSSatish Balay 
142e5c89e4eSSatish Balay    Not Collective
143e5c89e4eSSatish Balay 
1442fe279fdSBarry Smith    Input Parameter:
145cf0818bdSBarry Smith .  flag - values are
146cf0818bdSBarry Smith .vb
147cf0818bdSBarry Smith     PETSC_FP_TRAP_OFF   - do not trap any exceptions
148cf0818bdSBarry Smith     PETSC_FP_TRAP_ON - all exceptions that are possible on the system except underflow
149cf0818bdSBarry Smith     PETSC_FP_TRAP_INDIV - integer divide by zero
150cf0818bdSBarry Smith     PETSC_FP_TRAP_FLTOPERR - improper argument to function, for example with real numbers, the square root of a negative number
151cf0818bdSBarry Smith     PETSC_FP_TRAP_FLTOVF - overflow
152cf0818bdSBarry Smith     PETSC_FP_TRAP_FLTUND - underflow - not trapped by default on most systems
153cf0818bdSBarry Smith     PETSC_FP_TRAP_FLTDIV - floating point divide by zero
154cf0818bdSBarry Smith     PETSC_FP_TRAP_FLTINEX - inexact floating point result
155cf0818bdSBarry Smith .ve
156e5c89e4eSSatish Balay 
1572fe279fdSBarry Smith    Options Database Key:
158cf0818bdSBarry Smith .  -fp_trap <off,on> - turn on or off trapping of floating point exceptions
159e5c89e4eSSatish Balay 
160e5c89e4eSSatish Balay    Level: advanced
161e5c89e4eSSatish Balay 
162cf0818bdSBarry Smith    Notes:
1637de69702SBarry Smith    Preferred usage is `PetscFPTrapPush()` and `PetscFPTrapPop()` instead of this routine
1647de69702SBarry Smith 
165811af0c4SBarry Smith    Currently only `PETSC_FP_TRAP_OFF` and `PETSC_FP_TRAP_ON` are handled. All others are treated as `PETSC_FP_TRAP_ON`.
166cf0818bdSBarry Smith 
167cf0818bdSBarry Smith    The values are bit values and may be |ed together in the function call
168cf0818bdSBarry Smith 
169cf0818bdSBarry Smith    On systems that support it this routine causes floating point
170cf0818bdSBarry Smith    overflow, divide-by-zero, and invalid-operand (e.g., a NaN), but not underflow, to
171e5c89e4eSSatish Balay    cause a message to be printed and the program to exit.
172e5c89e4eSSatish Balay 
173cc9df77eSBarry Smith    On many common systems, the floating
1747d125cddSJed Brown    point exception state is not preserved from the location where the trap
1757d125cddSJed Brown    occurred through to the signal handler.  In this case, the signal handler
1767d125cddSJed Brown    will just say that an unknown floating point exception occurred and which
1777d125cddSJed Brown    function it occurred in.  If you run with -fp_trap in a debugger, it will
178cc9df77eSBarry Smith    break on the line where the error occurred.  On systems that support C99
179cc9df77eSBarry Smith    floating point exception handling You can check which
1807d125cddSJed Brown    exception occurred using fetestexcept(FE_ALL_EXCEPT).  See fenv.h
1817d125cddSJed Brown    (usually at /usr/include/bits/fenv.h) for the enum values on your system.
1827d125cddSJed Brown 
183db781477SPatrick Sanan .seealso: `PetscFPTrapPush()`, `PetscFPTrapPop()`, `PetscDetermineInitialFPTrap()`
184e5c89e4eSSatish Balay @*/
185d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSetFPTrap(PetscFPTrap flag)
186d71ae5a4SJacob Faibussowitsch {
187e5c89e4eSSatish Balay   char *out;
188e5c89e4eSSatish Balay 
189e5c89e4eSSatish Balay   PetscFunctionBegin;
190e5c89e4eSSatish Balay   /* Clear accumulated exceptions.  Used to suppress meaningless messages from f77 programs */
191e5c89e4eSSatish Balay   (void)ieee_flags("clear", "exception", "all", &out);
192bd2b07b1SBarry Smith   if (flag == PETSC_FP_TRAP_ON) {
193e5c89e4eSSatish Balay     /*
194a297a907SKarl Rupp       To trap more fp exceptions, including underflow, change the line below to
195e5c89e4eSSatish Balay       if (ieee_handler("set","all",PetscDefaultFPTrap)) {
196e5c89e4eSSatish Balay     */
197a297a907SKarl Rupp     if (ieee_handler("set", "common", PetscDefaultFPTrap)) (*PetscErrorPrintf)("Can't set floatingpoint handler\n");
198a297a907SKarl Rupp   } else if (ieee_handler("clear", "common", PetscDefaultFPTrap)) (*PetscErrorPrintf)("Can't clear floatingpoint handler\n");
199a297a907SKarl Rupp 
200670f3ff9SJed Brown   _trapmode = flag;
201bd2b07b1SBarry Smith   PetscCall(PetscInfo(NULL, "Using PETSC_HAVE_SUN4_STYLE_FPTRAP\n"));
2023ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
203e5c89e4eSSatish Balay }
204e5c89e4eSSatish Balay 
205cc9df77eSBarry Smith /*@
206811af0c4SBarry Smith    PetscDetermineInitialFPTrap - Attempts to determine the floating point trapping that exists when `PetscInitialize()` is called
207cc9df77eSBarry Smith 
208cc9df77eSBarry Smith    Not Collective
209cc9df77eSBarry Smith 
210811af0c4SBarry Smith    Note:
211337bb527SBarry Smith    Currently only supported on Linux and macOS. Checks if divide by zero is enable and if so declares that trapping is on.
212cc9df77eSBarry Smith 
213ee300463SSatish Balay    Level: advanced
214cc9df77eSBarry Smith 
215db781477SPatrick Sanan .seealso: `PetscFPTrapPush()`, `PetscFPTrapPop()`, `PetscDetermineInitialFPTrap()`
216cc9df77eSBarry Smith @*/
217d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDetermineInitialFPTrap(void)
218d71ae5a4SJacob Faibussowitsch {
219cc9df77eSBarry Smith   PetscFunctionBegin;
2209566063dSJacob Faibussowitsch   PetscCall(PetscInfo(NULL, "Unable to determine initial floating point trapping. Assuming it is off\n"));
2213ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
222cc9df77eSBarry Smith }
223cc9df77eSBarry Smith 
224e5c89e4eSSatish Balay /* -------------------------------------------------------------------------------------------*/
225e5c89e4eSSatish Balay #elif defined(PETSC_HAVE_SOLARIS_STYLE_FPTRAP)
226e5c89e4eSSatish Balay   #include <sunmath.h>
227e5c89e4eSSatish Balay   #include <floatingpoint.h>
228e5c89e4eSSatish Balay   #include <siginfo.h>
229e5c89e4eSSatish Balay   #include <ucontext.h>
230e5c89e4eSSatish Balay 
2319371c9d4SSatish Balay static struct {
2329371c9d4SSatish Balay   int   code_no;
2339371c9d4SSatish Balay   char *name;
2349371c9d4SSatish Balay } error_codes[] = {
235e5c89e4eSSatish Balay   {FPE_FLTINV, "invalid floating point operand"},
236e5c89e4eSSatish Balay   {FPE_FLTRES, "inexact floating point result" },
237e5c89e4eSSatish Balay   {FPE_FLTDIV, "division-by-zero"              },
238e5c89e4eSSatish Balay   {FPE_FLTUND, "floating point underflow"      },
239e5c89e4eSSatish Balay   {FPE_FLTOVF, "floating point overflow"       },
240e5c89e4eSSatish Balay   {0,          "unknown error"                 }
241e5c89e4eSSatish Balay };
242e5c89e4eSSatish Balay   #define SIGPC(scp) (scp->si_addr)
243e5c89e4eSSatish Balay 
244d71ae5a4SJacob Faibussowitsch void PetscDefaultFPTrap(int sig, siginfo_t *scp, ucontext_t *uap)
245d71ae5a4SJacob Faibussowitsch {
2465f80ce2aSJacob Faibussowitsch   int err_ind = -1, code = scp->si_code;
247e5c89e4eSSatish Balay 
248e5c89e4eSSatish Balay   PetscFunctionBegin;
2495f80ce2aSJacob Faibussowitsch   for (int j = 0; error_codes[j].code_no; j++) {
250e5c89e4eSSatish Balay     if (error_codes[j].code_no == code) err_ind = j;
251e5c89e4eSSatish Balay   }
252e5c89e4eSSatish Balay 
253*dd460d27SBarry Smith   if (err_ind >= 0) (void)(*PetscErrorPrintf)("*** %s occurred at pc=%X ***\n", error_codes[err_ind].name, SIGPC(scp));
254*dd460d27SBarry Smith   else (*PetscErrorPrintf)("*** floating point error 0x%x occurred at pc=%X ***\n", code, SIGPC(scp));
255a297a907SKarl Rupp 
256*dd460d27SBarry Smith   PetscError(PETSC_COMM_SELF, 0, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_REPEAT, "floating point error");
25741e02c4dSJunchao Zhang   PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP);
258e5c89e4eSSatish Balay }
259e5c89e4eSSatish Balay 
260d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSetFPTrap(PetscFPTrap flag)
261d71ae5a4SJacob Faibussowitsch {
262e5c89e4eSSatish Balay   char *out;
263e5c89e4eSSatish Balay 
264e5c89e4eSSatish Balay   PetscFunctionBegin;
265e5c89e4eSSatish Balay   /* Clear accumulated exceptions.  Used to suppress meaningless messages from f77 programs */
266e5c89e4eSSatish Balay   (void)ieee_flags("clear", "exception", "all", &out);
267e5c89e4eSSatish Balay   if (flag == PETSC_FP_TRAP_ON) {
268a297a907SKarl Rupp     if (ieee_handler("set", "common", (sigfpe_handler_type)PetscDefaultFPTrap)) (*PetscErrorPrintf)("Can't set floating point handler\n");
269cc9df77eSBarry Smith   } else {
270cc9df77eSBarry Smith     if (ieee_handler("clear", "common", (sigfpe_handler_type)PetscDefaultFPTrap)) (*PetscErrorPrintf)("Can't clear floatingpoint handler\n");
271cc9df77eSBarry Smith   }
272670f3ff9SJed Brown   _trapmode = flag;
273bd2b07b1SBarry Smith   PetscCall(PetscInfo(NULL,"Using PETSC_HAVE_SOLARIS_STYLE_FPTRAP\n");
2743ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
275e5c89e4eSSatish Balay }
276e5c89e4eSSatish Balay 
277d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDetermineInitialFPTrap(void)
278d71ae5a4SJacob Faibussowitsch {
279cc9df77eSBarry Smith   PetscFunctionBegin;
2809566063dSJacob Faibussowitsch   PetscCall(PetscInfo(NULL, "Unable to determine initial floating point trapping. Assuming it is off\n"));
2813ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
282cc9df77eSBarry Smith }
283cc9df77eSBarry Smith 
284cc9df77eSBarry Smith /* ------------------------------------------------------------------------------------------*/
285e5c89e4eSSatish Balay #elif defined(PETSC_HAVE_IRIX_STYLE_FPTRAP)
286e5c89e4eSSatish Balay   #include <sigfpe.h>
2879371c9d4SSatish Balay static struct {
2889371c9d4SSatish Balay   int   code_no;
2899371c9d4SSatish Balay   char *name;
2909371c9d4SSatish Balay } error_codes[] = {
291e5c89e4eSSatish Balay   {_INVALID, "IEEE operand error"      },
292e5c89e4eSSatish Balay   {_OVERFL,  "floating point overflow" },
293e5c89e4eSSatish Balay   {_UNDERFL, "floating point underflow"},
294e5c89e4eSSatish Balay   {_DIVZERO, "floating point divide"   },
295e5c89e4eSSatish Balay   {0,        "unknown error"           }
296e5c89e4eSSatish Balay };
297d71ae5a4SJacob Faibussowitsch void PetscDefaultFPTrap(unsigned exception[], int val[])
298d71ae5a4SJacob Faibussowitsch {
2995f80ce2aSJacob Faibussowitsch   int err_ind = -1, code = exception[0];
300e5c89e4eSSatish Balay 
301e5c89e4eSSatish Balay   PetscFunctionBegin;
3025f80ce2aSJacob Faibussowitsch   for (int j = 0; error_codes[j].code_no; j++) {
303e5c89e4eSSatish Balay     if (error_codes[j].code_no == code) err_ind = j;
304e5c89e4eSSatish Balay   }
305*dd460d27SBarry Smith   if (err_ind >= 0) (void)(*PetscErrorPrintf)("*** %s occurred ***\n", error_codes[err_ind].name);
306*dd460d27SBarry Smith   else (void)(*PetscErrorPrintf)("*** floating point error 0x%x occurred ***\n", code);
307a297a907SKarl Rupp 
308*dd460d27SBarry Smith   (void)PetscError(PETSC_COMM_SELF, 0, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_REPEAT, "floating point error");
30941e02c4dSJunchao Zhang   PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP);
310e5c89e4eSSatish Balay }
311e5c89e4eSSatish Balay 
312d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSetFPTrap(PetscFPTrap flag)
313d71ae5a4SJacob Faibussowitsch {
314e5c89e4eSSatish Balay   PetscFunctionBegin;
315bd2b07b1SBarry Smith   if (flag == PETSC_FP_TRAP_ON) handle_sigfpes(_ON, , _EN_UNDERFL | _EN_OVERFL | _EN_DIVZERO | _EN_INVALID, PetscDefaultFPTrap, _ABORT_ON_ERROR, 0);
316cc9df77eSBarry Smith   else handle_sigfpes(_OFF, _EN_UNDERFL | _EN_OVERFL | _EN_DIVZERO | _EN_INVALID, 0, _ABORT_ON_ERROR, 0);
317670f3ff9SJed Brown   _trapmode = flag;
318bd2b07b1SBarry Smith   PetscCall(PetscInfo(NULL, "Using PETSC_HAVE_IRIX_STYLE_FPTRAP\n"));
3193ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
320cc9df77eSBarry Smith }
321cc9df77eSBarry Smith 
322d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDetermineInitialFPTrap(void)
323d71ae5a4SJacob Faibussowitsch {
324cc9df77eSBarry Smith   PetscFunctionBegin;
3259566063dSJacob Faibussowitsch   PetscCall(PetscInfo(NULL, "Unable to determine initial floating point trapping. Assuming it is off\n"));
3263ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
327cc9df77eSBarry Smith }
328cc9df77eSBarry Smith 
329cc9df77eSBarry Smith /*----------------------------------------------- --------------------------------------------*/
330cc9df77eSBarry Smith #elif defined(PETSC_HAVE_RS6000_STYLE_FPTRAP)
331e5c89e4eSSatish Balay /* In "fast" mode, floating point traps are imprecise and ignored.
332e5c89e4eSSatish Balay    This is the reason for the fptrap(FP_TRAP_SYNC) call */
333e5c89e4eSSatish Balay struct sigcontext;
334e5c89e4eSSatish Balay   #include <fpxcp.h>
335e5c89e4eSSatish Balay   #include <fptrap.h>
336e5c89e4eSSatish Balay   #define FPE_FLTOPERR_TRAP (fptrap_t)(0x20000000)
337e5c89e4eSSatish Balay   #define FPE_FLTOVF_TRAP   (fptrap_t)(0x10000000)
338e5c89e4eSSatish Balay   #define FPE_FLTUND_TRAP   (fptrap_t)(0x08000000)
339e5c89e4eSSatish Balay   #define FPE_FLTDIV_TRAP   (fptrap_t)(0x04000000)
340e5c89e4eSSatish Balay   #define FPE_FLTINEX_TRAP  (fptrap_t)(0x02000000)
341e5c89e4eSSatish Balay 
3429371c9d4SSatish Balay static struct {
3439371c9d4SSatish Balay   int   code_no;
3449371c9d4SSatish Balay   char *name;
3459371c9d4SSatish Balay } error_codes[] = {
346e5c89e4eSSatish Balay   {FPE_FLTOPERR_TRAP, "IEEE operand error"           },
347e5c89e4eSSatish Balay   {FPE_FLTOVF_TRAP,   "floating point overflow"      },
348e5c89e4eSSatish Balay   {FPE_FLTUND_TRAP,   "floating point underflow"     },
349e5c89e4eSSatish Balay   {FPE_FLTDIV_TRAP,   "floating point divide"        },
350e5c89e4eSSatish Balay   {FPE_FLTINEX_TRAP,  "inexact floating point result"},
351bd2b07b1SBarry Smith   < {0,                 "unknown error"                }
352e5c89e4eSSatish Balay };
353e5c89e4eSSatish Balay   #define SIGPC(scp)        (0) /* Info MIGHT be in scp->sc_jmpbuf.jmp_context.iar */
354e5c89e4eSSatish Balay /*
355e5c89e4eSSatish Balay    For some reason, scp->sc_jmpbuf does not work on the RS6000, even though
356e5c89e4eSSatish Balay    it looks like it should from the include definitions.  It is probably
357e5c89e4eSSatish Balay    some strange interaction with the "POSIX_SOURCE" that we require.
358e5c89e4eSSatish Balay */
359e5c89e4eSSatish Balay 
360d71ae5a4SJacob Faibussowitsch void PetscDefaultFPTrap(int sig, int code, struct sigcontext *scp)
361d71ae5a4SJacob Faibussowitsch {
362e5c89e4eSSatish Balay   int      err_ind, j;
363e5c89e4eSSatish Balay   fp_ctx_t flt_context;
364e5c89e4eSSatish Balay 
365e5c89e4eSSatish Balay   PetscFunctionBegin;
366e5c89e4eSSatish Balay   fp_sh_trap_info(scp, &flt_context);
367e5c89e4eSSatish Balay 
368e5c89e4eSSatish Balay   err_ind = -1;
369e5c89e4eSSatish Balay   for (j = 0; error_codes[j].code_no; j++) {
370e5c89e4eSSatish Balay     if (error_codes[j].code_no == flt_context.trap) err_ind = j;
371e5c89e4eSSatish Balay   }
372e5c89e4eSSatish Balay 
373*dd460d27SBarry Smith   if (err_ind >= 0) (void)(*PetscErrorPrintf)("*** %s occurred ***\n", error_codes[err_ind].name);
374*dd460d27SBarry Smith   else (void)(*PetscErrorPrintf)("*** floating point error 0x%x occurred ***\n", flt_context.trap);
375a297a907SKarl Rupp 
376*dd460d27SBarry Smith   (void)PetscError(PETSC_COMM_SELF, 0, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_REPEAT, "floating point error");
37741e02c4dSJunchao Zhang   PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP);
378e5c89e4eSSatish Balay }
379e5c89e4eSSatish Balay 
380d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSetFPTrap(PetscFPTrap flag)
381d71ae5a4SJacob Faibussowitsch {
382e5c89e4eSSatish Balay   PetscFunctionBegin;
383bd2b07b1SBarry Smith   if (flag == PETSC_FP_TRAP_ON) {
384e5c89e4eSSatish Balay     signal(SIGFPE, (void (*)(int))PetscDefaultFPTrap);
385e5c89e4eSSatish Balay     fp_trap(FP_TRAP_SYNC);
386bd2b07b1SBarry Smith     /* fp_enable(TRP_INVALID | TRP_DIV_BY_ZERO | TRP_OVERFLOW | TRP_UNDERFLOW); */
387bd2b07b1SBarry Smith     fp_enable(TRP_INVALID | TRP_DIV_BY_ZERO | TRP_OVERFLOW);
388e5c89e4eSSatish Balay   } else {
389e5c89e4eSSatish Balay     signal(SIGFPE, SIG_DFL);
390cc9df77eSBarry Smith     fp_disable(TRP_INVALID | TRP_DIV_BY_ZERO | TRP_OVERFLOW | TRP_UNDERFLOW);
391e5c89e4eSSatish Balay     fp_trap(FP_TRAP_OFF);
392e5c89e4eSSatish Balay   }
393cf0818bdSBarry Smith   _trapmode = flag;
394bd2b07b1SBarry Smith   PetscCall(PetscInfo(NULL, "Using PETSC_HAVE_RS6000_STYLE_FPTRAP\n"));
3953ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
396e5c89e4eSSatish Balay }
397e5c89e4eSSatish Balay 
398d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDetermineInitialFPTrap(void)
399d71ae5a4SJacob Faibussowitsch {
400cc9df77eSBarry Smith   PetscFunctionBegin;
4019566063dSJacob Faibussowitsch   PetscCall(PetscInfo(NULL, "Unable to determine initial floating point trapping. Assuming it is off\n"));
4023ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
403cc9df77eSBarry Smith }
404cc9df77eSBarry Smith 
405cc9df77eSBarry Smith /* ------------------------------------------------------------*/
406cc9df77eSBarry Smith #elif defined(PETSC_HAVE_WINDOWS_COMPILERS)
407cc9df77eSBarry Smith   #include <float.h>
408d71ae5a4SJacob Faibussowitsch void PetscDefaultFPTrap(int sig)
409d71ae5a4SJacob Faibussowitsch {
410cc9df77eSBarry Smith   PetscFunctionBegin;
411*dd460d27SBarry Smith   (void)(*PetscErrorPrintf)("*** floating point error occurred ***\n");
412*dd460d27SBarry Smith   (void)PetscError(PETSC_COMM_SELF, 0, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_REPEAT, "floating point error");
413cc9df77eSBarry Smith   PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP);
414cc9df77eSBarry Smith }
415cc9df77eSBarry Smith 
416d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSetFPTrap(PetscFPTrap flag)
417d71ae5a4SJacob Faibussowitsch {
418cc9df77eSBarry Smith   unsigned int cw;
419cc9df77eSBarry Smith 
420cc9df77eSBarry Smith   PetscFunctionBegin;
421bd2b07b1SBarry Smith   if (flag == PETSC_FP_TRAP_ON) {
422bd2b07b1SBarry Smith     /* cw = _EM_INVALID | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW; */
423bd2b07b1SBarry Smith     cw = _EM_INVALID | _EM_ZERODIVIDE | _EM_OVERFLOW;
42408401ef6SPierre Jolivet     PetscCheck(SIG_ERR != signal(SIGFPE, PetscDefaultFPTrap), PETSC_COMM_SELF, PETSC_ERR_LIB, "Can't set floating point handler");
425cc9df77eSBarry Smith   } else {
426cc9df77eSBarry Smith     cw = 0;
42708401ef6SPierre Jolivet     PetscCheck(SIG_ERR != signal(SIGFPE, SIG_DFL), PETSC_COMM_SELF, PETSC_ERR_LIB, "Can't clear floating point handler");
428cc9df77eSBarry Smith   }
429cc9df77eSBarry Smith   (void)_controlfp(0, cw);
430cf0818bdSBarry Smith   _trapmode = flag;
431bd2b07b1SBarry Smith   PetscCall(PetscInfo(NULL, "Using PETSC_HAVE_WINDOWS_COMPILERS FPTRAP\n"));
4323ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
433cc9df77eSBarry Smith }
434cc9df77eSBarry Smith 
435d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDetermineInitialFPTrap(void)
436d71ae5a4SJacob Faibussowitsch {
437cc9df77eSBarry Smith   PetscFunctionBegin;
4389566063dSJacob Faibussowitsch   PetscCall(PetscInfo(NULL, "Unable to determine initial floating point trapping. Assuming it is off\n"));
4393ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
440cc9df77eSBarry Smith }
441cc9df77eSBarry Smith 
442cc9df77eSBarry Smith /* ------------------------------------------------------------*/
4439a2402e9SBarry Smith #elif defined(PETSC_HAVE_FENV_H) && !defined(__cplusplus)
444b014e56cSJed Brown   /*
445b014e56cSJed Brown    C99 style floating point environment.
446b014e56cSJed Brown 
447b014e56cSJed Brown    Note that C99 merely specifies how to save, restore, and clear the floating
448b014e56cSJed Brown    point environment as well as defining an enumeration of exception codes.  In
449b014e56cSJed Brown    particular, C99 does not specify how to make floating point exceptions raise
450b014e56cSJed Brown    a signal.  Glibc offers this capability through FE_NOMASK_ENV (or with finer
451b014e56cSJed Brown    granularity, feenableexcept()), xmmintrin.h offers _MM_SET_EXCEPTION_MASK().
452b014e56cSJed Brown */
453b014e56cSJed Brown   #include <fenv.h>
454accbd18bSBarry Smith   #if defined(PETSC_HAVE_FE_VALUES)
4559371c9d4SSatish Balay typedef struct {
4569371c9d4SSatish Balay   int         code;
4579371c9d4SSatish Balay   const char *name;
4589371c9d4SSatish Balay } FPNode;
459b014e56cSJed Brown static const FPNode error_codes[] = {
460b014e56cSJed Brown   {FE_DIVBYZERO, "divide by zero"                                 },
461b014e56cSJed Brown   {FE_INEXACT,   "inexact floating point result"                  },
462b014e56cSJed Brown   {FE_INVALID,   "invalid floating point arguments (domain error)"},
463b014e56cSJed Brown   {FE_OVERFLOW,  "floating point overflow"                        },
464b014e56cSJed Brown   {FE_UNDERFLOW, "floating point underflow"                       },
465b014e56cSJed Brown   {0,            "unknown error"                                  }
466b014e56cSJed Brown };
467accbd18bSBarry Smith   #endif
46899e0435eSBarry Smith 
469d71ae5a4SJacob Faibussowitsch void PetscDefaultFPTrap(int sig)
470d71ae5a4SJacob Faibussowitsch {
471accbd18bSBarry Smith   #if defined(PETSC_HAVE_FE_VALUES)
472b014e56cSJed Brown   const FPNode *node;
473b014e56cSJed Brown   int           code;
474ace3abfcSBarry Smith   PetscBool     matched = PETSC_FALSE;
475accbd18bSBarry Smith   #endif
476b014e56cSJed Brown 
477b014e56cSJed Brown   PetscFunctionBegin;
478b014e56cSJed Brown   /* Note: While it is possible for the exception state to be preserved by the
479b014e56cSJed Brown    * kernel, this seems to be rare which makes the following flag testing almost
480b014e56cSJed Brown    * useless.  But on a system where the flags can be preserved, it would provide
4817d125cddSJed Brown    * more detail.
482b014e56cSJed Brown    */
483accbd18bSBarry Smith   #if defined(PETSC_HAVE_FE_VALUES)
484b014e56cSJed Brown   code = fetestexcept(FE_ALL_EXCEPT);
485b014e56cSJed Brown   for (node = &error_codes[0]; node->code; node++) {
486b014e56cSJed Brown     if (code & node->code) {
487b014e56cSJed Brown       matched = PETSC_TRUE;
488*dd460d27SBarry Smith       (void)(*PetscErrorPrintf)("*** floating point error \"%s\" occurred ***\n", node->name);
489b014e56cSJed Brown       code &= ~node->code; /* Unset this flag since it has been processed */
490b014e56cSJed Brown     }
491b014e56cSJed Brown   }
492b014e56cSJed Brown   if (!matched || code) { /* If any remaining flags are set, or we didn't process any flags */
493*dd460d27SBarry Smith     (void)(*PetscErrorPrintf)("*** unknown floating point error occurred ***\n");
494*dd460d27SBarry Smith     (void)(*PetscErrorPrintf)("The specific exception can be determined by running in a debugger.  When the\n");
495*dd460d27SBarry Smith     (void)(*PetscErrorPrintf)("debugger traps the signal, the exception can be found with fetestexcept(0x%x)\n", FE_ALL_EXCEPT);
496*dd460d27SBarry Smith     (void)(*PetscErrorPrintf)("where the result is a bitwise OR of the following flags:\n");
497*dd460d27SBarry 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);
498b014e56cSJed Brown   }
499accbd18bSBarry Smith   #else
500*dd460d27SBarry Smith   (void)(*PetscErrorPrintf)("*** unknown floating point error occurred ***\n");
501accbd18bSBarry Smith   #endif
5027d125cddSJed Brown 
503*dd460d27SBarry Smith   (void)(*PetscErrorPrintf)("Try option -start_in_debugger\n");
50427104ee2SJacob Faibussowitsch   #if PetscDefined(USE_DEBUG)
505dfb7d7afSStefano Zampini     #if !PetscDefined(HAVE_THREADSAFETY)
506*dd460d27SBarry Smith   (void)(*PetscErrorPrintf)("likely location of problem given in stack below\n");
507*dd460d27SBarry Smith   (void)(*PetscErrorPrintf)("---------------------  Stack Frames ------------------------------------\n");
508*dd460d27SBarry Smith   (void)PetscStackView(PETSC_STDOUT);
509dfb7d7afSStefano Zampini     #endif
51027104ee2SJacob Faibussowitsch   #else
511*dd460d27SBarry Smith   (void)(*PetscErrorPrintf)("configure using --with-debugging=yes, recompile, link, and run \n");
512*dd460d27SBarry Smith   (void)(*PetscErrorPrintf)("with -start_in_debugger to get more information on the crash.\n");
51327104ee2SJacob Faibussowitsch   #endif
514*dd460d27SBarry Smith   (void)PetscError(PETSC_COMM_SELF, 0, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_INITIAL, "trapped floating point error");
51541e02c4dSJunchao Zhang   PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP);
516b014e56cSJed Brown }
517b014e56cSJed Brown 
518d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSetFPTrap(PetscFPTrap flag)
519d71ae5a4SJacob Faibussowitsch {
520b014e56cSJed Brown   PetscFunctionBegin;
521bd2b07b1SBarry Smith   if (flag == PETSC_FP_TRAP_ON) {
522b014e56cSJed Brown     /* Clear any flags that are currently set so that activating trapping will not immediately call the signal handler. */
523cc73adaaSBarry Smith     PetscCheck(!feclearexcept(FE_ALL_EXCEPT), PETSC_COMM_SELF, PETSC_ERR_LIB, "Cannot clear floating point exception flags");
524accbd18bSBarry Smith   #if defined(FE_NOMASK_ENV) && defined(PETSC_HAVE_FE_VALUES)
525cc9df77eSBarry Smith     /* Could use fesetenv(FE_NOMASK_ENV), but that causes spurious exceptions (like gettimeofday() -> PetscLogDouble). */
526cf0818bdSBarry Smith     /* PetscCheck(feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW) != -1,PETSC_COMM_SELF,PETSC_ERR_LIB,"Cannot activate floating point exceptions"); */
527bd2b07b1SBarry Smith     /* Doesn't work on AArch64 targets. There's a known hardware limitation. Need to detect hardware at configure time? */
528cf0818bdSBarry Smith     PetscCheck(feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW) != -1, PETSC_COMM_SELF, PETSC_ERR_LIB, "Cannot activate floating point exceptions");
529bd2b07b1SBarry Smith     PetscCall(PetscInfo(NULL, "Using PETSC_HAVE_FENV_H FPTRAP with FE_NOMASK_ENV\n"));
530b014e56cSJed Brown   #elif defined PETSC_HAVE_XMMINTRIN_H
531cc9df77eSBarry Smith     _MM_SET_EXCEPTION_MASK(_MM_GET_EXCEPTION_MASK() & ~_MM_MASK_DIV_ZERO);
532bd2b07b1SBarry Smith     /* _MM_SET_EXCEPTION_MASK(_MM_GET_EXCEPTION_MASK() & ~_MM_MASK_UNDERFLOW); */
533cc9df77eSBarry Smith     _MM_SET_EXCEPTION_MASK(_MM_GET_EXCEPTION_MASK() & ~_MM_MASK_OVERFLOW);
534cc9df77eSBarry Smith     _MM_SET_EXCEPTION_MASK(_MM_GET_EXCEPTION_MASK() & ~_MM_MASK_INVALID);
535bd2b07b1SBarry Smith     PetscCall(PetscInfo(NULL, "Using PETSC_HAVE_FENV_H FPTRAP with PETSC_HAVE_XMMINTRIN_H\n"));
536b014e56cSJed Brown   #else
537b014e56cSJed Brown     /* C99 does not provide a way to modify the environment so there is no portable way to activate trapping. */
538bd2b07b1SBarry Smith     PetscCall(PetscInfo(NULL, "Using PETSC_HAVE_FENV_H FPTRAP\n"));
539b014e56cSJed Brown   #endif
54008401ef6SPierre Jolivet     PetscCheck(SIG_ERR != signal(SIGFPE, PetscDefaultFPTrap), PETSC_COMM_SELF, PETSC_ERR_LIB, "Can't set floating point handler");
541b014e56cSJed Brown   } else {
542cc73adaaSBarry Smith     PetscCheck(!fesetenv(FE_DFL_ENV), PETSC_COMM_SELF, PETSC_ERR_LIB, "Cannot disable floating point exceptions");
543cc9df77eSBarry Smith     /* can use _MM_SET_EXCEPTION_MASK(_MM_GET_EXCEPTION_MASK() | _MM_MASK_UNDERFLOW); if PETSC_HAVE_XMMINTRIN_H exists */
54408401ef6SPierre Jolivet     PetscCheck(SIG_ERR != signal(SIGFPE, SIG_DFL), PETSC_COMM_SELF, PETSC_ERR_LIB, "Can't clear floating point handler");
545b014e56cSJed Brown   }
546cf0818bdSBarry Smith   _trapmode = flag;
5473ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
548b014e56cSJed Brown }
549b014e56cSJed Brown 
550d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDetermineInitialFPTrap(void)
551d71ae5a4SJacob Faibussowitsch {
552cc9df77eSBarry Smith   #if defined(FE_NOMASK_ENV) || defined PETSC_HAVE_XMMINTRIN_H
553cc9df77eSBarry Smith   unsigned int flags;
554cc9df77eSBarry Smith   #endif
555cc9df77eSBarry Smith 
556cc9df77eSBarry Smith   PetscFunctionBegin;
557cc9df77eSBarry Smith   #if defined(FE_NOMASK_ENV)
558cc9df77eSBarry Smith   flags = fegetexcept();
559cc9df77eSBarry Smith   if (flags & FE_DIVBYZERO) {
560cc9df77eSBarry Smith   #elif defined PETSC_HAVE_XMMINTRIN_H
561cc9df77eSBarry Smith   flags = _MM_GET_EXCEPTION_MASK();
562cc9df77eSBarry Smith   if (!(flags & _MM_MASK_DIV_ZERO)) {
563cc9df77eSBarry Smith   #else
5649566063dSJacob Faibussowitsch   PetscCall(PetscInfo(NULL, "Floating point trapping unknown, assuming off\n"));
5653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
566cc9df77eSBarry Smith   #endif
567cc9df77eSBarry Smith   #if defined(FE_NOMASK_ENV) || defined PETSC_HAVE_XMMINTRIN_H
568cc9df77eSBarry Smith     _trapmode = PETSC_FP_TRAP_ON;
5699566063dSJacob Faibussowitsch     PetscCall(PetscInfo(NULL, "Floating point trapping is on by default %d\n", flags));
570cc9df77eSBarry Smith   } else {
571cc9df77eSBarry Smith     _trapmode = PETSC_FP_TRAP_OFF;
5729566063dSJacob Faibussowitsch     PetscCall(PetscInfo(NULL, "Floating point trapping is off by default %d\n", flags));
573cc9df77eSBarry Smith   }
5743ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
575cc9df77eSBarry Smith   #endif
576cc9df77eSBarry Smith }
577cc9df77eSBarry Smith 
578cc9df77eSBarry Smith /* ------------------------------------------------------------*/
579cc9df77eSBarry Smith #elif defined(PETSC_HAVE_IEEEFP_H)
580cc9df77eSBarry Smith   #include <ieeefp.h>
581d71ae5a4SJacob Faibussowitsch void PetscDefaultFPTrap(int sig)
582d71ae5a4SJacob Faibussowitsch {
583cc9df77eSBarry Smith   PetscFunctionBegin;
584*dd460d27SBarry Smith   (void)(*PetscErrorPrintf)("*** floating point error occurred ***\n");
585*dd460d27SBarry Smith   (void)PetscError(PETSC_COMM_SELF, 0, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_REPEAT, "floating point error");
586cc9df77eSBarry Smith   PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP);
587cc9df77eSBarry Smith }
588cc9df77eSBarry Smith 
589d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSetFPTrap(PetscFPTrap flag)
590d71ae5a4SJacob Faibussowitsch {
591cc9df77eSBarry Smith   PetscFunctionBegin;
592cf0818bdSBarry Smith   if (flag == PETSC_FP_TRAP_ON) {
59318da0197SPierre Jolivet   #if defined(PETSC_HAVE_FPRESETSTICKY)
594cc9df77eSBarry Smith     fpresetsticky(fpgetsticky());
595cc9df77eSBarry Smith   #elif defined(PETSC_HAVE_FPSETSTICKY)
596cc9df77eSBarry Smith     fpsetsticky(fpgetsticky());
597cc9df77eSBarry Smith   #endif
598cc9df77eSBarry Smith     fpsetmask(FP_X_INV | FP_X_DZ | FP_X_OFL | FP_X_OFL);
59908401ef6SPierre Jolivet     PetscCheck(SIG_ERR != signal(SIGFPE, PetscDefaultFPTrap), PETSC_COMM_SELF, PETSC_ERR_LIB, "Can't set floating point handler");
600cc9df77eSBarry Smith   } else {
60118da0197SPierre Jolivet   #if defined(PETSC_HAVE_FPRESETSTICKY)
602cc9df77eSBarry Smith     fpresetsticky(fpgetsticky());
603cc9df77eSBarry Smith   #elif defined(PETSC_HAVE_FPSETSTICKY)
604cc9df77eSBarry Smith     fpsetsticky(fpgetsticky());
605cc9df77eSBarry Smith   #endif
606cc9df77eSBarry Smith     fpsetmask(0);
60708401ef6SPierre Jolivet     PetscCheck(SIG_ERR != signal(SIGFPE, SIG_DFL), PETSC_COMM_SELF, PETSC_ERR_LIB, "Can't clear floating point handler");
608cc9df77eSBarry Smith   }
609cf0818bdSBarry Smith   _trapmode = flag;
610bd2b07b1SBarry Smith   PetscCall(PetscInfo(NULL, "Using PETSC_HAVE_IEEEFP_H FPTRAP\n"));
6113ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
612cc9df77eSBarry Smith }
613cc9df77eSBarry Smith 
614d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDetermineInitialFPTrap(void)
615d71ae5a4SJacob Faibussowitsch {
616cc9df77eSBarry Smith   PetscFunctionBegin;
6179566063dSJacob Faibussowitsch   PetscCall(PetscInfo(NULL, "Unable to determine initial floating point trapping. Assuming it is off\n"));
6183ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
619cc9df77eSBarry Smith }
620cc9df77eSBarry Smith 
621e5c89e4eSSatish Balay /* -------------------------Default -----------------------------------*/
622e5c89e4eSSatish Balay #else
62399e0435eSBarry Smith 
62466976f2fSJacob Faibussowitsch static void PetscDefaultFPTrap(int sig)
625d71ae5a4SJacob Faibussowitsch {
626e5c89e4eSSatish Balay   PetscFunctionBegin;
627*dd460d27SBarry Smith   (void)(*PetscErrorPrintf)("*** floating point error occurred ***\n");
628*dd460d27SBarry Smith   (void)PetscError(PETSC_COMM_SELF, 0, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_REPEAT, "floating point error");
62941e02c4dSJunchao Zhang   PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP);
630e5c89e4eSSatish Balay }
63199e0435eSBarry Smith 
632d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSetFPTrap(PetscFPTrap flag)
633d71ae5a4SJacob Faibussowitsch {
634e5c89e4eSSatish Balay   PetscFunctionBegin;
635bd2b07b1SBarry Smith   if (flag == PETSC_FP_TRAP_ON) {
6363ba16761SJacob Faibussowitsch     if (SIG_ERR == signal(SIGFPE, PetscDefaultFPTrap)) PetscCall((*PetscErrorPrintf)("Can't set floatingpoint handler\n"));
6373ba16761SJacob Faibussowitsch   } else if (SIG_ERR == signal(SIGFPE, SIG_DFL)) PetscCall((*PetscErrorPrintf)("Can't clear floatingpoint handler\n"));
638a297a907SKarl Rupp 
639cf0818bdSBarry Smith   _trapmode = flag;
640bd2b07b1SBarry Smith   PetscCall(PetscInfo(NULL, "Using default FPTRAP\n"));
6413ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
642e5c89e4eSSatish Balay }
643cc9df77eSBarry Smith 
644d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDetermineInitialFPTrap(void)
645d71ae5a4SJacob Faibussowitsch {
646cc9df77eSBarry Smith   PetscFunctionBegin;
6479566063dSJacob Faibussowitsch   PetscCall(PetscInfo(NULL, "Unable to determine initial floating point trapping. Assuming it is off\n"));
6483ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
649cc9df77eSBarry Smith }
650e5c89e4eSSatish Balay #endif
651