Actual source code: fp.c


  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: */

  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

 18: #include <petsc/private/petscimpl.h>
 19: #include <signal.h>

 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 */

 28: /*@
 29:    PetscFPTrapPush - push a floating point trapping mode, restored using `PetscFPTrapPop()`

 31:    Not Collective

 33:    Input Parameter:
 34: .    trap - `PETSC_FP_TRAP_ON` or `PETSC_FP_TRAP_OFF` or any of the values passable to `PetscSetFPTrap()`

 36:    Level: advanced

 38:    Notes:
 39:      This only changes the trapping if the new mode is different than the current mode.

 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().

 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

 49: .seealso: `PetscFPTrapPop()`, `PetscSetFPTrap()`, `PetscDetermineInitialFPTrap()`
 50: @*/
 51: PetscErrorCode PetscFPTrapPush(PetscFPTrap trap)
 52: {
 53:   struct PetscFPTrapLink *link;

 55:   PetscFunctionBegin;
 56:   PetscCall(PetscNew(&link));
 57: #if defined(PETSC_HAVE_THREADSAFETY) && defined(PETSC_HAVE_OPENMP)
 58:   PetscPragmaOMP(critical)
 59: #endif
 60:   {
 61:     link->trapmode = _trapmode;
 62:     link->next     = _trapstack;
 63:     _trapstack     = link;
 64:   }
 65:   if (trap != _trapmode) PetscCall(PetscSetFPTrap(trap));
 66:   PetscFunctionReturn(PETSC_SUCCESS);
 67: }

 69: /*@
 70:    PetscFPTrapPop - push a floating point trapping mode, to be restored using `PetscFPTrapPop()`

 72:    Not Collective

 74:    Level: advanced

 76: .seealso: `PetscFPTrapPush()`, `PetscSetFPTrap()`, `PetscDetermineInitialFPTrap()`
 77: @*/
 78: PetscErrorCode PetscFPTrapPop(void)
 79: {
 80:   struct PetscFPTrapLink *link;

 82:   PetscFunctionBegin;
 83:   if (_trapstack->trapmode != _trapmode) PetscCall(PetscSetFPTrap(_trapstack->trapmode));
 84: #if defined(PETSC_HAVE_THREADSAFETY) && defined(PETSC_HAVE_OPENMP)
 85:   PetscPragmaOMP(critical)
 86: #endif
 87:   {
 88:     link       = _trapstack;
 89:     _trapstack = _trapstack->next;
 90:   }
 91:   PetscCall(PetscFree(link));
 92:   PetscFunctionReturn(PETSC_SUCCESS);
 93: }

 95: /*--------------------------------------- ---------------------------------------------------*/
 96: #if defined(PETSC_HAVE_SUN4_STYLE_FPTRAP)
 97:   #include <floatingpoint.h>

 99: PETSC_EXTERN PetscErrorCode ieee_flags(char *, char *, char *, char **);
100: PETSC_EXTERN PetscErrorCode ieee_handler(char *, char *, sigfpe_handler_type(int, int, struct sigcontext *, char *));

102: static struct {
103:   int   code_no;
104:   char *name;
105: } error_codes[] = {
106:   {FPE_INTDIV_TRAP,   "integer divide"               },
107:   {FPE_FLTOPERR_TRAP, "IEEE operand error"           },
108:   {FPE_FLTOVF_TRAP,   "floating point overflow"      },
109:   {FPE_FLTUND_TRAP,   "floating point underflow"     },
110:   {FPE_FLTDIV_TRAP,   "floating pointing divide"     },
111:   {FPE_FLTINEX_TRAP,  "inexact floating point result"},
112:   {0,                 "unknown error"                }
113: };
114:   #define SIGPC(scp) (scp->sc_pc)

