xref: /petsc/src/sys/error/fp.c (revision 2fa40bb9206b96114faa7cb222621ec184d31cd2)
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   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   (*PetscErrorPrintf)("likely location of problem given in stack below\n");
537   (*PetscErrorPrintf)("---------------------  Stack Frames ------------------------------------\n");
538   PetscStackView(PETSC_STDOUT);
539 #else
540   (*PetscErrorPrintf)("configure using --with-debugging=yes, recompile, link, and run \n");
541   (*PetscErrorPrintf)("with -start_in_debugger to get more information on the crash.\n");
542 #endif
543   PetscError(PETSC_COMM_SELF,0,"User provided function","Unknown file",PETSC_ERR_FP,PETSC_ERROR_INITIAL,"trapped floating point error");
544   PETSCABORT(MPI_COMM_WORLD,PETSC_ERR_FP);
545 }
546 
547 PetscErrorCode  PetscSetFPTrap(PetscFPTrap on)
548 {
549   PetscFunctionBegin;
550   if (on == PETSC_FP_TRAP_ON) {
551     /* Clear any flags that are currently set so that activating trapping will not immediately call the signal handler. */
552     if (feclearexcept(FE_ALL_EXCEPT)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Cannot clear floating point exception flags\n");
553 #if defined(FE_NOMASK_ENV)
554     /* Could use fesetenv(FE_NOMASK_ENV), but that causes spurious exceptions (like gettimeofday() -> PetscLogDouble). */
555     if (feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW) == -1) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Cannot activate floating point exceptions\n");
556 #elif defined PETSC_HAVE_XMMINTRIN_H
557    _MM_SET_EXCEPTION_MASK(_MM_GET_EXCEPTION_MASK() & ~_MM_MASK_DIV_ZERO);
558    _MM_SET_EXCEPTION_MASK(_MM_GET_EXCEPTION_MASK() & ~_MM_MASK_UNDERFLOW);
559    _MM_SET_EXCEPTION_MASK(_MM_GET_EXCEPTION_MASK() & ~_MM_MASK_OVERFLOW);
560    _MM_SET_EXCEPTION_MASK(_MM_GET_EXCEPTION_MASK() & ~_MM_MASK_INVALID);
561 #else
562     /* C99 does not provide a way to modify the environment so there is no portable way to activate trapping. */
563 #endif
564     if (SIG_ERR == signal(SIGFPE,PetscDefaultFPTrap)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Can't set floating point handler\n");
565   } else {
566     if (fesetenv(FE_DFL_ENV)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Cannot disable floating point exceptions");
567     /* can use _MM_SET_EXCEPTION_MASK(_MM_GET_EXCEPTION_MASK() | _MM_MASK_UNDERFLOW); if PETSC_HAVE_XMMINTRIN_H exists */
568     if (SIG_ERR == signal(SIGFPE,SIG_DFL)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Can't clear floating point handler\n");
569   }
570   _trapmode = on;
571   PetscFunctionReturn(0);
572 }
573 
574 PetscErrorCode  PetscDetermineInitialFPTrap(void)
575 {
576 #if defined(FE_NOMASK_ENV) || defined PETSC_HAVE_XMMINTRIN_H
577   unsigned int   flags;
578 #endif
579   PetscErrorCode ierr;
580 
581   PetscFunctionBegin;
582 #if defined(FE_NOMASK_ENV)
583   flags = fegetexcept();
584   if (flags & FE_DIVBYZERO) {
585 #elif defined PETSC_HAVE_XMMINTRIN_H
586   flags = _MM_GET_EXCEPTION_MASK();
587   if (!(flags & _MM_MASK_DIV_ZERO)) {
588 #else
589   ierr = PetscInfo(NULL,"Floating point trapping unknown, assuming off\n");CHKERRQ(ierr);
590   PetscFunctionReturn(0);
591 #endif
592 #if defined(FE_NOMASK_ENV) || defined PETSC_HAVE_XMMINTRIN_H
593     _trapmode = PETSC_FP_TRAP_ON;
594     ierr = PetscInfo1(NULL,"Floating point trapping is on by default %d\n",flags);CHKERRQ(ierr);
595   } else {
596     _trapmode = PETSC_FP_TRAP_OFF;
597     ierr = PetscInfo1(NULL,"Floating point trapping is off by default %d\n",flags);CHKERRQ(ierr);
598   }
599   PetscFunctionReturn(0);
600 #endif
601 }
602 
603 /* ------------------------------------------------------------*/
604 #elif defined(PETSC_HAVE_IEEEFP_H)
605 #include <ieeefp.h>
606 void PetscDefaultFPTrap(int sig)
607 {
608   PetscFunctionBegin;
609   (*PetscErrorPrintf)("*** floating point error occurred ***\n");
610   PetscError(PETSC_COMM_SELF,0,"User provided function","Unknown file",PETSC_ERR_FP,PETSC_ERROR_REPEAT,"floating point error");
611   PETSCABORT(MPI_COMM_WORLD,PETSC_ERR_FP);
612 }
613 
614 PetscErrorCode  PetscSetFPTrap(PetscFPTrap on)
615 {
616   PetscFunctionBegin;
617   if (on == PETSC_FP_TRAP_ON) {
618 #if defined(PETSC_HAVE_FPPRESETSTICKY)
619     fpresetsticky(fpgetsticky());
620 #elif defined(PETSC_HAVE_FPSETSTICKY)
621     fpsetsticky(fpgetsticky());
622 #endif
623     fpsetmask(FP_X_INV | FP_X_DZ | FP_X_OFL |  FP_X_OFL);
624     if (SIG_ERR == signal(SIGFPE,PetscDefaultFPTrap)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Can't set floating point handler\n");
625   } else {
626 #if defined(PETSC_HAVE_FPPRESETSTICKY)
627     fpresetsticky(fpgetsticky());
628 #elif defined(PETSC_HAVE_FPSETSTICKY)
629     fpsetsticky(fpgetsticky());
630 #endif
631     fpsetmask(0);
632     if (SIG_ERR == signal(SIGFPE,SIG_DFL)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Can't clear floating point handler\n");
633   }
634   _trapmode = on;
635   PetscFunctionReturn(0);
636 }
637 
638 PetscErrorCode  PetscDetermineInitialFPTrap(void)
639 {
640   PetscErrorCode ierr;
641 
642   PetscFunctionBegin;
643   ierr = PetscInfo(NULL,"Unable to determine initial floating point trapping. Assuming it is off\n");CHKERRQ(ierr);
644   PetscFunctionReturn(0);
645 }
646 
647 /* -------------------------Default -----------------------------------*/
648 #else
649 
650 void PetscDefaultFPTrap(int sig)
651 {
652   PetscFunctionBegin;
653   (*PetscErrorPrintf)("*** floating point error occurred ***\n");
654   PetscError(PETSC_COMM_SELF,0,"User provided function","Unknown file",PETSC_ERR_FP,PETSC_ERROR_REPEAT,"floating point error");
655   PETSCABORT(MPI_COMM_WORLD,PETSC_ERR_FP);
656 }
657 
658 PetscErrorCode  PetscSetFPTrap(PetscFPTrap on)
659 {
660   PetscFunctionBegin;
661   if (on == PETSC_FP_TRAP_ON) {
662     if (SIG_ERR == signal(SIGFPE,PetscDefaultFPTrap)) (*PetscErrorPrintf)("Can't set floatingpoint handler\n");
663   } else if (SIG_ERR == signal(SIGFPE,SIG_DFL))       (*PetscErrorPrintf)("Can't clear floatingpoint handler\n");
664 
665   _trapmode = on;
666   PetscFunctionReturn(0);
667 }
668 
669 PetscErrorCode  PetscDetermineInitialFPTrap(void)
670 {
671   PetscErrorCode ierr;
672 
673   PetscFunctionBegin;
674   ierr = PetscInfo(NULL,"Unable to determine initial floating point trapping. Assuming it is off\n");CHKERRQ(ierr);
675   PetscFunctionReturn(0);
676 }
677 #endif
678 
679