xref: /petsc/src/sys/error/fp.c (revision a69119a591a03a9d906b29c0a4e9802e4d7c9795)
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    Caution:
175    On certain machines, in particular the IBM PowerPC, floating point
176    trapping may be VERY slow!
177 
178 .seealso: `PetscFPTrapPush()`, `PetscFPTrapPop()`, `PetscDetermineInitialFPTrap()`
179 @*/
180 PetscErrorCode PetscSetFPTrap(PetscFPTrap flag) {
181   char *out;
182 
183   PetscFunctionBegin;
184   /* Clear accumulated exceptions.  Used to suppress meaningless messages from f77 programs */
185   (void)ieee_flags("clear", "exception", "all", &out);
186   if (flag) {
187     /*
188       To trap more fp exceptions, including underflow, change the line below to
189       if (ieee_handler("set","all",PetscDefaultFPTrap)) {
190     */
191     if (ieee_handler("set", "common", PetscDefaultFPTrap)) (*PetscErrorPrintf)("Can't set floatingpoint handler\n");
192   } else if (ieee_handler("clear", "common", PetscDefaultFPTrap)) (*PetscErrorPrintf)("Can't clear floatingpoint handler\n");
193 
194   _trapmode = flag;
195   PetscFunctionReturn(0);
196 }
197 
198 /*@
199    PetscDetermineInitialFPTrap - Attempts to determine the floating point trapping that exists when PetscInitialize() is called
200 
201    Not Collective
202 
203    Notes:
204       Currently only supported on Linux and MacOS. Checks if divide by zero is enable and if so declares that trapping is on.
205 
206    Level: advanced
207 
208 .seealso: `PetscFPTrapPush()`, `PetscFPTrapPop()`, `PetscDetermineInitialFPTrap()`
209 @*/
210 PetscErrorCode PetscDetermineInitialFPTrap(void) {
211   PetscFunctionBegin;
212   PetscCall(PetscInfo(NULL, "Unable to determine initial floating point trapping. Assuming it is off\n"));
213   PetscFunctionReturn(0);
214 }
215 
216 /* -------------------------------------------------------------------------------------------*/
217 #elif defined(PETSC_HAVE_SOLARIS_STYLE_FPTRAP)
218 #include <sunmath.h>
219 #include <floatingpoint.h>
220 #include <siginfo.h>
221 #include <ucontext.h>
222 
223 static struct {
224   int   code_no;
225   char *name;
226 } error_codes[] = {
227   {FPE_FLTINV, "invalid floating point operand"},
228   {FPE_FLTRES, "inexact floating point result" },
229   {FPE_FLTDIV, "division-by-zero"              },
230   {FPE_FLTUND, "floating point underflow"      },
231   {FPE_FLTOVF, "floating point overflow"       },
232   {0,          "unknown error"                 }
233 };
234 #define SIGPC(scp) (scp->si_addr)
235 
236 void PetscDefaultFPTrap(int sig, siginfo_t *scp, ucontext_t *uap) {
237   int err_ind = -1, code = scp->si_code;
238 
239   PetscFunctionBegin;
240   for (int j = 0; error_codes[j].code_no; j++) {
241     if (error_codes[j].code_no == code) err_ind = j;
242   }
243 
244   if (err_ind >= 0) (*PetscErrorPrintf)("*** %s occurred at pc=%X ***\n", error_codes[err_ind].name, SIGPC(scp));
245   else (*PetscErrorPrintf)("*** floating point error 0x%x occurred at pc=%X ***\n", code, SIGPC(scp));
246 
247   (void)PetscError(PETSC_COMM_SELF, 0, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_REPEAT, "floating point error");
248   PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP);
249 }
250 
251 PetscErrorCode PetscSetFPTrap(PetscFPTrap flag) {
252   char *out;
253 
254   PetscFunctionBegin;
255   /* Clear accumulated exceptions.  Used to suppress meaningless messages from f77 programs */
256   (void)ieee_flags("clear", "exception", "all", &out);
257   if (flag == PETSC_FP_TRAP_ON) {
258     if (ieee_handler("set", "common", (sigfpe_handler_type)PetscDefaultFPTrap)) (*PetscErrorPrintf)("Can't set floating point handler\n");
259   } else {
260     if (ieee_handler("clear", "common", (sigfpe_handler_type)PetscDefaultFPTrap)) (*PetscErrorPrintf)("Can't clear floatingpoint handler\n");
261   }
262   _trapmode = flag;
263   PetscFunctionReturn(0);
264 }
265 
266 PetscErrorCode PetscDetermineInitialFPTrap(void) {
267   PetscFunctionBegin;
268   PetscCall(PetscInfo(NULL, "Unable to determine initial floating point trapping. Assuming it is off\n"));
269   PetscFunctionReturn(0);
270 }
271 
272 /* ------------------------------------------------------------------------------------------*/
273 #elif defined(PETSC_HAVE_IRIX_STYLE_FPTRAP)
274 #include <sigfpe.h>
275 static struct {
276   int   code_no;
277   char *name;
278 } error_codes[] = {
279   {_INVALID, "IEEE operand error"      },
280   {_OVERFL,  "floating point overflow" },
281   {_UNDERFL, "floating point underflow"},
282   {_DIVZERO, "floating point divide"   },
283   {0,        "unknown error"           }
284 };
285 void PetscDefaultFPTrap(unsigned exception[], int val[]) {
286   int err_ind = -1, code = exception[0];
287 
288   PetscFunctionBegin;
289   for (int j = 0; error_codes[j].code_no; j++) {
290     if (error_codes[j].code_no == code) err_ind = j;
291   }
292   if (err_ind >= 0) (*PetscErrorPrintf)("*** %s occurred ***\n", error_codes[err_ind].name);
293   else (*PetscErrorPrintf)("*** floating point error 0x%x occurred ***\n", code);
294 
295   (void)PetscError(PETSC_COMM_SELF, 0, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_REPEAT, "floating point error");
296   PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP);
297 }
298 
299 PetscErrorCode PetscSetFPTrap(PetscFPTrap flag) {
300   PetscFunctionBegin;
301   if (flag) handle_sigfpes(_ON, , _EN_UNDERFL | _EN_OVERFL | _EN_DIVZERO | _EN_INVALID, PetscDefaultFPTrap, _ABORT_ON_ERROR, 0);
302   else handle_sigfpes(_OFF, _EN_UNDERFL | _EN_OVERFL | _EN_DIVZERO | _EN_INVALID, 0, _ABORT_ON_ERROR, 0);
303   _trapmode = flag;
304   PetscFunctionReturn(0);
305 }
306 
307 PetscErrorCode PetscDetermineInitialFPTrap(void) {
308   PetscFunctionBegin;
309   PetscCall(PetscInfo(NULL, "Unable to determine initial floating point trapping. Assuming it is off\n"));
310   PetscFunctionReturn(0);
311 }
312 
313 /* -------------------------------------------------------------------------------------------*/
314 #elif defined(PETSC_HAVE_SOLARIS_STYLE_FPTRAP)
315 #include <sunmath.h>
316 #include <floatingpoint.h>
317 #include <siginfo.h>
318 #include <ucontext.h>
319 
320 static struct {
321   int   code_no;
322   char *name;
323 } error_codes[] = {
324   {FPE_FLTINV, "invalid floating point operand"},
325   {FPE_FLTRES, "inexact floating point result" },
326   {FPE_FLTDIV, "division-by-zero"              },
327   {FPE_FLTUND, "floating point underflow"      },
328   {FPE_FLTOVF, "floating point overflow"       },
329   {0,          "unknown error"                 }
330 };
331 #define SIGPC(scp) (scp->si_addr)
332 
333 void PetscDefaultFPTrap(int sig, siginfo_t *scp, ucontext_t *uap) {
334   int err_ind = -1, code = scp->si_code;
335 
336   PetscFunctionBegin;
337   err_ind = -1;
338   for (int j = 0; error_codes[j].code_no; j++) {
339     if (error_codes[j].code_no == code) err_ind = j;
340   }
341 
342   if (err_ind >= 0) (*PetscErrorPrintf)("*** %s occurred at pc=%X ***\n", error_codes[err_ind].name, SIGPC(scp));
343   else (*PetscErrorPrintf)("*** floating point error 0x%x occurred at pc=%X ***\n", code, SIGPC(scp));
344 
345   (void)PetscError(PETSC_COMM_SELF, 0, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_REPEAT, "floating point error");
346   PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP);
347 }
348 
349 PetscErrorCode PetscSetFPTrap(PetscFPTrap flag) {
350   char *out;
351 
352   PetscFunctionBegin;
353   /* Clear accumulated exceptions.  Used to suppress meaningless messages from f77 programs */
354   (void)ieee_flags("clear", "exception", "all", &out);
355   if (flag) {
356     if (ieee_handler("set", "common", (sigfpe_handler_type)PetscDefaultFPTrap)) (*PetscErrorPrintf)("Can't set floating point handler\n");
357   } else {
358     if (ieee_handler("clear", "common", (sigfpe_handler_type)PetscDefaultFPTrap)) (*PetscErrorPrintf)("Can't clear floatingpoint handler\n");
359   }
360   _trapmode = flag;
361   PetscFunctionReturn(0);
362 }
363 
364 PetscErrorCode PetscDetermineInitialFPTrap(void) {
365   PetscFunctionBegin;
366   PetscCall(PetscInfo(NULL, "Unable to determine initial floating point trapping. Assuming it is off\n"));
367   PetscFunctionReturn(0);
368 }
369 
370 /*----------------------------------------------- --------------------------------------------*/
371 #elif defined(PETSC_HAVE_RS6000_STYLE_FPTRAP)
372 /* In "fast" mode, floating point traps are imprecise and ignored.
373    This is the reason for the fptrap(FP_TRAP_SYNC) call */
374 struct sigcontext;
375 #include <fpxcp.h>
376 #include <fptrap.h>
377 #define FPE_FLTOPERR_TRAP (fptrap_t)(0x20000000)
378 #define FPE_FLTOVF_TRAP   (fptrap_t)(0x10000000)
379 #define FPE_FLTUND_TRAP   (fptrap_t)(0x08000000)
380 #define FPE_FLTDIV_TRAP   (fptrap_t)(0x04000000)
381 #define FPE_FLTINEX_TRAP  (fptrap_t)(0x02000000)
382 
383 static struct {
384   int   code_no;
385   char *name;
386 } error_codes[] = {
387   {FPE_FLTOPERR_TRAP, "IEEE operand error"           },
388   {FPE_FLTOVF_TRAP,   "floating point overflow"      },
389   {FPE_FLTUND_TRAP,   "floating point underflow"     },
390   {FPE_FLTDIV_TRAP,   "floating point divide"        },
391   {FPE_FLTINEX_TRAP,  "inexact floating point result"},
392   {0,                 "unknown error"                }
393 };
394 #define SIGPC(scp)        (0) /* Info MIGHT be in scp->sc_jmpbuf.jmp_context.iar */
395 /*
396    For some reason, scp->sc_jmpbuf does not work on the RS6000, even though
397    it looks like it should from the include definitions.  It is probably
398    some strange interaction with the "POSIX_SOURCE" that we require.
399 */
400 
401 void PetscDefaultFPTrap(int sig, int code, struct sigcontext *scp) {
402   int      err_ind, j;
403   fp_ctx_t flt_context;
404 
405   PetscFunctionBegin;
406   fp_sh_trap_info(scp, &flt_context);
407 
408   err_ind = -1;
409   for (j = 0; error_codes[j].code_no; j++) {
410     if (error_codes[j].code_no == flt_context.trap) err_ind = j;
411   }
412 
413   if (err_ind >= 0) (*PetscErrorPrintf)("*** %s occurred ***\n", error_codes[err_ind].name);
414   else (*PetscErrorPrintf)("*** floating point error 0x%x occurred ***\n", flt_context.trap);
415 
416   (void)PetscError(PETSC_COMM_SELF, 0, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_REPEAT, "floating point error");
417   PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP);
418 }
419 
420 PetscErrorCode PetscSetFPTrap(PetscFPTrap flag) {
421   PetscFunctionBegin;
422   if (flag) {
423     signal(SIGFPE, (void (*)(int))PetscDefaultFPTrap);
424     fp_trap(FP_TRAP_SYNC);
425     fp_enable(TRP_INVALID | TRP_DIV_BY_ZERO | TRP_OVERFLOW | TRP_UNDERFLOW);
426     /* fp_enable(mask) for individual traps.  Values are:
427        TRP_INVALID
428        TRP_DIV_BY_ZERO
429        TRP_OVERFLOW
430        TRP_UNDERFLOW
431        TRP_INEXACT
432        Can OR then together.
433        fp_enable_all(); for all traps.
434     */
435   } else {
436     signal(SIGFPE, SIG_DFL);
437     fp_disable(TRP_INVALID | TRP_DIV_BY_ZERO | TRP_OVERFLOW | TRP_UNDERFLOW);
438     fp_trap(FP_TRAP_OFF);
439   }
440   _trapmode = flag;
441   PetscFunctionReturn(0);
442 }
443 
444 PetscErrorCode PetscDetermineInitialFPTrap(void) {
445   PetscFunctionBegin;
446   PetscCall(PetscInfo(NULL, "Unable to determine initial floating point trapping. Assuming it is off\n"));
447   PetscFunctionReturn(0);
448 }
449 
450 /* ------------------------------------------------------------*/
451 #elif defined(PETSC_HAVE_WINDOWS_COMPILERS)
452 #include <float.h>
453 void PetscDefaultFPTrap(int sig) {
454   PetscFunctionBegin;
455   (*PetscErrorPrintf)("*** floating point error occurred ***\n");
456   PetscError(PETSC_COMM_SELF, 0, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_REPEAT, "floating point error");
457   PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP);
458 }
459 
460 PetscErrorCode PetscSetFPTrap(PetscFPTrap flag) {
461   unsigned int cw;
462 
463   PetscFunctionBegin;
464   if (flag) {
465     cw = _EM_INVALID | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW;
466     PetscCheck(SIG_ERR != signal(SIGFPE, PetscDefaultFPTrap), PETSC_COMM_SELF, PETSC_ERR_LIB, "Can't set floating point handler");
467   } else {
468     cw = 0;
469     PetscCheck(SIG_ERR != signal(SIGFPE, SIG_DFL), PETSC_COMM_SELF, PETSC_ERR_LIB, "Can't clear floating point handler");
470   }
471   (void)_controlfp(0, cw);
472   _trapmode = flag;
473   PetscFunctionReturn(0);
474 }
475 
476 PetscErrorCode PetscDetermineInitialFPTrap(void) {
477   PetscFunctionBegin;
478   PetscCall(PetscInfo(NULL, "Unable to determine initial floating point trapping. Assuming it is off\n"));
479   PetscFunctionReturn(0);
480 }
481 
482 /* ------------------------------------------------------------*/
483 #elif defined(PETSC_HAVE_FENV_H) && !defined(__cplusplus)
484 /*
485    C99 style floating point environment.
486 
487    Note that C99 merely specifies how to save, restore, and clear the floating
488    point environment as well as defining an enumeration of exception codes.  In
489    particular, C99 does not specify how to make floating point exceptions raise
490    a signal.  Glibc offers this capability through FE_NOMASK_ENV (or with finer
491    granularity, feenableexcept()), xmmintrin.h offers _MM_SET_EXCEPTION_MASK().
492 */
493 #include <fenv.h>
494 typedef struct {
495   int         code;
496   const char *name;
497 } FPNode;
498 static const FPNode error_codes[] = {
499   {FE_DIVBYZERO, "divide by zero"                                 },
500   {FE_INEXACT,   "inexact floating point result"                  },
501   {FE_INVALID,   "invalid floating point arguments (domain error)"},
502   {FE_OVERFLOW,  "floating point overflow"                        },
503   {FE_UNDERFLOW, "floating point underflow"                       },
504   {0,            "unknown error"                                  }
505 };
506 
507 void PetscDefaultFPTrap(int sig) {
508   const FPNode *node;
509   int           code;
510   PetscBool     matched = PETSC_FALSE;
511 
512   PetscFunctionBegin;
513   /* Note: While it is possible for the exception state to be preserved by the
514    * kernel, this seems to be rare which makes the following flag testing almost
515    * useless.  But on a system where the flags can be preserved, it would provide
516    * more detail.
517    */
518   code = fetestexcept(FE_ALL_EXCEPT);
519   for (node = &error_codes[0]; node->code; node++) {
520     if (code & node->code) {
521       matched = PETSC_TRUE;
522       (*PetscErrorPrintf)("*** floating point error \"%s\" occurred ***\n", node->name);
523       code &= ~node->code; /* Unset this flag since it has been processed */
524     }
525   }
526   if (!matched || code) { /* If any remaining flags are set, or we didn't process any flags */
527     (*PetscErrorPrintf)("*** unknown floating point error occurred ***\n");
528     (*PetscErrorPrintf)("The specific exception can be determined by running in a debugger.  When the\n");
529     (*PetscErrorPrintf)("debugger traps the signal, the exception can be found with fetestexcept(0x%x)\n", FE_ALL_EXCEPT);
530     (*PetscErrorPrintf)("where the result is a bitwise OR of the following flags:\n");
531     (*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);
532   }
533 
534   (*PetscErrorPrintf)("Try option -start_in_debugger\n");
535 #if PetscDefined(USE_DEBUG)
536   (*PetscErrorPrintf)("likely location of problem given in stack below\n");
537   (*PetscErrorPrintf)("---------------------  Stack Frames ------------------------------------\n");
538   PetscStackView(PETSC_STDOUT);
539 #else
540   (*PetscErrorPrintf)("configure using --with-debugging=yes, recompile, link, and run \n");
541   (*PetscErrorPrintf)("with -start_in_debugger to get more information on the crash.\n");
542 #endif
543   PetscError(PETSC_COMM_SELF, 0, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_INITIAL, "trapped floating point error");
544   PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP);
545 }
546 
547 PetscErrorCode PetscSetFPTrap(PetscFPTrap flag) {
548   PetscFunctionBegin;
549   if (flag) {
550     /* Clear any flags that are currently set so that activating trapping will not immediately call the signal handler. */
551     PetscCheck(!feclearexcept(FE_ALL_EXCEPT), PETSC_COMM_SELF, PETSC_ERR_LIB, "Cannot clear floating point exception flags");
552 #if defined(FE_NOMASK_ENV)
553     /* Could use fesetenv(FE_NOMASK_ENV), but that causes spurious exceptions (like gettimeofday() -> PetscLogDouble). */
554     /* PetscCheck(feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW) != -1,PETSC_COMM_SELF,PETSC_ERR_LIB,"Cannot activate floating point exceptions"); */
555     PetscCheck(feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW) != -1, PETSC_COMM_SELF, PETSC_ERR_LIB, "Cannot activate floating point exceptions");
556 #elif defined PETSC_HAVE_XMMINTRIN_H
557     _MM_SET_EXCEPTION_MASK(_MM_GET_EXCEPTION_MASK() & ~_MM_MASK_DIV_ZERO);
558     _MM_SET_EXCEPTION_MASK(_MM_GET_EXCEPTION_MASK() & ~_MM_MASK_UNDERFLOW);
559     _MM_SET_EXCEPTION_MASK(_MM_GET_EXCEPTION_MASK() & ~_MM_MASK_OVERFLOW);
560     _MM_SET_EXCEPTION_MASK(_MM_GET_EXCEPTION_MASK() & ~_MM_MASK_INVALID);
561 #else
562     /* C99 does not provide a way to modify the environment so there is no portable way to activate trapping. */
563 #endif
564     PetscCheck(SIG_ERR != signal(SIGFPE, PetscDefaultFPTrap), PETSC_COMM_SELF, PETSC_ERR_LIB, "Can't set floating point handler");
565   } else {
566     PetscCheck(!fesetenv(FE_DFL_ENV), PETSC_COMM_SELF, PETSC_ERR_LIB, "Cannot disable floating point exceptions");
567     /* can use _MM_SET_EXCEPTION_MASK(_MM_GET_EXCEPTION_MASK() | _MM_MASK_UNDERFLOW); if PETSC_HAVE_XMMINTRIN_H exists */
568     PetscCheck(SIG_ERR != signal(SIGFPE, SIG_DFL), PETSC_COMM_SELF, PETSC_ERR_LIB, "Can't clear floating point handler");
569   }
570   _trapmode = flag;
571   PetscFunctionReturn(0);
572 }
573 
574 PetscErrorCode PetscDetermineInitialFPTrap(void) {
575 #if defined(FE_NOMASK_ENV) || defined PETSC_HAVE_XMMINTRIN_H
576   unsigned int flags;
577 #endif
578 
579   PetscFunctionBegin;
580 #if defined(FE_NOMASK_ENV)
581   flags = fegetexcept();
582   if (flags & FE_DIVBYZERO) {
583 #elif defined PETSC_HAVE_XMMINTRIN_H
584   flags = _MM_GET_EXCEPTION_MASK();
585   if (!(flags & _MM_MASK_DIV_ZERO)) {
586 #else
587   PetscCall(PetscInfo(NULL, "Floating point trapping unknown, assuming off\n"));
588   PetscFunctionReturn(0);
589 #endif
590 #if defined(FE_NOMASK_ENV) || defined PETSC_HAVE_XMMINTRIN_H
591     _trapmode = PETSC_FP_TRAP_ON;
592     PetscCall(PetscInfo(NULL, "Floating point trapping is on by default %d\n", flags));
593   } else {
594     _trapmode = PETSC_FP_TRAP_OFF;
595     PetscCall(PetscInfo(NULL, "Floating point trapping is off by default %d\n", flags));
596   }
597   PetscFunctionReturn(0);
598 #endif
599 }
600 
601 /* ------------------------------------------------------------*/
602 #elif defined(PETSC_HAVE_IEEEFP_H)
603 #include <ieeefp.h>
604 void PetscDefaultFPTrap(int sig) {
605   PetscFunctionBegin;
606   (*PetscErrorPrintf)("*** floating point error occurred ***\n");
607   PetscError(PETSC_COMM_SELF, 0, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_REPEAT, "floating point error");
608   PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP);
609 }
610 
611 PetscErrorCode PetscSetFPTrap(PetscFPTrap flag) {
612   PetscFunctionBegin;
613   if (flag == PETSC_FP_TRAP_ON) {
614 #if defined(PETSC_HAVE_FPPRESETSTICKY)
615     fpresetsticky(fpgetsticky());
616 #elif defined(PETSC_HAVE_FPSETSTICKY)
617     fpsetsticky(fpgetsticky());
618 #endif
619     fpsetmask(FP_X_INV | FP_X_DZ | FP_X_OFL | FP_X_OFL);
620     PetscCheck(SIG_ERR != signal(SIGFPE, PetscDefaultFPTrap), PETSC_COMM_SELF, PETSC_ERR_LIB, "Can't set floating point handler");
621   } else {
622 #if defined(PETSC_HAVE_FPPRESETSTICKY)
623     fpresetsticky(fpgetsticky());
624 #elif defined(PETSC_HAVE_FPSETSTICKY)
625     fpsetsticky(fpgetsticky());
626 #endif
627     fpsetmask(0);
628     PetscCheck(SIG_ERR != signal(SIGFPE, SIG_DFL), PETSC_COMM_SELF, PETSC_ERR_LIB, "Can't clear floating point handler");
629   }
630   _trapmode = flag;
631   PetscFunctionReturn(0);
632 }
633 
634 PetscErrorCode PetscDetermineInitialFPTrap(void) {
635   PetscFunctionBegin;
636   PetscCall(PetscInfo(NULL, "Unable to determine initial floating point trapping. Assuming it is off\n"));
637   PetscFunctionReturn(0);
638 }
639 
640 /* -------------------------Default -----------------------------------*/
641 #else
642 
643 void PetscDefaultFPTrap(int sig) {
644   PetscFunctionBegin;
645   (*PetscErrorPrintf)("*** floating point error occurred ***\n");
646   PetscError(PETSC_COMM_SELF, 0, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_REPEAT, "floating point error");
647   PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP);
648 }
649 
650 PetscErrorCode PetscSetFPTrap(PetscFPTrap flag) {
651   PetscFunctionBegin;
652   if (flag) {
653     if (SIG_ERR == signal(SIGFPE, PetscDefaultFPTrap)) (*PetscErrorPrintf)("Can't set floatingpoint handler\n");
654   } else if (SIG_ERR == signal(SIGFPE, SIG_DFL)) (*PetscErrorPrintf)("Can't clear floatingpoint handler\n");
655 
656   _trapmode = flag;
657   PetscFunctionReturn(0);
658 }
659 
660 PetscErrorCode PetscDetermineInitialFPTrap(void) {
661   PetscFunctionBegin;
662   PetscCall(PetscInfo(NULL, "Unable to determine initial floating point trapping. Assuming it is off\n"));
663   PetscFunctionReturn(0);
664 }
665 #endif
666