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