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