116: /* this function gets called if a trap has occurred and been caught */
117: sigfpe_handler_type PetscDefaultFPTrap(int sig, int code, struct sigcontext *scp, char *addr)
118: {
119:   int            err_ind = -1;
120:   PetscErrorCode ierr;

122:   PetscFunctionBegin;
123:   for (int j = 0; error_codes[j].code_no; j++) {
124:     if (error_codes[j].code_no == code) err_ind = j;
125:   }

127:   if (err_ind >= 0) ierr = (*PetscErrorPrintf)("*** %s occurred at pc=%X ***\n", error_codes[err_ind].name, SIGPC(scp));
128:   else ierr = (*PetscErrorPrintf)("*** floating point error 0x%x occurred at pc=%X ***\n", code, SIGPC(scp));

130:   ierr = PetscError(PETSC_COMM_SELF, PETSC_ERR_FP, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_REPEAT, "floating point error");
131:   (void)ierr;
132:   PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP);
133:   PetscFunctionReturn(PETSC_SUCCESS);
134: }

136: /*@
137:    PetscSetFPTrap - Enables traps/exceptions on common floating point errors. This option may not work on certain systems or only a
138:    subset of exceptions may be trapable.

140:    Not Collective

142:    Input Parameter:
143: .  flag - values are
144: .vb
145:     PETSC_FP_TRAP_OFF   - do not trap any exceptions
146:     PETSC_FP_TRAP_ON - all exceptions that are possible on the system except underflow
147:     PETSC_FP_TRAP_INDIV - integer divide by zero
148:     PETSC_FP_TRAP_FLTOPERR - improper argument to function, for example with real numbers, the square root of a negative number
149:     PETSC_FP_TRAP_FLTOVF - overflow
150:     PETSC_FP_TRAP_FLTUND - underflow - not trapped by default on most systems
151:     PETSC_FP_TRAP_FLTDIV - floating point divide by zero
152:     PETSC_FP_TRAP_FLTINEX - inexact floating point result
153: .ve

155:    Options Database Key:
156: .  -fp_trap <off,on> - turn on or off trapping of floating point exceptions

158:    Level: advanced

160:    Notes:
161:    Currently only `PETSC_FP_TRAP_OFF` and `PETSC_FP_TRAP_ON` are handled. All others are treated as `PETSC_FP_TRAP_ON`.

163:    The values are bit values and may be |ed together in the function call

165:    On systems that support it this routine causes floating point
166:    overflow, divide-by-zero, and invalid-operand (e.g., a NaN), but not underflow, to
167:    cause a message to be printed and the program to exit.

169:    On many common systems, the floating
170:    point exception state is not preserved from the location where the trap
171:    occurred through to the signal handler.  In this case, the signal handler
172:    will just say that an unknown floating point exception occurred and which
173:    function it occurred in.  If you run with -fp_trap in a debugger, it will
174:    break on the line where the error occurred.  On systems that support C99
175:    floating point exception handling You can check which
176:    exception occurred using fetestexcept(FE_ALL_EXCEPT).  See fenv.h
177:    (usually at /usr/include/bits/fenv.h) for the enum values on your system.

179: .seealso: `PetscFPTrapPush()`, `PetscFPTrapPop()`, `PetscDetermineInitialFPTrap()`
180: @*/
181: PetscErrorCode PetscSetFPTrap(PetscFPTrap flag)
182: {
183:   char *out;

185:   PetscFunctionBegin;
186:   /* Clear accumulated exceptions.  Used to suppress meaningless messages from f77 programs */
187:   (void)ieee_flags("clear", "exception", "all", &out);
188:   if (flag == PETSC_FP_TRAP_ON) {
189:     /*
190:       To trap more fp exceptions, including underflow, change the line below to
191:       if (ieee_handler("set","all",PetscDefaultFPTrap)) {
192:     */
193:     if (ieee_handler("set", "common", PetscDefaultFPTrap)) (*PetscErrorPrintf)("Can't set floatingpoint handler\n");
194:   } else if (ieee_handler("clear", "common", PetscDefaultFPTrap)) (*PetscErrorPrintf)("Can't clear floatingpoint handler\n");

196:   _trapmode = flag;
197:   PetscCall(PetscInfo(NULL, "Using PETSC_HAVE_SUN4_STYLE_FPTRAP\n"));
198:   PetscFunctionReturn(PETSC_SUCCESS);
199: }

