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