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