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