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