xref: /petsc/src/sys/error/fp.c (revision b33f4bec9907f62d08679bf5e7ff704a731f8c0f)
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   PetscErrorCode ierr;
379   int            err_ind,j;
380   fp_ctx_t       flt_context;
381 
382   PetscFunctionBegin;
383   fp_sh_trap_info(scp,&flt_context);
384 
385   err_ind = -1;
386   for (j = 0; error_codes[j].code_no; j++) {
387     if (error_codes[j].code_no == flt_context.trap) err_ind = j;
388   }
389 
390   if (err_ind >= 0) (*PetscErrorPrintf)("*** %s occurred ***\n",error_codes[err_ind].name);
391   else              (*PetscErrorPrintf)("*** floating point error 0x%x occurred ***\n",flt_context.trap);
392 
393   ierr = PetscError(PETSC_COMM_SELF,0,"User provided function","Unknown file",PETSC_ERR_FP,PETSC_ERROR_REPEAT,"floating point error");
394   PETSCABORT(MPI_COMM_WORLD,PETSC_ERR_FP);
395 }
396 
397 PetscErrorCode PetscSetFPTrap(PetscFPTrap on)
398 {
399   PetscFunctionBegin;
400   if (on == PETSC_FP_TRAP_ON) {
401     signal(SIGFPE,(void (*)(int))PetscDefaultFPTrap);
402     fp_trap(FP_TRAP_SYNC);
403     fp_enable(TRP_INVALID | TRP_DIV_BY_ZERO | TRP_OVERFLOW | TRP_UNDERFLOW);
404     /* fp_enable(mask) for individual traps.  Values are:
405        TRP_INVALID
406        TRP_DIV_BY_ZERO
407        TRP_OVERFLOW
408        TRP_UNDERFLOW
409        TRP_INEXACT
410        Can OR then together.
411        fp_enable_all(); for all traps.
412     */
413   } else {
414     signal(SIGFPE,SIG_DFL);
415     fp_disable(TRP_INVALID | TRP_DIV_BY_ZERO | TRP_OVERFLOW | TRP_UNDERFLOW);
416     fp_trap(FP_TRAP_OFF);
417   }
418   _trapmode = on;
419   PetscFunctionReturn(0);
420 }
421 
422 PetscErrorCode  PetscDetermineInitialFPTrap(void)
423 {
424   PetscFunctionBegin;
425   PetscCall(PetscInfo(NULL,"Unable to determine initial floating point trapping. Assuming it is off\n"));
426   PetscFunctionReturn(0);
427 }
428 
429 /* ------------------------------------------------------------*/
430 #elif defined(PETSC_HAVE_WINDOWS_COMPILERS)
431 #include <float.h>
432 void PetscDefaultFPTrap(int sig)
433 {
434   PetscFunctionBegin;
435   (*PetscErrorPrintf)("*** floating point error occurred ***\n");
436   PetscError(PETSC_COMM_SELF,0,"User provided function","Unknown file",PETSC_ERR_FP,PETSC_ERROR_REPEAT,"floating point error");
437   PETSCABORT(MPI_COMM_WORLD,PETSC_ERR_FP);
438 }
439 
440 PetscErrorCode  PetscSetFPTrap(PetscFPTrap on)
441 {
442   unsigned int cw;
443 
444   PetscFunctionBegin;
445   if (on == PETSC_FP_TRAP_ON) {
446     cw = _EM_INVALID | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW;
447     PetscCheck(SIG_ERR != signal(SIGFPE,PetscDefaultFPTrap),PETSC_COMM_SELF,PETSC_ERR_LIB,"Can't set floating point handler");
448   } else {
449     cw = 0;
450     PetscCheck(SIG_ERR != signal(SIGFPE,SIG_DFL),PETSC_COMM_SELF,PETSC_ERR_LIB,"Can't clear floating point handler");
451   }
452   (void)_controlfp(0, cw);
453   _trapmode = on;
454   PetscFunctionReturn(0);
455 }
456 
457 PetscErrorCode  PetscDetermineInitialFPTrap(void)
458 {
459   PetscFunctionBegin;
460   PetscCall(PetscInfo(NULL,"Unable to determine initial floating point trapping. Assuming it is off\n"));
461   PetscFunctionReturn(0);
462 }
463 
464 /* ------------------------------------------------------------*/
465 #elif defined(PETSC_HAVE_FENV_H) && !defined(__cplusplus)
466 /*
467    C99 style floating point environment.
468 
469    Note that C99 merely specifies how to save, restore, and clear the floating
470    point environment as well as defining an enumeration of exception codes.  In
471    particular, C99 does not specify how to make floating point exceptions raise
472    a signal.  Glibc offers this capability through FE_NOMASK_ENV (or with finer
473    granularity, feenableexcept()), xmmintrin.h offers _MM_SET_EXCEPTION_MASK().
474 */
475 #include <fenv.h>
476 typedef struct {int code; const char *name;} FPNode;
477 static const FPNode error_codes[] = {
478   {FE_DIVBYZERO,"divide by zero"},
479   {FE_INEXACT,  "inexact floating point result"},
480   {FE_INVALID,  "invalid floating point arguments (domain error)"},
481   {FE_OVERFLOW, "floating point overflow"},
482   {FE_UNDERFLOW,"floating point underflow"},
483   {0           ,"unknown error"}
484 };
485 
486 void PetscDefaultFPTrap(int sig)
487 {
488   const FPNode *node;
489   int          code;
490   PetscBool    matched = PETSC_FALSE;
491 
492   PetscFunctionBegin;
493   /* Note: While it is possible for the exception state to be preserved by the
494    * kernel, this seems to be rare which makes the following flag testing almost
495    * useless.  But on a system where the flags can be preserved, it would provide
496    * more detail.
497    */
498   code = fetestexcept(FE_ALL_EXCEPT);
499   for (node=&error_codes[0]; node->code; node++) {
500     if (code & node->code) {
501       matched = PETSC_TRUE;
502       (*PetscErrorPrintf)("*** floating point error \"%s\" occurred ***\n",node->name);
503       code &= ~node->code; /* Unset this flag since it has been processed */
504     }
505   }
506   if (!matched || code) { /* If any remaining flags are set, or we didn't process any flags */
507     (*PetscErrorPrintf)("*** unknown floating point error occurred ***\n");
508     (*PetscErrorPrintf)("The specific exception can be determined by running in a debugger.  When the\n");
509     (*PetscErrorPrintf)("debugger traps the signal, the exception can be found with fetestexcept(0x%x)\n",FE_ALL_EXCEPT);
510     (*PetscErrorPrintf)("where the result is a bitwise OR of the following flags:\n");
511     (*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);
512   }
513 
514   (*PetscErrorPrintf)("Try option -start_in_debugger\n");
515 #if PetscDefined(USE_DEBUG)
516   (*PetscErrorPrintf)("likely location of problem given in stack below\n");
517   (*PetscErrorPrintf)("---------------------  Stack Frames ------------------------------------\n");
518   PetscStackView(PETSC_STDOUT);
519 #else
520   (*PetscErrorPrintf)("configure using --with-debugging=yes, recompile, link, and run \n");
521   (*PetscErrorPrintf)("with -start_in_debugger to get more information on the crash.\n");
522 #endif
523   PetscError(PETSC_COMM_SELF,0,"User provided function","Unknown file",PETSC_ERR_FP,PETSC_ERROR_INITIAL,"trapped floating point error");
524   PETSCABORT(MPI_COMM_WORLD,PETSC_ERR_FP);
525 }
526 
527 PetscErrorCode  PetscSetFPTrap(PetscFPTrap on)
528 {
529   PetscFunctionBegin;
530   if (on == PETSC_FP_TRAP_ON) {
531     /* Clear any flags that are currently set so that activating trapping will not immediately call the signal handler. */
532     PetscCheckFalse(feclearexcept(FE_ALL_EXCEPT),PETSC_COMM_SELF,PETSC_ERR_LIB,"Cannot clear floating point exception flags");
533 #if defined(FE_NOMASK_ENV)
534     /* Could use fesetenv(FE_NOMASK_ENV), but that causes spurious exceptions (like gettimeofday() -> PetscLogDouble). */
535     PetscCheck(feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW) != -1,PETSC_COMM_SELF,PETSC_ERR_LIB,"Cannot activate floating point exceptions");
536 #elif defined PETSC_HAVE_XMMINTRIN_H
537    _MM_SET_EXCEPTION_MASK(_MM_GET_EXCEPTION_MASK() & ~_MM_MASK_DIV_ZERO);
538    _MM_SET_EXCEPTION_MASK(_MM_GET_EXCEPTION_MASK() & ~_MM_MASK_UNDERFLOW);
539    _MM_SET_EXCEPTION_MASK(_MM_GET_EXCEPTION_MASK() & ~_MM_MASK_OVERFLOW);
540    _MM_SET_EXCEPTION_MASK(_MM_GET_EXCEPTION_MASK() & ~_MM_MASK_INVALID);
541 #else
542     /* C99 does not provide a way to modify the environment so there is no portable way to activate trapping. */
543 #endif
544     PetscCheck(SIG_ERR != signal(SIGFPE,PetscDefaultFPTrap),PETSC_COMM_SELF,PETSC_ERR_LIB,"Can't set floating point handler");
545   } else {
546     PetscCheckFalse(fesetenv(FE_DFL_ENV),PETSC_COMM_SELF,PETSC_ERR_LIB,"Cannot disable floating point exceptions");
547     /* can use _MM_SET_EXCEPTION_MASK(_MM_GET_EXCEPTION_MASK() | _MM_MASK_UNDERFLOW); if PETSC_HAVE_XMMINTRIN_H exists */
548     PetscCheck(SIG_ERR != signal(SIGFPE,SIG_DFL),PETSC_COMM_SELF,PETSC_ERR_LIB,"Can't clear floating point handler");
549   }
550   _trapmode = on;
551   PetscFunctionReturn(0);
552 }
553 
554 PetscErrorCode  PetscDetermineInitialFPTrap(void)
555 {
556 #if defined(FE_NOMASK_ENV) || defined PETSC_HAVE_XMMINTRIN_H
557   unsigned int flags;
558 #endif
559 
560   PetscFunctionBegin;
561 #if defined(FE_NOMASK_ENV)
562   flags = fegetexcept();
563   if (flags & FE_DIVBYZERO) {
564 #elif defined PETSC_HAVE_XMMINTRIN_H
565   flags = _MM_GET_EXCEPTION_MASK();
566   if (!(flags & _MM_MASK_DIV_ZERO)) {
567 #else
568   PetscCall(PetscInfo(NULL,"Floating point trapping unknown, assuming off\n"));
569   PetscFunctionReturn(0);
570 #endif
571 #if defined(FE_NOMASK_ENV) || defined PETSC_HAVE_XMMINTRIN_H
572     _trapmode = PETSC_FP_TRAP_ON;
573     PetscCall(PetscInfo(NULL,"Floating point trapping is on by default %d\n",flags));
574   } else {
575     _trapmode = PETSC_FP_TRAP_OFF;
576     PetscCall(PetscInfo(NULL,"Floating point trapping is off by default %d\n",flags));
577   }
578   PetscFunctionReturn(0);
579 #endif
580 }
581 
582 /* ------------------------------------------------------------*/
583 #elif defined(PETSC_HAVE_IEEEFP_H)
584 #include <ieeefp.h>
585 void PetscDefaultFPTrap(int sig)
586 {
587   PetscFunctionBegin;
588   (*PetscErrorPrintf)("*** floating point error occurred ***\n");
589   PetscError(PETSC_COMM_SELF,0,"User provided function","Unknown file",PETSC_ERR_FP,PETSC_ERROR_REPEAT,"floating point error");
590   PETSCABORT(MPI_COMM_WORLD,PETSC_ERR_FP);
591 }
592 
593 PetscErrorCode  PetscSetFPTrap(PetscFPTrap on)
594 {
595   PetscFunctionBegin;
596   if (on == PETSC_FP_TRAP_ON) {
597 #if defined(PETSC_HAVE_FPPRESETSTICKY)
598     fpresetsticky(fpgetsticky());
599 #elif defined(PETSC_HAVE_FPSETSTICKY)
600     fpsetsticky(fpgetsticky());
601 #endif
602     fpsetmask(FP_X_INV | FP_X_DZ | FP_X_OFL |  FP_X_OFL);
603     PetscCheck(SIG_ERR != signal(SIGFPE,PetscDefaultFPTrap),PETSC_COMM_SELF,PETSC_ERR_LIB,"Can't set floating point handler");
604   } else {
605 #if defined(PETSC_HAVE_FPPRESETSTICKY)
606     fpresetsticky(fpgetsticky());
607 #elif defined(PETSC_HAVE_FPSETSTICKY)
608     fpsetsticky(fpgetsticky());
609 #endif
610     fpsetmask(0);
611     PetscCheck(SIG_ERR != signal(SIGFPE,SIG_DFL),PETSC_COMM_SELF,PETSC_ERR_LIB,"Can't clear floating point handler");
612   }
613   _trapmode = on;
614   PetscFunctionReturn(0);
615 }
616 
617 PetscErrorCode  PetscDetermineInitialFPTrap(void)
618 {
619   PetscFunctionBegin;
620   PetscCall(PetscInfo(NULL,"Unable to determine initial floating point trapping. Assuming it is off\n"));
621   PetscFunctionReturn(0);
622 }
623 
624 /* -------------------------Default -----------------------------------*/
625 #else
626 
627 void PetscDefaultFPTrap(int sig)
628 {
629   PetscFunctionBegin;
630   (*PetscErrorPrintf)("*** floating point error occurred ***\n");
631   PetscError(PETSC_COMM_SELF,0,"User provided function","Unknown file",PETSC_ERR_FP,PETSC_ERROR_REPEAT,"floating point error");
632   PETSCABORT(MPI_COMM_WORLD,PETSC_ERR_FP);
633 }
634 
635 PetscErrorCode  PetscSetFPTrap(PetscFPTrap on)
636 {
637   PetscFunctionBegin;
638   if (on == PETSC_FP_TRAP_ON) {
639     if (SIG_ERR == signal(SIGFPE,PetscDefaultFPTrap)) (*PetscErrorPrintf)("Can't set floatingpoint handler\n");
640   } else if (SIG_ERR == signal(SIGFPE,SIG_DFL))       (*PetscErrorPrintf)("Can't clear floatingpoint handler\n");
641 
642   _trapmode = on;
643   PetscFunctionReturn(0);
644 }
645 
646 PetscErrorCode  PetscDetermineInitialFPTrap(void)
647 {
648   PetscFunctionBegin;
649   PetscCall(PetscInfo(NULL,"Unable to determine initial floating point trapping. Assuming it is off\n"));
650   PetscFunctionReturn(0);
651 }
652 #endif
653