201: /*@
202:    PetscDetermineInitialFPTrap - Attempts to determine the floating point trapping that exists when `PetscInitialize()` is called

204:    Not Collective

206:    Note:
207:       Currently only supported on Linux and MacOS. Checks if divide by zero is enable and if so declares that trapping is on.

209:    Level: advanced

211: .seealso: `PetscFPTrapPush()`, `PetscFPTrapPop()`, `PetscDetermineInitialFPTrap()`
212: @*/
213: PetscErrorCode PetscDetermineInitialFPTrap(void)
214: {
215:   PetscFunctionBegin;
216:   PetscCall(PetscInfo(NULL, "Unable to determine initial floating point trapping. Assuming it is off\n"));
217:   PetscFunctionReturn(PETSC_SUCCESS);
218: }

220: /* -------------------------------------------------------------------------------------------*/
221: #elif defined(PETSC_HAVE_SOLARIS_STYLE_FPTRAP)
222:   #include <sunmath.h>
223:   #include <floatingpoint.h>
224:   #include <siginfo.h>
225:   #include <ucontext.h>

227: static struct {
228:   int   code_no;
229:   char *name;
230: } error_codes[] = {
231:   {FPE_FLTINV, "invalid floating point operand"},
232:   {FPE_FLTRES, "inexact floating point result" },
233:   {FPE_FLTDIV, "division-by-zero"              },
234:   {FPE_FLTUND, "floating point underflow"      },
235:   {FPE_FLTOVF, "floating point overflow"       },
236:   {0,          "unknown error"                 }
237: };
238:   #define SIGPC(scp) (scp->si_addr)

240: void PetscDefaultFPTrap(int sig, siginfo_t *scp, ucontext_t *uap)
241: {
242:   int            err_ind = -1, code = scp->si_code;
243:   PetscErrorCode ierr;

245:   PetscFunctionBegin;
246:   for (int j = 0; error_codes[j].code_no; j++) {
247:     if (error_codes[j].code_no == code) err_ind = j;
248:   }

250:   if (err_ind >= 0) ierr = (*PetscErrorPrintf)("*** %s occurred at pc=%X ***\n", error_codes[err_ind].name, SIGPC(scp));
251:   else ierr = (*PetscErrorPrintf)("*** floating point error 0x%x occurred at pc=%X ***\n", code, SIGPC(scp));

253:   ierr = PetscError(PETSC_COMM_SELF, 0, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_REPEAT, "floating point error");
254:   (void)ierr;
255:   PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP);
256: }

258: PetscErrorCode PetscSetFPTrap(PetscFPTrap flag)
259: {
260:   char *out;

262:   PetscFunctionBegin;
263:   /* Clear accumulated exceptions.  Used to suppress meaningless messages from f77 programs */
264:   (void)ieee_flags("clear", "exception", "all", &out);
265:   if (flag == PETSC_FP_TRAP_ON) {
266:     if (ieee_handler("set", "common", (sigfpe_handler_type)PetscDefaultFPTrap)) (*PetscErrorPrintf)("Can't set floating point handler\n");
267:   } else {
268:     if (ieee_handler("clear", "common", (sigfpe_handler_type)PetscDefaultFPTrap)) (*PetscErrorPrintf)("Can't clear floatingpoint handler\n");
269:   }
270:   _trapmode = flag;
271:   PetscCall(PetscInfo(NULL,"Using PETSC_HAVE_SOLARIS_STYLE_FPTRAP\n");
272:   PetscFunctionReturn(PETSC_SUCCESS);
273: }

275: PetscErrorCode PetscDetermineInitialFPTrap(void)
276: {
277:   PetscFunctionBegin;
278:   PetscCall(PetscInfo(NULL, "Unable to determine initial floating point trapping. Assuming it is off\n"));
279:   PetscFunctionReturn(PETSC_SUCCESS);
280: }

282: /* ------------------------------------------------------------------------------------------*/
283: #elif defined(PETSC_HAVE_IRIX_STYLE_FPTRAP)
284:   #include <sigfpe.h>
285: static struct {
286:   int   code_no;
287:   char *name;
288: } error_codes[] = {
289:   {_INVALID, "IEEE operand error"      },
290:   {_OVERFL,  "floating point overflow" },
291:   {_UNDERFL, "floating point underflow"},
292:   {_DIVZERO, "floating point divide"   },
293:   {0,        "unknown error"           }
294: };
295: void PetscDefaultFPTrap(unsigned exception[], int val[])
296: {
297:   int            err_ind = -1, code = exception[0];
298:   PetscErrorCode ierr;

300:   PetscFunctionBegin;
301:   for (int j = 0; error_codes[j].code_no; j++) {
302:     if (error_codes[j].code_no == code) err_ind = j;
303:   }
304:   if (err_ind >= 0) ierr = (*PetscErrorPrintf)("*** %s occurred ***\n", error_codes[err_ind].name);
305:   else ierr = (*PetscErrorPrintf)("*** floating point error 0x%x occurred ***\n", code);

307:   ierr = PetscError(PETSC_COMM_SELF, 0, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_REPEAT, "floating point error");
308:   (void)ierr;
309:   PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP);
310: }

