xref: /petsc/src/sys/error/fp.c (revision 811af0c4b09a35de4306c442f88bd09fdc09897d)
1 
2 /*
3    IEEE error handler for all machines. Since each OS has
4    enough slight differences we have completely separate codes for each one.
5 */
6 
7 /*
8   This feature test macro provides FE_NOMASK_ENV on GNU.  It must be defined
9   at the top of the file because other headers may pull in fenv.h even when
10   not strictly necessary.  Strictly speaking, we could include ONLY petscconf.h,
11   check PETSC_HAVE_FENV_H, and only define _GNU_SOURCE in that case, but such
12   shenanigans ought to be unnecessary.
13 */
14 #if !defined(_GNU_SOURCE)
15 #define _GNU_SOURCE
16 #endif
17 
18 #include <petsc/private/petscimpl.h> /*I  "petscsys.h"  I*/
19 #include <signal.h>
20 
21 struct PetscFPTrapLink {
22   PetscFPTrap             trapmode;
23   struct PetscFPTrapLink *next;
24 };
25 static PetscFPTrap             _trapmode = PETSC_FP_TRAP_OFF; /* Current trapping mode; see PetscDetermineInitialFPTrap() */
26 static struct PetscFPTrapLink *_trapstack;                    /* Any pushed states of _trapmode */
27 
28 /*@
29    PetscFPTrapPush - push a floating point trapping mode, restored using `PetscFPTrapPop()`
30 
31    Not Collective
32 
33    Input Parameter:
34 .    trap - `PETSC_FP_TRAP_ON` or `PETSC_FP_TRAP_OFF` or any of the values passable to `PetscSetFPTrap()`
35 
36    Level: advanced
37 
38    Notes:
39      This only changes the trapping if the new mode is different than the current mode.
40 
41      This routine is called to turn off trapping for certain LAPACK routines that assume that dividing
42      by zero is acceptable. In particular the routine ieeeck().
43 
44      Most systems by default have all trapping turned off, but certain Fortran compilers have
45      link flags that turn on trapping before the program begins.
46 $       gfortran -ffpe-trap=invalid,zero,overflow,underflow,denormal
47 $       ifort -fpe0
48 
49 .seealso: `PetscFPTrapPop()`, `PetscSetFPTrap()`, `PetscDetermineInitialFPTrap()`
50 @*/
51 PetscErrorCode PetscFPTrapPush(PetscFPTrap trap) {
52   struct PetscFPTrapLink *link;
53 
54   PetscFunctionBegin;
55   PetscCall(PetscNew(&link));
56 #if defined(PETSC_HAVE_THREADSAFETY) && defined(PETSC_HAVE_OPENMP)
57 #pragma omp critical
58 #endif
59   {
60     link->trapmode = _trapmode;
61     link->next     = _trapstack;
62     _trapstack     = link;
63   }
64   if (trap != _trapmode) PetscCall(PetscSetFPTrap(trap));
65   PetscFunctionReturn(0);
66 }
67 
68 /*@
69    PetscFPTrapPop - push a floating point trapping mode, to be restored using `PetscFPTrapPop()`
70 
71    Not Collective
72 
73    Level: advanced
74 
75 .seealso: `PetscFPTrapPush()`, `PetscSetFPTrap()`, `PetscDetermineInitialFPTrap()`
76 @*/
77 PetscErrorCode PetscFPTrapPop(void) {
78   struct PetscFPTrapLink *link;
79 
80   PetscFunctionBegin;
81   if (_trapstack->trapmode != _trapmode) PetscCall(PetscSetFPTrap(_trapstack->trapmode));
82 #if defined(PETSC_HAVE_THREADSAFETY) && defined(PETSC_HAVE_OPENMP)
83 #pragma omp critical
84 #endif
85   {
86     link       = _trapstack;
87     _trapstack = _trapstack->next;
88   }
89   PetscCall(PetscFree(link));
90   PetscFunctionReturn(0);
91 }
92 
93 /*--------------------------------------- ---------------------------------------------------*/
94 #if defined(PETSC_HAVE_SUN4_STYLE_FPTRAP)
95 #include <floatingpoint.h>
96 
97 PETSC_EXTERN PetscErrorCode ieee_flags(char *, char *, char *, char **);
98 PETSC_EXTERN PetscErrorCode ieee_handler(char *, char *, sigfpe_handler_type(int, int, struct sigcontext *, char *));
99 
100 static struct {
101   int   code_no;
102   char *name;
103 } error_codes[] = {
104   {FPE_INTDIV_TRAP,   "integer divide"               },
105   {FPE_FLTOPERR_TRAP, "IEEE operand error"           },
106   {FPE_FLTOVF_TRAP,   "floating point overflow"      },
107   {FPE_FLTUND_TRAP,   "floating point underflow"     },
108   {FPE_FLTDIV_TRAP,   "floating pointing divide"     },
109   {FPE_FLTINEX_TRAP,  "inexact floating point result"},
110   {0,                 "unknown error"                }
111 };
112 #define SIGPC(scp) (scp->sc_pc)
113 
114 /* this function gets called if a trap has occurred and been caught */
115 sigfpe_handler_type PetscDefaultFPTrap(int sig, int code, struct sigcontext *scp, char *addr) {
116   int err_ind = -1;
117 
118   PetscFunctionBegin;
119   for (int j = 0; error_codes[j].code_no; j++) {
120     if (error_codes[j].code_no == code) err_ind = j;
121   }
122 
123   if (err_ind >= 0) (*PetscErrorPrintf)("*** %s occurred at pc=%X ***\n", error_codes[err_ind].name, SIGPC(scp));
124   else (*PetscErrorPrintf)("*** floating point error 0x%x occurred at pc=%X ***\n", code, SIGPC(scp));
125 
126   (void)PetscError(PETSC_COMM_SELF, PETSC_ERR_FP, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_REPEAT, "floating point error");
127   PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP);
128   PetscFunctionReturn(0);
129 }
130 
131 /*@
132    PetscSetFPTrap - Enables traps/exceptions on common floating point errors. This option may not work on certain systems or only a
133    subset of exceptions may be trapable.
134 
135    Not Collective
136 
137    Input Parameters:
138 .  flag - values are
139 .vb
140     PETSC_FP_TRAP_OFF   - do not trap any exceptions
141     PETSC_FP_TRAP_ON - all exceptions that are possible on the system except underflow
142     PETSC_FP_TRAP_INDIV - integer divide by zero
143     PETSC_FP_TRAP_FLTOPERR - improper argument to function, for example with real numbers, the square root of a negative number
144     PETSC_FP_TRAP_FLTOVF - overflow
145     PETSC_FP_TRAP_FLTUND - underflow - not trapped by default on most systems
146     PETSC_FP_TRAP_FLTDIV - floating point divide by zero
147     PETSC_FP_TRAP_FLTINEX - inexact floating point result
148 .ve
149 
150    Options Database Keys:
151 .  -fp_trap <off,on> - turn on or off trapping of floating point exceptions
152 
153    Level: advanced
154 
155    Notes:
156    Currently only `PETSC_FP_TRAP_OFF` and `PETSC_FP_TRAP_ON` are handled. All others are treated as `PETSC_FP_TRAP_ON`.
157 
158    The values are bit values and may be |ed together in the function call
159 
160    On systems that support it this routine causes floating point
161    overflow, divide-by-zero, and invalid-operand (e.g., a NaN), but not underflow, to
162    cause a message to be printed and the program to exit.
163 
164    On many common systems, the floating
165    point exception state is not preserved from the location where the trap
166    occurred through to the signal handler.  In this case, the signal handler
167    will just say that an unknown floating point exception occurred and which
168    function it occurred in.  If you run with -fp_trap in a debugger, it will
169    break on the line where the error occurred.  On systems that support C99
170    floating point exception handling You can check which
171    exception occurred using fetestexcept(FE_ALL_EXCEPT).  See fenv.h
172    (usually at /usr/include/bits/fenv.h) for the enum values on your system.
173 
174 .seealso: `PetscFPTrapPush()`, `PetscFPTrapPop()`, `PetscDetermineInitialFPTrap()`
175 @*/
176 PetscErrorCode PetscSetFPTrap(PetscFPTrap flag) {
177   char *out;
178 
179   PetscFunctionBegin;
180   /* Clear accumulated exceptions.  Used to suppress meaningless messages from f77 programs */
181   (void)ieee_flags("clear", "exception", "all", &out);
182   if (flag) {
183     /*
184       To trap more fp exceptions, including underflow, change the line below to
185       if (ieee_handler("set","all",PetscDefaultFPTrap)) {
186     */
187     if (ieee_handler("set", "common", PetscDefaultFPTrap)) (*PetscErrorPrintf)("Can't set floatingpoint handler\n");
188   } else if (ieee_handler("clear", "common", PetscDefaultFPTrap)) (*PetscErrorPrintf)("Can't clear floatingpoint handler\n");
189 
190   _trapmode = flag;
191   PetscFunctionReturn(0);
192 }
193 
194 /*@
195    PetscDetermineInitialFPTrap - Attempts to determine the floating point trapping that exists when `PetscInitialize()` is called
196 
197    Not Collective
198 
199    Note:
200       Currently only supported on Linux and MacOS. Checks if divide by zero is enable and if so declares that trapping is on.
201 
202    Level: advanced
203 
204 .seealso: `PetscFPTrapPush()`, `PetscFPTrapPop()`, `PetscDetermineInitialFPTrap()`
205 @*/
206 PetscErrorCode PetscDetermineInitialFPTrap(void) {
207   PetscFunctionBegin;
208   PetscCall(PetscInfo(NULL, "Unable to determine initial floating point trapping. Assuming it is off\n"));
209   PetscFunctionReturn(0);
210 }
211 
212 /* -------------------------------------------------------------------------------------------*/
213 #elif defined(PETSC_HAVE_SOLARIS_STYLE_FPTRAP)
214 #include <sunmath.h>
215 #include <floatingpoint.h>
216 #include <siginfo.h>
217 #include <ucontext.h>
218 
219 static struct {
220   int   code_no;
221   char *name;
222 } error_codes[] = {
223   {FPE_FLTINV, "invalid floating point operand"},
224   {FPE_FLTRES, "inexact floating point result" },
225   {FPE_FLTDIV, "division-by-zero"              },
226   {FPE_FLTUND, "floating point underflow"      },
227   {FPE_FLTOVF, "floating point overflow"       },
228   {0,          "unknown error"                 }
229 };
230 #define SIGPC(scp) (scp->si_addr)
231 
232 void PetscDefaultFPTrap(int sig, siginfo_t *scp, ucontext_t *uap) {
233   int err_ind = -1, code = scp->si_code;
234 
235   PetscFunctionBegin;
236   for (int j = 0; error_codes[j].code_no; j++) {
237     if (error_codes[j].code_no == code) err_ind = j;
238   }
239 
240   if (err_ind >= 0) (*PetscErrorPrintf)("*** %s occurred at pc=%X ***\n", error_codes[err_ind].name, SIGPC(scp));
241   else (*PetscErrorPrintf)("*** floating point error 0x%x occurred at pc=%X ***\n", code, SIGPC(scp));
242 
243   (void)PetscError(PETSC_COMM_SELF, 0, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_REPEAT, "floating point error");
244   PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP);
245 }
246 
247 PetscErrorCode PetscSetFPTrap(PetscFPTrap flag) {
248   char *out;
249 
250   PetscFunctionBegin;
251   /* Clear accumulated exceptions.  Used to suppress meaningless messages from f77 programs */
252   (void)ieee_flags("clear", "exception", "all", &out);
253   if (flag == PETSC_FP_TRAP_ON) {
254     if (ieee_handler("set", "common", (sigfpe_handler_type)PetscDefaultFPTrap)) (*PetscErrorPrintf)("Can't set floating point handler\n");
255   } else {
256     if (ieee_handler("clear", "common", (sigfpe_handler_type)PetscDefaultFPTrap)) (*PetscErrorPrintf)("Can't clear floatingpoint handler\n");
257   }
258   _trapmode = flag;
259   PetscFunctionReturn(0);
260 }
261 
262 PetscErrorCode PetscDetermineInitialFPTrap(void) {
263   PetscFunctionBegin;
264   PetscCall(PetscInfo(NULL, "Unable to determine initial floating point trapping. Assuming it is off\n"));
265   PetscFunctionReturn(0);
266 }
267 
268 /* ------------------------------------------------------------------------------------------*/
269 #elif defined(PETSC_HAVE_IRIX_STYLE_FPTRAP)
270 #include <sigfpe.h>
271 static struct {
272   int   code_no;
273   char *name;
274 } error_codes[] = {
275   {_INVALID, "IEEE operand error"      },
276   {_OVERFL,  "floating point overflow" },
277   {_UNDERFL, "floating point underflow"},
278   {_DIVZERO, "floating point divide"   },
279   {0,        "unknown error"           }
280 };
281 void PetscDefaultFPTrap(unsigned exception[], int val[]) {
282   int err_ind = -1, code = exception[0];
283 
284   PetscFunctionBegin;
285   for (int j = 0; error_codes[j].code_no; j++) {
286     if (error_codes[j].code_no == code) err_ind = j;
287   }
288   if (err_ind >= 0) (*PetscErrorPrintf)("*** %s occurred ***\n", error_codes[err_ind].name);
289   else (*PetscErrorPrintf)("*** floating point error 0x%x occurred ***\n", code);
290 
291   (void)PetscError(PETSC_COMM_SELF, 0, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_REPEAT, "floating point error");
292   PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP);
293 }
294 
295 PetscErrorCode PetscSetFPTrap(PetscFPTrap flag) {
296   PetscFunctionBegin;
297   if (flag) handle_sigfpes(_ON, , _EN_UNDERFL | _EN_OVERFL | _EN_DIVZERO | _EN_INVALID, PetscDefaultFPTrap, _ABORT_ON_ERROR, 0);
298   else handle_sigfpes(_OFF, _EN_UNDERFL | _EN_OVERFL | _EN_DIVZERO | _EN_INVALID, 0, _ABORT_ON_ERROR, 0);
299   _trapmode = flag;
300   PetscFunctionReturn(0);
301 }
302 
303 PetscErrorCode PetscDetermineInitialFPTrap(void) {
304   PetscFunctionBegin;
305   PetscCall(PetscInfo(NULL, "Unable to determine initial floating point trapping. Assuming it is off\n"));
306   PetscFunctionReturn(0);
307 }
308 
309 /* -------------------------------------------------------------------------------------------*/
310 #elif defined(PETSC_HAVE_SOLARIS_STYLE_FPTRAP)
311 #include <sunmath.h>
312 #include <floatingpoint.h>
313 #include <siginfo.h>
314 #include <ucontext.h>
315 
316 static struct {
317   int   code_no;
318   char *name;
319 } error_codes[] = {
320   {FPE_FLTINV, "invalid floating point operand"},
321   {FPE_FLTRES, "inexact floating point result" },
322   {FPE_FLTDIV, "division-by-zero"              },
323   {FPE_FLTUND, "floating point underflow"      },
324   {FPE_FLTOVF, "floating point overflow"       },
325   {0,          "unknown error"                 }
326 };
327 #define SIGPC(scp) (scp->si_addr)
328 
329 void PetscDefaultFPTrap(int sig, siginfo_t *scp, ucontext_t *uap) {
330   int err_ind = -1, code = scp->si_code;
331 
332   PetscFunctionBegin;
333   err_ind = -1;
334   for (int j = 0; error_codes[j].code_no; j++) {
335     if (error_codes[j].code_no == code) err_ind = j;
336   }
337 
338   if (err_ind >= 0) (*PetscErrorPrintf)("*** %s occurred at pc=%X ***\n", error_codes[err_ind].name, SIGPC(scp));
339   else (*PetscErrorPrintf)("*** floating point error 0x%x occurred at pc=%X ***\n", code, SIGPC(scp));
340 
341   (void)PetscError(PETSC_COMM_SELF, 0, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_REPEAT, "floating point error");
342   PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP);
343 }
344 
345 PetscErrorCode PetscSetFPTrap(PetscFPTrap flag) {
346   char *out;
347 
348   PetscFunctionBegin;
349   /* Clear accumulated exceptions.  Used to suppress meaningless messages from f77 programs */
350   (void)ieee_flags("clear", "exception", "all", &out);
351   if (flag) {
352     if (ieee_handler("set", "common", (sigfpe_handler_type)PetscDefaultFPTrap)) (*PetscErrorPrintf)("Can't set floating point handler\n");
353   } else {
354     if (ieee_handler("clear", "common", (sigfpe_handler_type)PetscDefaultFPTrap)) (*PetscErrorPrintf)("Can't clear floatingpoint handler\n");
355   }
356   _trapmode = flag;
357   PetscFunctionReturn(0);
358 }
359 
360 PetscErrorCode PetscDetermineInitialFPTrap(void) {
361   PetscFunctionBegin;
362   PetscCall(PetscInfo(NULL, "Unable to determine initial floating point trapping. Assuming it is off\n"));
363   PetscFunctionReturn(0);
364 }
365 
366 /*----------------------------------------------- --------------------------------------------*/
367 #elif defined(PETSC_HAVE_RS6000_STYLE_FPTRAP)
368 /* In "fast" mode, floating point traps are imprecise and ignored.
369    This is the reason for the fptrap(FP_TRAP_SYNC) call */
370 struct sigcontext;
371 #include <fpxcp.h>
372 #include <fptrap.h>
373 #define FPE_FLTOPERR_TRAP (fptrap_t)(0x20000000)
374 #define FPE_FLTOVF_TRAP   (fptrap_t)(0x10000000)
375 #define FPE_FLTUND_TRAP   (fptrap_t)(0x08000000)
376 #define FPE_FLTDIV_TRAP   (fptrap_t)(0x04000000)
377 #define FPE_FLTINEX_TRAP  (fptrap_t)(0x02000000)
378 
379 static struct {
380   int   code_no;
381   char *name;
382 } error_codes[] = {
383   {FPE_FLTOPERR_TRAP, "IEEE operand error"           },
384   {FPE_FLTOVF_TRAP,   "floating point overflow"      },
385   {FPE_FLTUND_TRAP,   "floating point underflow"     },
386   {FPE_FLTDIV_TRAP,   "floating point divide"        },
387   {FPE_FLTINEX_TRAP,  "inexact floating point result"},
388   {0,                 "unknown error"                }
389 };
390 #define SIGPC(scp)        (0) /* Info MIGHT be in scp->sc_jmpbuf.jmp_context.iar */
391 /*
392    For some reason, scp->sc_jmpbuf does not work on the RS6000, even though
393    it looks like it should from the include definitions.  It is probably
394    some strange interaction with the "POSIX_SOURCE" that we require.
395 */
396 
397 void PetscDefaultFPTrap(int sig, int code, struct sigcontext *scp) {
398   int      err_ind, j;
399   fp_ctx_t flt_context;
400 
401   PetscFunctionBegin;
402   fp_sh_trap_info(scp, &flt_context);
403 
404   err_ind = -1;
405   for (j = 0; error_codes[j].code_no; j++) {
406     if (error_codes[j].code_no == flt_context.trap) err_ind = j;
407   }
408 
409   if (err_ind >= 0) (*PetscErrorPrintf)("*** %s occurred ***\n", error_codes[err_ind].name);
410   else (*PetscErrorPrintf)("*** floating point error 0x%x occurred ***\n", flt_context.trap);
411 
412   (void)PetscError(PETSC_COMM_SELF, 0, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_REPEAT, "floating point error");
413   PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP);
414 }
415 
416 PetscErrorCode PetscSetFPTrap(PetscFPTrap flag) {
417   PetscFunctionBegin;
418   if (flag) {
419     signal(SIGFPE, (void (*)(int))PetscDefaultFPTrap);
420     fp_trap(FP_TRAP_SYNC);
421     fp_enable(TRP_INVALID | TRP_DIV_BY_ZERO | TRP_OVERFLOW | TRP_UNDERFLOW);
422     /* fp_enable(mask) for individual traps.  Values are:
423        TRP_INVALID
424        TRP_DIV_BY_ZERO
425        TRP_OVERFLOW
426        TRP_UNDERFLOW
427        TRP_INEXACT
428        Can OR then together.
429        fp_enable_all(); for all traps.
430     */
431   } else {
432     signal(SIGFPE, SIG_DFL);
433     fp_disable(TRP_INVALID | TRP_DIV_BY_ZERO | TRP_OVERFLOW | TRP_UNDERFLOW);
434     fp_trap(FP_TRAP_OFF);
435   }
436   _trapmode = flag;
437   PetscFunctionReturn(0);
438 }
439 
440 PetscErrorCode PetscDetermineInitialFPTrap(void) {
441   PetscFunctionBegin;
442   PetscCall(PetscInfo(NULL, "Unable to determine initial floating point trapping. Assuming it is off\n"));
443   PetscFunctionReturn(0);
444 }
445 
446 /* ------------------------------------------------------------*/
447 #elif defined(PETSC_HAVE_WINDOWS_COMPILERS)
448 #include <float.h>
449 void PetscDefaultFPTrap(int sig) {
450   PetscFunctionBegin;
451   (*PetscErrorPrintf)("*** floating point error occurred ***\n");
452   PetscError(PETSC_COMM_SELF, 0, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_REPEAT, "floating point error");
453   PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP);
454 }
455 
456 PetscErrorCode PetscSetFPTrap(PetscFPTrap flag) {
457   unsigned int cw;
458 
459   PetscFunctionBegin;
460   if (flag) {
461     cw = _EM_INVALID | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW;
462     PetscCheck(SIG_ERR != signal(SIGFPE, PetscDefaultFPTrap), PETSC_COMM_SELF, PETSC_ERR_LIB, "Can't set floating point handler");
463   } else {
464     cw = 0;
465     PetscCheck(SIG_ERR != signal(SIGFPE, SIG_DFL), PETSC_COMM_SELF, PETSC_ERR_LIB, "Can't clear floating point handler");
466   }
467   (void)_controlfp(0, cw);
468   _trapmode = flag;
469   PetscFunctionReturn(0);
470 }
471 
472 PetscErrorCode PetscDetermineInitialFPTrap(void) {
473   PetscFunctionBegin;
474   PetscCall(PetscInfo(NULL, "Unable to determine initial floating point trapping. Assuming it is off\n"));
475   PetscFunctionReturn(0);
476 }
477 
478 /* ------------------------------------------------------------*/
479 #elif defined(PETSC_HAVE_FENV_H) && !defined(__cplusplus)
480 /*
481    C99 style floating point environment.
482 
483    Note that C99 merely specifies how to save, restore, and clear the floating
484    point environment as well as defining an enumeration of exception codes.  In
485    particular, C99 does not specify how to make floating point exceptions raise
486    a signal.  Glibc offers this capability through FE_NOMASK_ENV (or with finer
487    granularity, feenableexcept()), xmmintrin.h offers _MM_SET_EXCEPTION_MASK().
488 */
489 #include <fenv.h>
490 typedef struct {
491   int         code;
492   const char *name;
493 } FPNode;
494 static const FPNode error_codes[] = {
495   {FE_DIVBYZERO, "divide by zero"                                 },
496   {FE_INEXACT,   "inexact floating point result"                  },
497   {FE_INVALID,   "invalid floating point arguments (domain error)"},
498   {FE_OVERFLOW,  "floating point overflow"                        },
499   {FE_UNDERFLOW, "floating point underflow"                       },
500   {0,            "unknown error"                                  }
501 };
502 
503 void PetscDefaultFPTrap(int sig) {
504   const FPNode *node;
505   int           code;
506   PetscBool     matched = PETSC_FALSE;
507 
508   PetscFunctionBegin;
509   /* Note: While it is possible for the exception state to be preserved by the
510    * kernel, this seems to be rare which makes the following flag testing almost
511    * useless.  But on a system where the flags can be preserved, it would provide
512    * more detail.
513    */
514   code = fetestexcept(FE_ALL_EXCEPT);
515   for (node = &error_codes[0]; node->code; node++) {
516     if (code & node->code) {
517       matched = PETSC_TRUE;
518       (*PetscErrorPrintf)("*** floating point error \"%s\" occurred ***\n", node->name);
519       code &= ~node->code; /* Unset this flag since it has been processed */
520     }
521   }
522   if (!matched || code) { /* If any remaining flags are set, or we didn't process any flags */
523     (*PetscErrorPrintf)("*** unknown floating point error occurred ***\n");
524     (*PetscErrorPrintf)("The specific exception can be determined by running in a debugger.  When the\n");
525     (*PetscErrorPrintf)("debugger traps the signal, the exception can be found with fetestexcept(0x%x)\n", FE_ALL_EXCEPT);
526     (*PetscErrorPrintf)("where the result is a bitwise OR of the following flags:\n");
527     (*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);
528   }
529 
530   (*PetscErrorPrintf)("Try option -start_in_debugger\n");
531 #if PetscDefined(USE_DEBUG)
532   (*PetscErrorPrintf)("likely location of problem given in stack below\n");
533   (*PetscErrorPrintf)("---------------------  Stack Frames ------------------------------------\n");
534   PetscStackView(PETSC_STDOUT);
535 #else
536   (*PetscErrorPrintf)("configure using --with-debugging=yes, recompile, link, and run \n");
537   (*PetscErrorPrintf)("with -start_in_debugger to get more information on the crash.\n");
538 #endif
539   PetscError(PETSC_COMM_SELF, 0, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_INITIAL, "trapped floating point error");
540   PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP);
541 }
542 
543 PetscErrorCode PetscSetFPTrap(PetscFPTrap flag) {
544   PetscFunctionBegin;
545   if (flag) {
546     /* Clear any flags that are currently set so that activating trapping will not immediately call the signal handler. */
547     PetscCheck(!feclearexcept(FE_ALL_EXCEPT), PETSC_COMM_SELF, PETSC_ERR_LIB, "Cannot clear floating point exception flags");
548 #if defined(FE_NOMASK_ENV)
549     /* Could use fesetenv(FE_NOMASK_ENV), but that causes spurious exceptions (like gettimeofday() -> PetscLogDouble). */
550     /* PetscCheck(feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW) != -1,PETSC_COMM_SELF,PETSC_ERR_LIB,"Cannot activate floating point exceptions"); */
551     PetscCheck(feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW) != -1, PETSC_COMM_SELF, PETSC_ERR_LIB, "Cannot activate floating point exceptions");
552 #elif defined PETSC_HAVE_XMMINTRIN_H
553     _MM_SET_EXCEPTION_MASK(_MM_GET_EXCEPTION_MASK() & ~_MM_MASK_DIV_ZERO);
554     _MM_SET_EXCEPTION_MASK(_MM_GET_EXCEPTION_MASK() & ~_MM_MASK_UNDERFLOW);
555     _MM_SET_EXCEPTION_MASK(_MM_GET_EXCEPTION_MASK() & ~_MM_MASK_OVERFLOW);
556     _MM_SET_EXCEPTION_MASK(_MM_GET_EXCEPTION_MASK() & ~_MM_MASK_INVALID);
557 #else
558     /* C99 does not provide a way to modify the environment so there is no portable way to activate trapping. */
559 #endif
560     PetscCheck(SIG_ERR != signal(SIGFPE, PetscDefaultFPTrap), PETSC_COMM_SELF, PETSC_ERR_LIB, "Can't set floating point handler");
561   } else {
562     PetscCheck(!fesetenv(FE_DFL_ENV), PETSC_COMM_SELF, PETSC_ERR_LIB, "Cannot disable floating point exceptions");
563     /* can use _MM_SET_EXCEPTION_MASK(_MM_GET_EXCEPTION_MASK() | _MM_MASK_UNDERFLOW); if PETSC_HAVE_XMMINTRIN_H exists */
564     PetscCheck(SIG_ERR != signal(SIGFPE, SIG_DFL), PETSC_COMM_SELF, PETSC_ERR_LIB, "Can't clear floating point handler");
565   }
566   _trapmode = flag;
567   PetscFunctionReturn(0);
568 }
569 
570 PetscErrorCode PetscDetermineInitialFPTrap(void) {
571 #if defined(FE_NOMASK_ENV) || defined PETSC_HAVE_XMMINTRIN_H
572   unsigned int flags;
573 #endif
574 
575   PetscFunctionBegin;
576 #if defined(FE_NOMASK_ENV)
577   flags = fegetexcept();
578   if (flags & FE_DIVBYZERO) {
579 #elif defined PETSC_HAVE_XMMINTRIN_H
580   flags = _MM_GET_EXCEPTION_MASK();
581   if (!(flags & _MM_MASK_DIV_ZERO)) {
582 #else
583   PetscCall(PetscInfo(NULL, "Floating point trapping unknown, assuming off\n"));
584   PetscFunctionReturn(0);
585 #endif
586 #if defined(FE_NOMASK_ENV) || defined PETSC_HAVE_XMMINTRIN_H
587     _trapmode = PETSC_FP_TRAP_ON;
588     PetscCall(PetscInfo(NULL, "Floating point trapping is on by default %d\n", flags));
589   } else {
590     _trapmode = PETSC_FP_TRAP_OFF;
591     PetscCall(PetscInfo(NULL, "Floating point trapping is off by default %d\n", flags));
592   }
593   PetscFunctionReturn(0);
594 #endif
595 }
596 
597 /* ------------------------------------------------------------*/
598 #elif defined(PETSC_HAVE_IEEEFP_H)
599 #include <ieeefp.h>
600 void PetscDefaultFPTrap(int sig) {
601   PetscFunctionBegin;
602   (*PetscErrorPrintf)("*** floating point error occurred ***\n");
603   PetscError(PETSC_COMM_SELF, 0, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_REPEAT, "floating point error");
604   PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP);
605 }
606 
607 PetscErrorCode PetscSetFPTrap(PetscFPTrap flag) {
608   PetscFunctionBegin;
609   if (flag == PETSC_FP_TRAP_ON) {
610 #if defined(PETSC_HAVE_FPPRESETSTICKY)
611     fpresetsticky(fpgetsticky());
612 #elif defined(PETSC_HAVE_FPSETSTICKY)
613     fpsetsticky(fpgetsticky());
614 #endif
615     fpsetmask(FP_X_INV | FP_X_DZ | FP_X_OFL | FP_X_OFL);
616     PetscCheck(SIG_ERR != signal(SIGFPE, PetscDefaultFPTrap), PETSC_COMM_SELF, PETSC_ERR_LIB, "Can't set floating point handler");
617   } else {
618 #if defined(PETSC_HAVE_FPPRESETSTICKY)
619     fpresetsticky(fpgetsticky());
620 #elif defined(PETSC_HAVE_FPSETSTICKY)
621     fpsetsticky(fpgetsticky());
622 #endif
623     fpsetmask(0);
624     PetscCheck(SIG_ERR != signal(SIGFPE, SIG_DFL), PETSC_COMM_SELF, PETSC_ERR_LIB, "Can't clear floating point handler");
625   }
626   _trapmode = flag;
627   PetscFunctionReturn(0);
628 }
629 
630 PetscErrorCode PetscDetermineInitialFPTrap(void) {
631   PetscFunctionBegin;
632   PetscCall(PetscInfo(NULL, "Unable to determine initial floating point trapping. Assuming it is off\n"));
633   PetscFunctionReturn(0);
634 }
635 
636 /* -------------------------Default -----------------------------------*/
637 #else
638 
639 void PetscDefaultFPTrap(int sig) {
640   PetscFunctionBegin;
641   (*PetscErrorPrintf)("*** floating point error occurred ***\n");
642   PetscError(PETSC_COMM_SELF, 0, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_REPEAT, "floating point error");
643   PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP);
644 }
645 
646 PetscErrorCode PetscSetFPTrap(PetscFPTrap flag) {
647   PetscFunctionBegin;
648   if (flag) {
649     if (SIG_ERR == signal(SIGFPE, PetscDefaultFPTrap)) (*PetscErrorPrintf)("Can't set floatingpoint handler\n");
650   } else if (SIG_ERR == signal(SIGFPE, SIG_DFL)) (*PetscErrorPrintf)("Can't clear floatingpoint handler\n");
651 
652   _trapmode = flag;
653   PetscFunctionReturn(0);
654 }
655 
656 PetscErrorCode PetscDetermineInitialFPTrap(void) {
657   PetscFunctionBegin;
658   PetscCall(PetscInfo(NULL, "Unable to determine initial floating point trapping. Assuming it is off\n"));
659   PetscFunctionReturn(0);
660 }
661 #endif
662