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