312: PetscErrorCode PetscSetFPTrap(PetscFPTrap flag)
313: {
314:   PetscFunctionBegin;
315:   if (flag == PETSC_FP_TRAP_ON) handle_sigfpes(_ON, , _EN_UNDERFL | _EN_OVERFL | _EN_DIVZERO | _EN_INVALID, PetscDefaultFPTrap, _ABORT_ON_ERROR, 0);
316:   else handle_sigfpes(_OFF, _EN_UNDERFL | _EN_OVERFL | _EN_DIVZERO | _EN_INVALID, 0, _ABORT_ON_ERROR, 0);
317:   _trapmode = flag;
318:   PetscCall(PetscInfo(NULL, "Using PETSC_HAVE_IRIX_STYLE_FPTRAP\n"));
319:   PetscFunctionReturn(PETSC_SUCCESS);
320: }

322: PetscErrorCode PetscDetermineInitialFPTrap(void)
323: {
324:   PetscFunctionBegin;
325:   PetscCall(PetscInfo(NULL, "Unable to determine initial floating point trapping. Assuming it is off\n"));
326:   PetscFunctionReturn(PETSC_SUCCESS);
327: }

329: /*----------------------------------------------- --------------------------------------------*/
330: #elif defined(PETSC_HAVE_RS6000_STYLE_FPTRAP)
331: /* In "fast" mode, floating point traps are imprecise and ignored.
332:    This is the reason for the fptrap(FP_TRAP_SYNC) call */
333: struct sigcontext;
334:   #include <fpxcp.h>
335:   #include <fptrap.h>
336:   #define FPE_FLTOPERR_TRAP (fptrap_t)(0x20000000)
337:   #define FPE_FLTOVF_TRAP   (fptrap_t)(0x10000000)
338:   #define FPE_FLTUND_TRAP   (fptrap_t)(0x08000000)
339:   #define FPE_FLTDIV_TRAP   (fptrap_t)(0x04000000)
340:   #define FPE_FLTINEX_TRAP  (fptrap_t)(0x02000000)

342: static struct {
343:   int   code_no;
344:   char *name;
345: } error_codes[] = {
346:   {FPE_FLTOPERR_TRAP, "IEEE operand error"           },
347:   {FPE_FLTOVF_TRAP,   "floating point overflow"      },
348:   {FPE_FLTUND_TRAP,   "floating point underflow"     },
349:   {FPE_FLTDIV_TRAP,   "floating point divide"        },
350:   {FPE_FLTINEX_TRAP,  "inexact floating point result"},
351:   < {0,                 "unknown error"                }
352: };
353:   #define SIGPC(scp)        (0) /* Info MIGHT be in scp->sc_jmpbuf.jmp_context.iar */
354: /*
355:    For some reason, scp->sc_jmpbuf does not work on the RS6000, even though
356:    it looks like it should from the include definitions.  It is probably
357:    some strange interaction with the "POSIX_SOURCE" that we require.
358: */

