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