xref: /petsc/src/sys/error/fp.c (revision 337bb5272d4c69d1e0ed3a339250a90ad66a4bf4)
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;
1243ba16761SJacob Faibussowitsch   PetscErrorCode ierr;
125e5c89e4eSSatish Balay 
126e5c89e4eSSatish Balay   PetscFunctionBegin;
1275f80ce2aSJacob Faibussowitsch   for (int j = 0; error_codes[j].code_no; j++) {
128e5c89e4eSSatish Balay     if (error_codes[j].code_no == code) err_ind = j;
129e5c89e4eSSatish Balay   }
130e5c89e4eSSatish Balay 
1313ba16761SJacob Faibussowitsch   if (err_ind >= 0) ierr = (*PetscErrorPrintf)("*** %s occurred at pc=%X ***\n", error_codes[err_ind].name, SIGPC(scp));
1323ba16761SJacob Faibussowitsch   else ierr = (*PetscErrorPrintf)("*** floating point error 0x%x occurred at pc=%X ***\n", code, SIGPC(scp));
133a297a907SKarl Rupp 
1343ba16761SJacob Faibussowitsch   ierr = PetscError(PETSC_COMM_SELF, PETSC_ERR_FP, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_REPEAT, "floating point error");
1353ba16761SJacob Faibussowitsch   (void)ierr;
13641e02c4dSJunchao Zhang   PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP);
1373ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
138e5c89e4eSSatish Balay }
139e5c89e4eSSatish Balay 
140e30d2299SSatish Balay /*@
141cf0818bdSBarry Smith    PetscSetFPTrap - Enables traps/exceptions on common floating point errors. This option may not work on certain systems or only a
142cf0818bdSBarry Smith    subset of exceptions may be trapable.
143e5c89e4eSSatish Balay 
144e5c89e4eSSatish Balay    Not Collective
145e5c89e4eSSatish Balay 
1462fe279fdSBarry Smith    Input Parameter:
147cf0818bdSBarry Smith .  flag - values are
148cf0818bdSBarry Smith .vb
149cf0818bdSBarry Smith     PETSC_FP_TRAP_OFF   - do not trap any exceptions
150cf0818bdSBarry Smith     PETSC_FP_TRAP_ON - all exceptions that are possible on the system except underflow
151cf0818bdSBarry Smith     PETSC_FP_TRAP_INDIV - integer divide by zero
152cf0818bdSBarry Smith     PETSC_FP_TRAP_FLTOPERR - improper argument to function, for example with real numbers, the square root of a negative number
153cf0818bdSBarry Smith     PETSC_FP_TRAP_FLTOVF - overflow
154cf0818bdSBarry Smith     PETSC_FP_TRAP_FLTUND - underflow - not trapped by default on most systems
155cf0818bdSBarry Smith     PETSC_FP_TRAP_FLTDIV - floating point divide by zero
156cf0818bdSBarry Smith     PETSC_FP_TRAP_FLTINEX - inexact floating point result
157cf0818bdSBarry Smith .ve
158e5c89e4eSSatish Balay 
1592fe279fdSBarry Smith    Options Database Key:
160cf0818bdSBarry Smith .  -fp_trap <off,on> - turn on or off trapping of floating point exceptions
161e5c89e4eSSatish Balay 
162e5c89e4eSSatish Balay    Level: advanced
163e5c89e4eSSatish Balay 
164cf0818bdSBarry Smith    Notes:
1657de69702SBarry Smith    Preferred usage is `PetscFPTrapPush()` and `PetscFPTrapPop()` instead of this routine
1667de69702SBarry Smith 
167811af0c4SBarry Smith    Currently only `PETSC_FP_TRAP_OFF` and `PETSC_FP_TRAP_ON` are handled. All others are treated as `PETSC_FP_TRAP_ON`.
168cf0818bdSBarry Smith 
169cf0818bdSBarry Smith    The values are bit values and may be |ed together in the function call
170cf0818bdSBarry Smith 
171cf0818bdSBarry Smith    On systems that support it this routine causes floating point
172cf0818bdSBarry Smith    overflow, divide-by-zero, and invalid-operand (e.g., a NaN), but not underflow, to
173e5c89e4eSSatish Balay    cause a message to be printed and the program to exit.
174e5c89e4eSSatish Balay 
175cc9df77eSBarry Smith    On many common systems, the floating
1767d125cddSJed Brown    point exception state is not preserved from the location where the trap
1777d125cddSJed Brown    occurred through to the signal handler.  In this case, the signal handler
1787d125cddSJed Brown    will just say that an unknown floating point exception occurred and which
1797d125cddSJed Brown    function it occurred in.  If you run with -fp_trap in a debugger, it will
180cc9df77eSBarry Smith    break on the line where the error occurred.  On systems that support C99
181cc9df77eSBarry Smith    floating point exception handling You can check which
1827d125cddSJed Brown    exception occurred using fetestexcept(FE_ALL_EXCEPT).  See fenv.h
1837d125cddSJed Brown    (usually at /usr/include/bits/fenv.h) for the enum values on your system.
1847d125cddSJed Brown 
185db781477SPatrick Sanan .seealso: `PetscFPTrapPush()`, `PetscFPTrapPop()`, `PetscDetermineInitialFPTrap()`
186e5c89e4eSSatish Balay @*/
187d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSetFPTrap(PetscFPTrap flag)
188d71ae5a4SJacob Faibussowitsch {
189e5c89e4eSSatish Balay   char *out;
190e5c89e4eSSatish Balay 
191e5c89e4eSSatish Balay   PetscFunctionBegin;
192e5c89e4eSSatish Balay   /* Clear accumulated exceptions.  Used to suppress meaningless messages from f77 programs */
193e5c89e4eSSatish Balay   (void)ieee_flags("clear", "exception", "all", &out);
194bd2b07b1SBarry Smith   if (flag == PETSC_FP_TRAP_ON) {
195e5c89e4eSSatish Balay     /*
196a297a907SKarl Rupp       To trap more fp exceptions, including underflow, change the line below to
197e5c89e4eSSatish Balay       if (ieee_handler("set","all",PetscDefaultFPTrap)) {
198e5c89e4eSSatish Balay     */
199a297a907SKarl Rupp     if (ieee_handler("set", "common", PetscDefaultFPTrap)) (*PetscErrorPrintf)("Can't set floatingpoint handler\n");
200a297a907SKarl Rupp   } else if (ieee_handler("clear", "common", PetscDefaultFPTrap)) (*PetscErrorPrintf)("Can't clear floatingpoint handler\n");
201a297a907SKarl Rupp 
202670f3ff9SJed Brown   _trapmode = flag;
203bd2b07b1SBarry Smith   PetscCall(PetscInfo(NULL, "Using PETSC_HAVE_SUN4_STYLE_FPTRAP\n"));
2043ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
205e5c89e4eSSatish Balay }
206e5c89e4eSSatish Balay 
207cc9df77eSBarry Smith /*@
208811af0c4SBarry Smith    PetscDetermineInitialFPTrap - Attempts to determine the floating point trapping that exists when `PetscInitialize()` is called
209cc9df77eSBarry Smith 
210cc9df77eSBarry Smith    Not Collective
211cc9df77eSBarry Smith 
212811af0c4SBarry Smith    Note:
213*337bb527SBarry Smith    Currently only supported on Linux and macOS. Checks if divide by zero is enable and if so declares that trapping is on.
214cc9df77eSBarry Smith 
215ee300463SSatish Balay    Level: advanced
216cc9df77eSBarry Smith 
217db781477SPatrick Sanan .seealso: `PetscFPTrapPush()`, `PetscFPTrapPop()`, `PetscDetermineInitialFPTrap()`
218cc9df77eSBarry Smith @*/
219d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDetermineInitialFPTrap(void)
220d71ae5a4SJacob Faibussowitsch {
221cc9df77eSBarry Smith   PetscFunctionBegin;
2229566063dSJacob Faibussowitsch   PetscCall(PetscInfo(NULL, "Unable to determine initial floating point trapping. Assuming it is off\n"));
2233ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
224cc9df77eSBarry Smith }
225cc9df77eSBarry Smith 
226e5c89e4eSSatish Balay /* -------------------------------------------------------------------------------------------*/
227e5c89e4eSSatish Balay #elif defined(PETSC_HAVE_SOLARIS_STYLE_FPTRAP)
228e5c89e4eSSatish Balay   #include <sunmath.h>
229e5c89e4eSSatish Balay   #include <floatingpoint.h>
230e5c89e4eSSatish Balay   #include <siginfo.h>
231e5c89e4eSSatish Balay   #include <ucontext.h>
232e5c89e4eSSatish Balay 
2339371c9d4SSatish Balay static struct {
2349371c9d4SSatish Balay   int   code_no;
2359371c9d4SSatish Balay   char *name;
2369371c9d4SSatish Balay } error_codes[] = {
237e5c89e4eSSatish Balay   {FPE_FLTINV, "invalid floating point operand"},
238e5c89e4eSSatish Balay   {FPE_FLTRES, "inexact floating point result" },
239e5c89e4eSSatish Balay   {FPE_FLTDIV, "division-by-zero"              },
240e5c89e4eSSatish Balay   {FPE_FLTUND, "floating point underflow"      },
241e5c89e4eSSatish Balay   {FPE_FLTOVF, "floating point overflow"       },
242e5c89e4eSSatish Balay   {0,          "unknown error"                 }
243e5c89e4eSSatish Balay };
244e5c89e4eSSatish Balay   #define SIGPC(scp) (scp->si_addr)
245e5c89e4eSSatish Balay 
246d71ae5a4SJacob Faibussowitsch void PetscDefaultFPTrap(int sig, siginfo_t *scp, ucontext_t *uap)
247d71ae5a4SJacob Faibussowitsch {
2485f80ce2aSJacob Faibussowitsch   int            err_ind = -1, code = scp->si_code;
2493ba16761SJacob Faibussowitsch   PetscErrorCode ierr;
250e5c89e4eSSatish Balay 
251e5c89e4eSSatish Balay   PetscFunctionBegin;
2525f80ce2aSJacob Faibussowitsch   for (int j = 0; error_codes[j].code_no; j++) {
253e5c89e4eSSatish Balay     if (error_codes[j].code_no == code) err_ind = j;
254e5c89e4eSSatish Balay   }
255e5c89e4eSSatish Balay 
2563ba16761SJacob Faibussowitsch   if (err_ind >= 0) ierr = (*PetscErrorPrintf)("*** %s occurred at pc=%X ***\n", error_codes[err_ind].name, SIGPC(scp));
2573ba16761SJacob Faibussowitsch   else ierr = (*PetscErrorPrintf)("*** floating point error 0x%x occurred at pc=%X ***\n", code, SIGPC(scp));
258a297a907SKarl Rupp 
2593ba16761SJacob Faibussowitsch   ierr = PetscError(PETSC_COMM_SELF, 0, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_REPEAT, "floating point error");
2603ba16761SJacob Faibussowitsch   (void)ierr;
26141e02c4dSJunchao Zhang   PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP);
262e5c89e4eSSatish Balay }
263e5c89e4eSSatish Balay 
264d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSetFPTrap(PetscFPTrap flag)
265d71ae5a4SJacob Faibussowitsch {
266e5c89e4eSSatish Balay   char *out;
267e5c89e4eSSatish Balay 
268e5c89e4eSSatish Balay   PetscFunctionBegin;
269e5c89e4eSSatish Balay   /* Clear accumulated exceptions.  Used to suppress meaningless messages from f77 programs */
270e5c89e4eSSatish Balay   (void)ieee_flags("clear", "exception", "all", &out);
271e5c89e4eSSatish Balay   if (flag == PETSC_FP_TRAP_ON) {
272a297a907SKarl Rupp     if (ieee_handler("set", "common", (sigfpe_handler_type)PetscDefaultFPTrap)) (*PetscErrorPrintf)("Can't set floating point handler\n");
273cc9df77eSBarry Smith   } else {
274cc9df77eSBarry Smith     if (ieee_handler("clear", "common", (sigfpe_handler_type)PetscDefaultFPTrap)) (*PetscErrorPrintf)("Can't clear floatingpoint handler\n");
275cc9df77eSBarry Smith   }
276670f3ff9SJed Brown   _trapmode = flag;
277bd2b07b1SBarry Smith   PetscCall(PetscInfo(NULL,"Using PETSC_HAVE_SOLARIS_STYLE_FPTRAP\n");
2783ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
279e5c89e4eSSatish Balay }
280e5c89e4eSSatish Balay 
281d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDetermineInitialFPTrap(void)
282d71ae5a4SJacob Faibussowitsch {
283cc9df77eSBarry Smith   PetscFunctionBegin;
2849566063dSJacob Faibussowitsch   PetscCall(PetscInfo(NULL, "Unable to determine initial floating point trapping. Assuming it is off\n"));
2853ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
286cc9df77eSBarry Smith }
287cc9df77eSBarry Smith 
288cc9df77eSBarry Smith /* ------------------------------------------------------------------------------------------*/
289e5c89e4eSSatish Balay #elif defined(PETSC_HAVE_IRIX_STYLE_FPTRAP)
290e5c89e4eSSatish Balay   #include <sigfpe.h>
2919371c9d4SSatish Balay static struct {
2929371c9d4SSatish Balay   int   code_no;
2939371c9d4SSatish Balay   char *name;
2949371c9d4SSatish Balay } error_codes[] = {
295e5c89e4eSSatish Balay   {_INVALID, "IEEE operand error"      },
296e5c89e4eSSatish Balay   {_OVERFL,  "floating point overflow" },
297e5c89e4eSSatish Balay   {_UNDERFL, "floating point underflow"},
298e5c89e4eSSatish Balay   {_DIVZERO, "floating point divide"   },
299e5c89e4eSSatish Balay   {0,        "unknown error"           }
300e5c89e4eSSatish Balay };
301d71ae5a4SJacob Faibussowitsch void PetscDefaultFPTrap(unsigned exception[], int val[])
302d71ae5a4SJacob Faibussowitsch {
3035f80ce2aSJacob Faibussowitsch   int            err_ind = -1, code = exception[0];
3043ba16761SJacob Faibussowitsch   PetscErrorCode ierr;
305e5c89e4eSSatish Balay 
306e5c89e4eSSatish Balay   PetscFunctionBegin;
3075f80ce2aSJacob Faibussowitsch   for (int j = 0; error_codes[j].code_no; j++) {
308e5c89e4eSSatish Balay     if (error_codes[j].code_no == code) err_ind = j;
309e5c89e4eSSatish Balay   }
3103ba16761SJacob Faibussowitsch   if (err_ind >= 0) ierr = (*PetscErrorPrintf)("*** %s occurred ***\n", error_codes[err_ind].name);
3113ba16761SJacob Faibussowitsch   else ierr = (*PetscErrorPrintf)("*** floating point error 0x%x occurred ***\n", code);
312a297a907SKarl Rupp 
3133ba16761SJacob Faibussowitsch   ierr = PetscError(PETSC_COMM_SELF, 0, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_REPEAT, "floating point error");
3143ba16761SJacob Faibussowitsch   (void)ierr;
31541e02c4dSJunchao Zhang   PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP);
316e5c89e4eSSatish Balay }
317e5c89e4eSSatish Balay 
318d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSetFPTrap(PetscFPTrap flag)
319d71ae5a4SJacob Faibussowitsch {
320e5c89e4eSSatish Balay   PetscFunctionBegin;
321bd2b07b1SBarry Smith   if (flag == PETSC_FP_TRAP_ON) handle_sigfpes(_ON, , _EN_UNDERFL | _EN_OVERFL | _EN_DIVZERO | _EN_INVALID, PetscDefaultFPTrap, _ABORT_ON_ERROR, 0);
322cc9df77eSBarry Smith   else handle_sigfpes(_OFF, _EN_UNDERFL | _EN_OVERFL | _EN_DIVZERO | _EN_INVALID, 0, _ABORT_ON_ERROR, 0);
323670f3ff9SJed Brown   _trapmode = flag;
324bd2b07b1SBarry Smith   PetscCall(PetscInfo(NULL, "Using PETSC_HAVE_IRIX_STYLE_FPTRAP\n"));
3253ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
326cc9df77eSBarry Smith }
327cc9df77eSBarry Smith 
328d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDetermineInitialFPTrap(void)
329d71ae5a4SJacob Faibussowitsch {
330cc9df77eSBarry Smith   PetscFunctionBegin;
3319566063dSJacob Faibussowitsch   PetscCall(PetscInfo(NULL, "Unable to determine initial floating point trapping. Assuming it is off\n"));
3323ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
333cc9df77eSBarry Smith }
334cc9df77eSBarry Smith 
335cc9df77eSBarry Smith /*----------------------------------------------- --------------------------------------------*/
336cc9df77eSBarry Smith #elif defined(PETSC_HAVE_RS6000_STYLE_FPTRAP)
337e5c89e4eSSatish Balay /* In "fast" mode, floating point traps are imprecise and ignored.
338e5c89e4eSSatish Balay    This is the reason for the fptrap(FP_TRAP_SYNC) call */
339e5c89e4eSSatish Balay struct sigcontext;
340e5c89e4eSSatish Balay   #include <fpxcp.h>
341e5c89e4eSSatish Balay   #include <fptrap.h>
342e5c89e4eSSatish Balay   #define FPE_FLTOPERR_TRAP (fptrap_t)(0x20000000)
343e5c89e4eSSatish Balay   #define FPE_FLTOVF_TRAP   (fptrap_t)(0x10000000)
344e5c89e4eSSatish Balay   #define FPE_FLTUND_TRAP   (fptrap_t)(0x08000000)
345e5c89e4eSSatish Balay   #define FPE_FLTDIV_TRAP   (fptrap_t)(0x04000000)
346e5c89e4eSSatish Balay   #define FPE_FLTINEX_TRAP  (fptrap_t)(0x02000000)
347e5c89e4eSSatish Balay 
3489371c9d4SSatish Balay static struct {
3499371c9d4SSatish Balay   int   code_no;
3509371c9d4SSatish Balay   char *name;
3519371c9d4SSatish Balay } error_codes[] = {
352e5c89e4eSSatish Balay   {FPE_FLTOPERR_TRAP, "IEEE operand error"           },
353e5c89e4eSSatish Balay   {FPE_FLTOVF_TRAP,   "floating point overflow"      },
354e5c89e4eSSatish Balay   {FPE_FLTUND_TRAP,   "floating point underflow"     },
355e5c89e4eSSatish Balay   {FPE_FLTDIV_TRAP,   "floating point divide"        },
356e5c89e4eSSatish Balay   {FPE_FLTINEX_TRAP,  "inexact floating point result"},
357bd2b07b1SBarry Smith   < {0,                 "unknown error"                }
358e5c89e4eSSatish Balay };
359e5c89e4eSSatish Balay   #define SIGPC(scp)        (0) /* Info MIGHT be in scp->sc_jmpbuf.jmp_context.iar */
360e5c89e4eSSatish Balay /*
361e5c89e4eSSatish Balay    For some reason, scp->sc_jmpbuf does not work on the RS6000, even though
362e5c89e4eSSatish Balay    it looks like it should from the include definitions.  It is probably
363e5c89e4eSSatish Balay    some strange interaction with the "POSIX_SOURCE" that we require.
364e5c89e4eSSatish Balay */
365e5c89e4eSSatish Balay 
366d71ae5a4SJacob Faibussowitsch void PetscDefaultFPTrap(int sig, int code, struct sigcontext *scp)
367d71ae5a4SJacob Faibussowitsch {
368e5c89e4eSSatish Balay   int            err_ind, j;
369e5c89e4eSSatish Balay   fp_ctx_t       flt_context;
3703ba16761SJacob Faibussowitsch   PetscErrorCode ierr;
371e5c89e4eSSatish Balay 
372e5c89e4eSSatish Balay   PetscFunctionBegin;
373e5c89e4eSSatish Balay   fp_sh_trap_info(scp, &flt_context);
374e5c89e4eSSatish Balay 
375e5c89e4eSSatish Balay   err_ind = -1;
376e5c89e4eSSatish Balay   for (j = 0; error_codes[j].code_no; j++) {
377e5c89e4eSSatish Balay     if (error_codes[j].code_no == flt_context.trap) err_ind = j;
378e5c89e4eSSatish Balay   }
379e5c89e4eSSatish Balay 
3803ba16761SJacob Faibussowitsch   if (err_ind >= 0) ierr = (*PetscErrorPrintf)("*** %s occurred ***\n", error_codes[err_ind].name);
3813ba16761SJacob Faibussowitsch   else ierr = (*PetscErrorPrintf)("*** floating point error 0x%x occurred ***\n", flt_context.trap);
382a297a907SKarl Rupp 
3833ba16761SJacob Faibussowitsch   ierr = PetscError(PETSC_COMM_SELF, 0, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_REPEAT, "floating point error");
3843ba16761SJacob Faibussowitsch   (void)ierr;
38541e02c4dSJunchao Zhang   PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP);
386e5c89e4eSSatish Balay }
387e5c89e4eSSatish Balay 
388d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSetFPTrap(PetscFPTrap flag)
389d71ae5a4SJacob Faibussowitsch {
390e5c89e4eSSatish Balay   PetscFunctionBegin;
391bd2b07b1SBarry Smith   if (flag == PETSC_FP_TRAP_ON) {
392e5c89e4eSSatish Balay     signal(SIGFPE, (void (*)(int))PetscDefaultFPTrap);
393e5c89e4eSSatish Balay     fp_trap(FP_TRAP_SYNC);
394bd2b07b1SBarry Smith     /* fp_enable(TRP_INVALID | TRP_DIV_BY_ZERO | TRP_OVERFLOW | TRP_UNDERFLOW); */
395bd2b07b1SBarry Smith     fp_enable(TRP_INVALID | TRP_DIV_BY_ZERO | TRP_OVERFLOW);
396e5c89e4eSSatish Balay   } else {
397e5c89e4eSSatish Balay     signal(SIGFPE, SIG_DFL);
398cc9df77eSBarry Smith     fp_disable(TRP_INVALID | TRP_DIV_BY_ZERO | TRP_OVERFLOW | TRP_UNDERFLOW);
399e5c89e4eSSatish Balay     fp_trap(FP_TRAP_OFF);
400e5c89e4eSSatish Balay   }
401cf0818bdSBarry Smith   _trapmode = flag;
402bd2b07b1SBarry Smith   PetscCall(PetscInfo(NULL, "Using PETSC_HAVE_RS6000_STYLE_FPTRAP\n"));
4033ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
404e5c89e4eSSatish Balay }
405e5c89e4eSSatish Balay 
406d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDetermineInitialFPTrap(void)
407d71ae5a4SJacob Faibussowitsch {
408cc9df77eSBarry Smith   PetscFunctionBegin;
4099566063dSJacob Faibussowitsch   PetscCall(PetscInfo(NULL, "Unable to determine initial floating point trapping. Assuming it is off\n"));
4103ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
411cc9df77eSBarry Smith }
412cc9df77eSBarry Smith 
413cc9df77eSBarry Smith /* ------------------------------------------------------------*/
414cc9df77eSBarry Smith #elif defined(PETSC_HAVE_WINDOWS_COMPILERS)
415cc9df77eSBarry Smith   #include <float.h>
416d71ae5a4SJacob Faibussowitsch void PetscDefaultFPTrap(int sig)
417d71ae5a4SJacob Faibussowitsch {
4183ba16761SJacob Faibussowitsch   PetscErrorCode ierr;
4193ba16761SJacob Faibussowitsch 
420cc9df77eSBarry Smith   PetscFunctionBegin;
4213ba16761SJacob Faibussowitsch   ierr = (*PetscErrorPrintf)("*** floating point error occurred ***\n");
4223ba16761SJacob Faibussowitsch   ierr = PetscError(PETSC_COMM_SELF, 0, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_REPEAT, "floating point error");
4233ba16761SJacob Faibussowitsch   (void)ierr;
424cc9df77eSBarry Smith   PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP);
425cc9df77eSBarry Smith }
426cc9df77eSBarry Smith 
427d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSetFPTrap(PetscFPTrap flag)
428d71ae5a4SJacob Faibussowitsch {
429cc9df77eSBarry Smith   unsigned int cw;
430cc9df77eSBarry Smith 
431cc9df77eSBarry Smith   PetscFunctionBegin;
432bd2b07b1SBarry Smith   if (flag == PETSC_FP_TRAP_ON) {
433bd2b07b1SBarry Smith     /* cw = _EM_INVALID | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW; */
434bd2b07b1SBarry Smith     cw = _EM_INVALID | _EM_ZERODIVIDE | _EM_OVERFLOW;
43508401ef6SPierre Jolivet     PetscCheck(SIG_ERR != signal(SIGFPE, PetscDefaultFPTrap), PETSC_COMM_SELF, PETSC_ERR_LIB, "Can't set floating point handler");
436cc9df77eSBarry Smith   } else {
437cc9df77eSBarry Smith     cw = 0;
43808401ef6SPierre Jolivet     PetscCheck(SIG_ERR != signal(SIGFPE, SIG_DFL), PETSC_COMM_SELF, PETSC_ERR_LIB, "Can't clear floating point handler");
439cc9df77eSBarry Smith   }
440cc9df77eSBarry Smith   (void)_controlfp(0, cw);
441cf0818bdSBarry Smith   _trapmode = flag;
442bd2b07b1SBarry Smith   PetscCall(PetscInfo(NULL, "Using PETSC_HAVE_WINDOWS_COMPILERS FPTRAP\n"));
4433ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
444cc9df77eSBarry Smith }
445cc9df77eSBarry Smith 
446d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDetermineInitialFPTrap(void)
447d71ae5a4SJacob Faibussowitsch {
448cc9df77eSBarry Smith   PetscFunctionBegin;
4499566063dSJacob Faibussowitsch   PetscCall(PetscInfo(NULL, "Unable to determine initial floating point trapping. Assuming it is off\n"));
4503ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
451cc9df77eSBarry Smith }
452cc9df77eSBarry Smith 
453cc9df77eSBarry Smith /* ------------------------------------------------------------*/
4549a2402e9SBarry Smith #elif defined(PETSC_HAVE_FENV_H) && !defined(__cplusplus)
455b014e56cSJed Brown   /*
456b014e56cSJed Brown    C99 style floating point environment.
457b014e56cSJed Brown 
458b014e56cSJed Brown    Note that C99 merely specifies how to save, restore, and clear the floating
459b014e56cSJed Brown    point environment as well as defining an enumeration of exception codes.  In
460b014e56cSJed Brown    particular, C99 does not specify how to make floating point exceptions raise
461b014e56cSJed Brown    a signal.  Glibc offers this capability through FE_NOMASK_ENV (or with finer
462b014e56cSJed Brown    granularity, feenableexcept()), xmmintrin.h offers _MM_SET_EXCEPTION_MASK().
463b014e56cSJed Brown */
464b014e56cSJed Brown   #include <fenv.h>
465accbd18bSBarry Smith   #if defined(PETSC_HAVE_FE_VALUES)
4669371c9d4SSatish Balay typedef struct {
4679371c9d4SSatish Balay   int         code;
4689371c9d4SSatish Balay   const char *name;
4699371c9d4SSatish Balay } FPNode;
470b014e56cSJed Brown static const FPNode error_codes[] = {
471b014e56cSJed Brown   {FE_DIVBYZERO, "divide by zero"                                 },
472b014e56cSJed Brown   {FE_INEXACT,   "inexact floating point result"                  },
473b014e56cSJed Brown   {FE_INVALID,   "invalid floating point arguments (domain error)"},
474b014e56cSJed Brown   {FE_OVERFLOW,  "floating point overflow"                        },
475b014e56cSJed Brown   {FE_UNDERFLOW, "floating point underflow"                       },
476b014e56cSJed Brown   {0,            "unknown error"                                  }
477b014e56cSJed Brown };
478accbd18bSBarry Smith   #endif
47999e0435eSBarry Smith 
480d71ae5a4SJacob Faibussowitsch void PetscDefaultFPTrap(int sig)
481d71ae5a4SJacob Faibussowitsch {
482accbd18bSBarry Smith   #if defined(PETSC_HAVE_FE_VALUES)
483b014e56cSJed Brown   const FPNode  *node;
484b014e56cSJed Brown   int            code;
485ace3abfcSBarry Smith   PetscBool      matched = PETSC_FALSE;
486accbd18bSBarry Smith   #endif
4873ba16761SJacob Faibussowitsch   PetscErrorCode ierr;
488b014e56cSJed Brown 
489b014e56cSJed Brown   PetscFunctionBegin;
490b014e56cSJed Brown   /* Note: While it is possible for the exception state to be preserved by the
491b014e56cSJed Brown    * kernel, this seems to be rare which makes the following flag testing almost
492b014e56cSJed Brown    * useless.  But on a system where the flags can be preserved, it would provide
4937d125cddSJed Brown    * more detail.
494b014e56cSJed Brown    */
495accbd18bSBarry Smith   #if defined(PETSC_HAVE_FE_VALUES)
496b014e56cSJed Brown   code = fetestexcept(FE_ALL_EXCEPT);
497b014e56cSJed Brown   for (node = &error_codes[0]; node->code; node++) {
498b014e56cSJed Brown     if (code & node->code) {
499b014e56cSJed Brown       matched = PETSC_TRUE;
5003ba16761SJacob Faibussowitsch       ierr    = (*PetscErrorPrintf)("*** floating point error \"%s\" occurred ***\n", node->name);
501b014e56cSJed Brown       code &= ~node->code; /* Unset this flag since it has been processed */
502b014e56cSJed Brown     }
503b014e56cSJed Brown   }
504b014e56cSJed Brown   if (!matched || code) { /* If any remaining flags are set, or we didn't process any flags */
5053ba16761SJacob Faibussowitsch     ierr = (*PetscErrorPrintf)("*** unknown floating point error occurred ***\n");
5063ba16761SJacob Faibussowitsch     ierr = (*PetscErrorPrintf)("The specific exception can be determined by running in a debugger.  When the\n");
5073ba16761SJacob Faibussowitsch     ierr = (*PetscErrorPrintf)("debugger traps the signal, the exception can be found with fetestexcept(0x%x)\n", FE_ALL_EXCEPT);
5083ba16761SJacob Faibussowitsch     ierr = (*PetscErrorPrintf)("where the result is a bitwise OR of the following flags:\n");
5093ba16761SJacob Faibussowitsch     ierr = (*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);
510b014e56cSJed Brown   }
511accbd18bSBarry Smith   #else
5123ba16761SJacob Faibussowitsch   ierr = (*PetscErrorPrintf)("*** unknown floating point error occurred ***\n");
513accbd18bSBarry Smith   #endif
5147d125cddSJed Brown 
5153ba16761SJacob Faibussowitsch   ierr = (*PetscErrorPrintf)("Try option -start_in_debugger\n");
51627104ee2SJacob Faibussowitsch   #if PetscDefined(USE_DEBUG)
517dfb7d7afSStefano Zampini     #if !PetscDefined(HAVE_THREADSAFETY)
5183ba16761SJacob Faibussowitsch   ierr = (*PetscErrorPrintf)("likely location of problem given in stack below\n");
5193ba16761SJacob Faibussowitsch   ierr = (*PetscErrorPrintf)("---------------------  Stack Frames ------------------------------------\n");
5203ba16761SJacob Faibussowitsch   ierr = PetscStackView(PETSC_STDOUT);
521dfb7d7afSStefano Zampini     #endif
52227104ee2SJacob Faibussowitsch   #else
5233ba16761SJacob Faibussowitsch   ierr = (*PetscErrorPrintf)("configure using --with-debugging=yes, recompile, link, and run \n");
5243ba16761SJacob Faibussowitsch   ierr = (*PetscErrorPrintf)("with -start_in_debugger to get more information on the crash.\n");
52527104ee2SJacob Faibussowitsch   #endif
5263ba16761SJacob Faibussowitsch   ierr = PetscError(PETSC_COMM_SELF, 0, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_INITIAL, "trapped floating point error");
5273ba16761SJacob Faibussowitsch   (void)ierr;
52841e02c4dSJunchao Zhang   PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP);
529b014e56cSJed Brown }
530b014e56cSJed Brown 
531d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSetFPTrap(PetscFPTrap flag)
532d71ae5a4SJacob Faibussowitsch {
533b014e56cSJed Brown   PetscFunctionBegin;
534bd2b07b1SBarry Smith   if (flag == PETSC_FP_TRAP_ON) {
535b014e56cSJed Brown     /* Clear any flags that are currently set so that activating trapping will not immediately call the signal handler. */
536cc73adaaSBarry Smith     PetscCheck(!feclearexcept(FE_ALL_EXCEPT), PETSC_COMM_SELF, PETSC_ERR_LIB, "Cannot clear floating point exception flags");
537accbd18bSBarry Smith   #if defined(FE_NOMASK_ENV) && defined(PETSC_HAVE_FE_VALUES)
538cc9df77eSBarry Smith     /* Could use fesetenv(FE_NOMASK_ENV), but that causes spurious exceptions (like gettimeofday() -> PetscLogDouble). */
539cf0818bdSBarry Smith     /* PetscCheck(feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW) != -1,PETSC_COMM_SELF,PETSC_ERR_LIB,"Cannot activate floating point exceptions"); */
540bd2b07b1SBarry Smith     /* Doesn't work on AArch64 targets. There's a known hardware limitation. Need to detect hardware at configure time? */
541cf0818bdSBarry Smith     PetscCheck(feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW) != -1, PETSC_COMM_SELF, PETSC_ERR_LIB, "Cannot activate floating point exceptions");
542bd2b07b1SBarry Smith     PetscCall(PetscInfo(NULL, "Using PETSC_HAVE_FENV_H FPTRAP with FE_NOMASK_ENV\n"));
543b014e56cSJed Brown   #elif defined PETSC_HAVE_XMMINTRIN_H
544cc9df77eSBarry Smith     _MM_SET_EXCEPTION_MASK(_MM_GET_EXCEPTION_MASK() & ~_MM_MASK_DIV_ZERO);
545bd2b07b1SBarry Smith     /* _MM_SET_EXCEPTION_MASK(_MM_GET_EXCEPTION_MASK() & ~_MM_MASK_UNDERFLOW); */
546cc9df77eSBarry Smith     _MM_SET_EXCEPTION_MASK(_MM_GET_EXCEPTION_MASK() & ~_MM_MASK_OVERFLOW);
547cc9df77eSBarry Smith     _MM_SET_EXCEPTION_MASK(_MM_GET_EXCEPTION_MASK() & ~_MM_MASK_INVALID);
548bd2b07b1SBarry Smith     PetscCall(PetscInfo(NULL, "Using PETSC_HAVE_FENV_H FPTRAP with PETSC_HAVE_XMMINTRIN_H\n"));
549b014e56cSJed Brown   #else
550b014e56cSJed Brown     /* C99 does not provide a way to modify the environment so there is no portable way to activate trapping. */
551bd2b07b1SBarry Smith     PetscCall(PetscInfo(NULL, "Using PETSC_HAVE_FENV_H FPTRAP\n"));
552b014e56cSJed Brown   #endif
55308401ef6SPierre Jolivet     PetscCheck(SIG_ERR != signal(SIGFPE, PetscDefaultFPTrap), PETSC_COMM_SELF, PETSC_ERR_LIB, "Can't set floating point handler");
554b014e56cSJed Brown   } else {
555cc73adaaSBarry Smith     PetscCheck(!fesetenv(FE_DFL_ENV), PETSC_COMM_SELF, PETSC_ERR_LIB, "Cannot disable floating point exceptions");
556cc9df77eSBarry Smith     /* can use _MM_SET_EXCEPTION_MASK(_MM_GET_EXCEPTION_MASK() | _MM_MASK_UNDERFLOW); if PETSC_HAVE_XMMINTRIN_H exists */
55708401ef6SPierre Jolivet     PetscCheck(SIG_ERR != signal(SIGFPE, SIG_DFL), PETSC_COMM_SELF, PETSC_ERR_LIB, "Can't clear floating point handler");
558b014e56cSJed Brown   }
559cf0818bdSBarry Smith   _trapmode = flag;
5603ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
561b014e56cSJed Brown }
562b014e56cSJed Brown 
563d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDetermineInitialFPTrap(void)
564d71ae5a4SJacob Faibussowitsch {
565cc9df77eSBarry Smith   #if defined(FE_NOMASK_ENV) || defined PETSC_HAVE_XMMINTRIN_H
566cc9df77eSBarry Smith   unsigned int flags;
567cc9df77eSBarry Smith   #endif
568cc9df77eSBarry Smith 
569cc9df77eSBarry Smith   PetscFunctionBegin;
570cc9df77eSBarry Smith   #if defined(FE_NOMASK_ENV)
571cc9df77eSBarry Smith   flags = fegetexcept();
572cc9df77eSBarry Smith   if (flags & FE_DIVBYZERO) {
573cc9df77eSBarry Smith   #elif defined PETSC_HAVE_XMMINTRIN_H
574cc9df77eSBarry Smith   flags = _MM_GET_EXCEPTION_MASK();
575cc9df77eSBarry Smith   if (!(flags & _MM_MASK_DIV_ZERO)) {
576cc9df77eSBarry Smith   #else
5779566063dSJacob Faibussowitsch   PetscCall(PetscInfo(NULL, "Floating point trapping unknown, assuming off\n"));
5783ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
579cc9df77eSBarry Smith   #endif
580cc9df77eSBarry Smith   #if defined(FE_NOMASK_ENV) || defined PETSC_HAVE_XMMINTRIN_H
581cc9df77eSBarry Smith     _trapmode = PETSC_FP_TRAP_ON;
5829566063dSJacob Faibussowitsch     PetscCall(PetscInfo(NULL, "Floating point trapping is on by default %d\n", flags));
583cc9df77eSBarry Smith   } else {
584cc9df77eSBarry Smith     _trapmode = PETSC_FP_TRAP_OFF;
5859566063dSJacob Faibussowitsch     PetscCall(PetscInfo(NULL, "Floating point trapping is off by default %d\n", flags));
586cc9df77eSBarry Smith   }
5873ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
588cc9df77eSBarry Smith   #endif
589cc9df77eSBarry Smith }
590cc9df77eSBarry Smith 
591cc9df77eSBarry Smith /* ------------------------------------------------------------*/
592cc9df77eSBarry Smith #elif defined(PETSC_HAVE_IEEEFP_H)
593cc9df77eSBarry Smith   #include <ieeefp.h>
594d71ae5a4SJacob Faibussowitsch void PetscDefaultFPTrap(int sig)
595d71ae5a4SJacob Faibussowitsch {
5963ba16761SJacob Faibussowitsch   PetscErrorCode ierr;
5973ba16761SJacob Faibussowitsch 
598cc9df77eSBarry Smith   PetscFunctionBegin;
5993ba16761SJacob Faibussowitsch   ierr = (*PetscErrorPrintf)("*** floating point error occurred ***\n");
6003ba16761SJacob Faibussowitsch   ierr = PetscError(PETSC_COMM_SELF, 0, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_REPEAT, "floating point error");
6013ba16761SJacob Faibussowitsch   (void)ierr;
602cc9df77eSBarry Smith   PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP);
603cc9df77eSBarry Smith }
604cc9df77eSBarry Smith 
605d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSetFPTrap(PetscFPTrap flag)
606d71ae5a4SJacob Faibussowitsch {
607cc9df77eSBarry Smith   PetscFunctionBegin;
608cf0818bdSBarry Smith   if (flag == PETSC_FP_TRAP_ON) {
60918da0197SPierre Jolivet   #if defined(PETSC_HAVE_FPRESETSTICKY)
610cc9df77eSBarry Smith     fpresetsticky(fpgetsticky());
611cc9df77eSBarry Smith   #elif defined(PETSC_HAVE_FPSETSTICKY)
612cc9df77eSBarry Smith     fpsetsticky(fpgetsticky());
613cc9df77eSBarry Smith   #endif
614cc9df77eSBarry Smith     fpsetmask(FP_X_INV | FP_X_DZ | FP_X_OFL | FP_X_OFL);
61508401ef6SPierre Jolivet     PetscCheck(SIG_ERR != signal(SIGFPE, PetscDefaultFPTrap), PETSC_COMM_SELF, PETSC_ERR_LIB, "Can't set floating point handler");
616cc9df77eSBarry Smith   } else {
61718da0197SPierre Jolivet   #if defined(PETSC_HAVE_FPRESETSTICKY)
618cc9df77eSBarry Smith     fpresetsticky(fpgetsticky());
619cc9df77eSBarry Smith   #elif defined(PETSC_HAVE_FPSETSTICKY)
620cc9df77eSBarry Smith     fpsetsticky(fpgetsticky());
621cc9df77eSBarry Smith   #endif
622cc9df77eSBarry Smith     fpsetmask(0);
62308401ef6SPierre Jolivet     PetscCheck(SIG_ERR != signal(SIGFPE, SIG_DFL), PETSC_COMM_SELF, PETSC_ERR_LIB, "Can't clear floating point handler");
624cc9df77eSBarry Smith   }
625cf0818bdSBarry Smith   _trapmode = flag;
626bd2b07b1SBarry Smith   PetscCall(PetscInfo(NULL, "Using PETSC_HAVE_IEEEFP_H FPTRAP\n"));
6273ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
628cc9df77eSBarry Smith }
629cc9df77eSBarry Smith 
630d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDetermineInitialFPTrap(void)
631d71ae5a4SJacob Faibussowitsch {
632cc9df77eSBarry Smith   PetscFunctionBegin;
6339566063dSJacob Faibussowitsch   PetscCall(PetscInfo(NULL, "Unable to determine initial floating point trapping. Assuming it is off\n"));
6343ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
635cc9df77eSBarry Smith }
636cc9df77eSBarry Smith 
637e5c89e4eSSatish Balay /* -------------------------Default -----------------------------------*/
638e5c89e4eSSatish Balay #else
63999e0435eSBarry Smith 
64066976f2fSJacob Faibussowitsch static void PetscDefaultFPTrap(int sig)
641d71ae5a4SJacob Faibussowitsch {
6423ba16761SJacob Faibussowitsch   PetscErrorCode ierr;
6433ba16761SJacob Faibussowitsch 
644e5c89e4eSSatish Balay   PetscFunctionBegin;
6453ba16761SJacob Faibussowitsch   ierr = (*PetscErrorPrintf)("*** floating point error occurred ***\n");
6463ba16761SJacob Faibussowitsch   ierr = PetscError(PETSC_COMM_SELF, 0, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_REPEAT, "floating point error");
6473ba16761SJacob Faibussowitsch   (void)ierr;
64841e02c4dSJunchao Zhang   PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP);
649e5c89e4eSSatish Balay }
65099e0435eSBarry Smith 
651d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSetFPTrap(PetscFPTrap flag)
652d71ae5a4SJacob Faibussowitsch {
653e5c89e4eSSatish Balay   PetscFunctionBegin;
654bd2b07b1SBarry Smith   if (flag == PETSC_FP_TRAP_ON) {
6553ba16761SJacob Faibussowitsch     if (SIG_ERR == signal(SIGFPE, PetscDefaultFPTrap)) PetscCall((*PetscErrorPrintf)("Can't set floatingpoint handler\n"));
6563ba16761SJacob Faibussowitsch   } else if (SIG_ERR == signal(SIGFPE, SIG_DFL)) PetscCall((*PetscErrorPrintf)("Can't clear floatingpoint handler\n"));
657a297a907SKarl Rupp 
658cf0818bdSBarry Smith   _trapmode = flag;
659bd2b07b1SBarry Smith   PetscCall(PetscInfo(NULL, "Using default FPTRAP\n"));
6603ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
661e5c89e4eSSatish Balay }
662cc9df77eSBarry Smith 
663d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDetermineInitialFPTrap(void)
664d71ae5a4SJacob Faibussowitsch {
665cc9df77eSBarry Smith   PetscFunctionBegin;
6669566063dSJacob Faibussowitsch   PetscCall(PetscInfo(NULL, "Unable to determine initial floating point trapping. Assuming it is off\n"));
6673ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
668cc9df77eSBarry Smith }
669e5c89e4eSSatish Balay #endif
670