360: void PetscDefaultFPTrap(int sig, int code, struct sigcontext *scp)
361: {
362:   int            err_ind, j;
363:   fp_ctx_t       flt_context;
364:   PetscErrorCode ierr;

366:   PetscFunctionBegin;
367:   fp_sh_trap_info(scp, &flt_context);

369:   err_ind = -1;
370:   for (j = 0; error_codes[j].code_no; j++) {
371:     if (error_codes[j].code_no == flt_context.trap) err_ind = j;
372:   }

374:   if (err_ind >= 0) ierr = (*PetscErrorPrintf)("*** %s occurred ***\n", error_codes[err_ind].name);
375:   else ierr = (*PetscErrorPrintf)("*** floating point error 0x%x occurred ***\n", flt_context.trap);

377:   ierr = PetscError(PETSC_COMM_SELF, 0, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_REPEAT, "floating point error");
378:   (void)ierr;
379:   PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP);
380: }

382: PetscErrorCode PetscSetFPTrap(PetscFPTrap flag)
383: {
384:   PetscFunctionBegin;
385:   if (flag == PETSC_FP_TRAP_ON) {
386:     signal(SIGFPE, (void (*)(int))PetscDefaultFPTrap);
387:     fp_trap(FP_TRAP_SYNC);
388:     /* fp_enable(TRP_INVALID | TRP_DIV_BY_ZERO | TRP_OVERFLOW | TRP_UNDERFLOW); */
389:     fp_enable(TRP_INVALID | TRP_DIV_BY_ZERO | TRP_OVERFLOW);
390:   } else {
391:     signal(SIGFPE, SIG_DFL);
392:     fp_disable(TRP_INVALID | TRP_DIV_BY_ZERO | TRP_OVERFLOW | TRP_UNDERFLOW);
393:     fp_trap(FP_TRAP_OFF);
394:   }
395:   _trapmode = flag;
396:   PetscCall(PetscInfo(NULL, "Using PETSC_HAVE_RS6000_STYLE_FPTRAP\n"));
397:   PetscFunctionReturn(PETSC_SUCCESS);
398: }

400: PetscErrorCode PetscDetermineInitialFPTrap(void)
401: {
402:   PetscFunctionBegin;
403:   PetscCall(PetscInfo(NULL, "Unable to determine initial floating point trapping. Assuming it is off\n"));
404:   PetscFunctionReturn(PETSC_SUCCESS);
405: }

407: /* ------------------------------------------------------------*/
408: #elif defined(PETSC_HAVE_WINDOWS_COMPILERS)
409:   #include <float.h>
410: void PetscDefaultFPTrap(int sig)
411: {
412:   PetscErrorCode ierr;

414:   PetscFunctionBegin;
415:   ierr = (*PetscErrorPrintf)("*** floating point error occurred ***\n");
416:   ierr = PetscError(PETSC_COMM_SELF, 0, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_REPEAT, "floating point error");
417:   (void)ierr;
418:   PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP);
419: }

421: PetscErrorCode PetscSetFPTrap(PetscFPTrap flag)
422: {
423:   unsigned int cw;

425:   PetscFunctionBegin;
426:   if (flag == PETSC_FP_TRAP_ON) {
427:     /* cw = _EM_INVALID | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW; */
428:     cw = _EM_INVALID | _EM_ZERODIVIDE | _EM_OVERFLOW;
429:     PetscCheck(SIG_ERR != signal(SIGFPE, PetscDefaultFPTrap), PETSC_COMM_SELF, PETSC_ERR_LIB, "Can't set floating point handler");
430:   } else {
431:     cw = 0;
432:     PetscCheck(SIG_ERR != signal(SIGFPE, SIG_DFL), PETSC_COMM_SELF, PETSC_ERR_LIB, "Can't clear floating point handler");
433:   }
434:   (void)_controlfp(0, cw);
435:   _trapmode = flag;
436:   PetscCall(PetscInfo(NULL, "Using PETSC_HAVE_WINDOWS_COMPILERS FPTRAP\n"));
437:   PetscFunctionReturn(PETSC_SUCCESS);
438: }

440: PetscErrorCode PetscDetermineInitialFPTrap(void)
441: {
442:   PetscFunctionBegin;
443:   PetscCall(PetscInfo(NULL, "Unable to determine initial floating point trapping. Assuming it is off\n"));
444:   PetscFunctionReturn(PETSC_SUCCESS);
445: }

447: /* ------------------------------------------------------------*/
448: #elif defined(PETSC_HAVE_FENV_H) && !defined(__cplusplus)
449:   /*
450:    C99 style floating point environment.

452:    Note that C99 merely specifies how to save, restore, and clear the floating
453:    point environment as well as defining an enumeration of exception codes.  In
454:    particular, C99 does not specify how to make floating point exceptions raise
455:    a signal.  Glibc offers this capability through FE_NOMASK_ENV (or with finer
456:    granularity, feenableexcept()), xmmintrin.h offers _MM_SET_EXCEPTION_MASK().
457: */
458:   #include <fenv.h>
459:   #if defined(PETSC_HAVE_FE_VALUES)
460: typedef struct {
461:   int         code;
462:   const char *name;
463: } FPNode;
464: static const FPNode error_codes[] = {
465:   {FE_DIVBYZERO, "divide by zero"                                 },
466:   {FE_INEXACT,   "inexact floating point result"                  },
467:   {FE_INVALID,   "invalid floating point arguments (domain error)"},
468:   {FE_OVERFLOW,  "floating point overflow"                        },
469:   {FE_UNDERFLOW, "floating point underflow"                       },
470:   {0,            "unknown error"                                  }
471: };
472:   #endif

474: void PetscDefaultFPTrap(int sig)
475: {
476:   #if defined(PETSC_HAVE_FE_VALUES)
477:   const FPNode  *node;
478:   int            code;
479:   PetscBool      matched = PETSC_FALSE;
480:   #endif
481:   PetscErrorCode ierr;

483:   PetscFunctionBegin;
484:   /* Note: While it is possible for the exception state to be preserved by the
485:    * kernel, this seems to be rare which makes the following flag testing almost
486:    * useless.  But on a system where the flags can be preserved, it would provide
487:    * more detail.
488:    */
489:   #if defined(PETSC_HAVE_FE_VALUES)
490:   code = fetestexcept(FE_ALL_EXCEPT);
491:   for (node = &error_codes[0]; node->code; node++) {
492:     if (code & node->code) {
493:       matched = PETSC_TRUE;
494:       ierr    = (*PetscErrorPrintf)("*** floating point error \"%s\" occurred ***\n", node->name);
495:       code &= ~node->code; /* Unset this flag since it has been processed */
496:     }
497:   }
498:   if (!matched || code) { /* If any remaining flags are set, or we didn't process any flags */
499:     ierr = (*PetscErrorPrintf)("*** unknown floating point error occurred ***\n");
500:     ierr = (*PetscErrorPrintf)("The specific exception can be determined by running in a debugger.  When the\n");
501:     ierr = (*PetscErrorPrintf)("debugger traps the signal, the exception can be found with fetestexcept(0x%x)\n", FE_ALL_EXCEPT);
502:     ierr = (*PetscErrorPrintf)("where the result is a bitwise OR of the following flags:\n");
503:     ierr = (*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);
504:   }
505:   #else
506:   ierr = (*PetscErrorPrintf)("*** unknown floating point error occurred ***\n");
507:   #endif

509:   ierr = (*PetscErrorPrintf)("Try option -start_in_debugger\n");
510:   #if PetscDefined(USE_DEBUG)
511:     #if !PetscDefined(HAVE_THREADSAFETY)
512:   ierr = (*PetscErrorPrintf)("likely location of problem given in stack below\n");
513:   ierr = (*PetscErrorPrintf)("---------------------  Stack Frames ------------------------------------\n");
514:   ierr = PetscStackView(PETSC_STDOUT);
515:     #endif
516:   #else
517:   ierr = (*PetscErrorPrintf)("configure using --with-debugging=yes, recompile, link, and run \n");
518:   ierr = (*PetscErrorPrintf)("with -start_in_debugger to get more information on the crash.\n");
519:   #endif
520:   ierr = PetscError(PETSC_COMM_SELF, 0, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_INITIAL, "trapped floating point error");
521:   (void)ierr;
522:   PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP);
523: }

525: PetscErrorCode PetscSetFPTrap(PetscFPTrap flag)
526: {
527:   PetscFunctionBegin;
528:   if (flag == PETSC_FP_TRAP_ON) {
529:     /* Clear any flags that are currently set so that activating trapping will not immediately call the signal handler. */
530:     PetscCheck(!feclearexcept(FE_ALL_EXCEPT), PETSC_COMM_SELF, PETSC_ERR_LIB, "Cannot clear floating point exception flags");
531:   #if defined(FE_NOMASK_ENV) && defined(PETSC_HAVE_FE_VALUES)
532:     /* Could use fesetenv(FE_NOMASK_ENV), but that causes spurious exceptions (like gettimeofday() -> PetscLogDouble). */
533:     /* PetscCheck(feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW) != -1,PETSC_COMM_SELF,PETSC_ERR_LIB,"Cannot activate floating point exceptions"); */
534:     /* Doesn't work on AArch64 targets. There's a known hardware limitation. Need to detect hardware at configure time? */
535:     PetscCheck(feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW) != -1, PETSC_COMM_SELF, PETSC_ERR_LIB, "Cannot activate floating point exceptions");
536:     PetscCall(PetscInfo(NULL, "Using PETSC_HAVE_FENV_H FPTRAP with FE_NOMASK_ENV\n"));
537:   #elif defined PETSC_HAVE_XMMINTRIN_H
538:     _MM_SET_EXCEPTION_MASK(_MM_GET_EXCEPTION_MASK() & ~_MM_MASK_DIV_ZERO);
539:     /* _MM_SET_EXCEPTION_MASK(_MM_GET_EXCEPTION_MASK() & ~_MM_MASK_UNDERFLOW); */
540:     _MM_SET_EXCEPTION_MASK(_MM_GET_EXCEPTION_MASK() & ~_MM_MASK_OVERFLOW);
541:     _MM_SET_EXCEPTION_MASK(_MM_GET_EXCEPTION_MASK() & ~_MM_MASK_INVALID);
542:     PetscCall(PetscInfo(NULL, "Using PETSC_HAVE_FENV_H FPTRAP with PETSC_HAVE_XMMINTRIN_H\n"));
543:   #else
544:     /* C99 does not provide a way to modify the environment so there is no portable way to activate trapping. */
545:     PetscCall(PetscInfo(NULL, "Using PETSC_HAVE_FENV_H FPTRAP\n"));
546:   #endif
547:     PetscCheck(SIG_ERR != signal(SIGFPE, PetscDefaultFPTrap), PETSC_COMM_SELF, PETSC_ERR_LIB, "Can't set floating point handler");
548:   } else {
549:     PetscCheck(!fesetenv(FE_DFL_ENV), PETSC_COMM_SELF, PETSC_ERR_LIB, "Cannot disable floating point exceptions");
550:     /* can use _MM_SET_EXCEPTION_MASK(_MM_GET_EXCEPTION_MASK() | _MM_MASK_UNDERFLOW); if PETSC_HAVE_XMMINTRIN_H exists */
551:     PetscCheck(SIG_ERR != signal(SIGFPE, SIG_DFL), PETSC_COMM_SELF, PETSC_ERR_LIB, "Can't clear floating point handler");
552:   }
553:   _trapmode = flag;
554:   PetscFunctionReturn(PETSC_SUCCESS);
555: }

557: PetscErrorCode PetscDetermineInitialFPTrap(void)
558: {
559:   #if defined(FE_NOMASK_ENV) || defined PETSC_HAVE_XMMINTRIN_H
560:   unsigned int flags;
561:   #endif

563:   PetscFunctionBegin;
564:   #if defined(FE_NOMASK_ENV)
565:   flags = fegetexcept();
566:   if (flags & FE_DIVBYZERO) {
567:   #elif defined PETSC_HAVE_XMMINTRIN_H
568:   flags = _MM_GET_EXCEPTION_MASK();
569:   if (!(flags & _MM_MASK_DIV_ZERO)) {
570:   #else
571:   PetscCall(PetscInfo(NULL, "Floating point trapping unknown, assuming off\n"));
572:   PetscFunctionReturn(PETSC_SUCCESS);
573:   #endif
574:   #if defined(FE_NOMASK_ENV) || defined PETSC_HAVE_XMMINTRIN_H
575:     _trapmode = PETSC_FP_TRAP_ON;
576:     PetscCall(PetscInfo(NULL, "Floating point trapping is on by default %d\n", flags));
577:   } else {
578:     _trapmode = PETSC_FP_TRAP_OFF;
579:     PetscCall(PetscInfo(NULL, "Floating point trapping is off by default %d\n", flags));
580:   }
581:   PetscFunctionReturn(PETSC_SUCCESS);
582:   #endif
583: }

585: /* ------------------------------------------------------------*/
586: #elif defined(PETSC_HAVE_IEEEFP_H)
587:   #include <ieeefp.h>
588: void PetscDefaultFPTrap(int sig)
589: {
590:   PetscErrorCode ierr;

592:   PetscFunctionBegin;
593:   ierr = (*PetscErrorPrintf)("*** floating point error occurred ***\n");
594:   ierr = PetscError(PETSC_COMM_SELF, 0, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_REPEAT, "floating point error");
595:   (void)ierr;
596:   PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP);
597: }

599: PetscErrorCode PetscSetFPTrap(PetscFPTrap flag)
600: {
601:   PetscFunctionBegin;
602:   if (flag == PETSC_FP_TRAP_ON) {
603:   #if defined(PETSC_HAVE_FPRESETSTICKY)
604:     fpresetsticky(fpgetsticky());
605:   #elif defined(PETSC_HAVE_FPSETSTICKY)
606:     fpsetsticky(fpgetsticky());
607:   #endif
608:     fpsetmask(FP_X_INV | FP_X_DZ | FP_X_OFL | FP_X_OFL);
609:     PetscCheck(SIG_ERR != signal(SIGFPE, PetscDefaultFPTrap), PETSC_COMM_SELF, PETSC_ERR_LIB, "Can't set floating point handler");
610:   } else {
611:   #if defined(PETSC_HAVE_FPRESETSTICKY)
612:     fpresetsticky(fpgetsticky());
613:   #elif defined(PETSC_HAVE_FPSETSTICKY)
614:     fpsetsticky(fpgetsticky());
615:   #endif
616:     fpsetmask(0);
617:     PetscCheck(SIG_ERR != signal(SIGFPE, SIG_DFL), PETSC_COMM_SELF, PETSC_ERR_LIB, "Can't clear floating point handler");
618:   }
619:   _trapmode = flag;
620:   PetscCall(PetscInfo(NULL, "Using PETSC_HAVE_IEEEFP_H FPTRAP\n"));
621:   PetscFunctionReturn(PETSC_SUCCESS);
622: }

624: PetscErrorCode PetscDetermineInitialFPTrap(void)
625: {
626:   PetscFunctionBegin;
627:   PetscCall(PetscInfo(NULL, "Unable to determine initial floating point trapping. Assuming it is off\n"));
628:   PetscFunctionReturn(PETSC_SUCCESS);
629: }

631: /* -------------------------Default -----------------------------------*/
632: #else

634: void PetscDefaultFPTrap(int sig)
635: {
636:   PetscErrorCode ierr;

638:   PetscFunctionBegin;
639:   ierr = (*PetscErrorPrintf)("*** floating point error occurred ***\n");
640:   ierr = PetscError(PETSC_COMM_SELF, 0, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_REPEAT, "floating point error");
641:   (void)ierr;
642:   PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP);
643: }

645: PetscErrorCode PetscSetFPTrap(PetscFPTrap flag)
646: {
647:   PetscFunctionBegin;
648:   if (flag == PETSC_FP_TRAP_ON) {
649:     if (SIG_ERR == signal(SIGFPE, PetscDefaultFPTrap)) PetscCall((*PetscErrorPrintf)("Can't set floatingpoint handler\n"));
650:   } else if (SIG_ERR == signal(SIGFPE, SIG_DFL)) PetscCall((*PetscErrorPrintf)("Can't clear floatingpoint handler\n"));

652:   _trapmode = flag;
653:   PetscCall(PetscInfo(NULL, "Using default FPTRAP\n"));
654:   PetscFunctionReturn(PETSC_SUCCESS);
655: }

657: PetscErrorCode PetscDetermineInitialFPTrap(void)
658: {
659:   PetscFunctionBegin;
660:   PetscCall(PetscInfo(NULL, "Unable to determine initial floating point trapping. Assuming it is off\n"));
661:   PetscFunctionReturn(PETSC_SUCCESS);
662: }
663: #endif