feexceptErsatz.H
Go to the documentation of this file.
1 // ============================================================================
2 // Generic handling of floating point exceptions
3 //
4 // 2018 Alexey Matveichev
5 // 2021 Tatsuya Shimizu - ARM64 support
6 // 2023 Guanyang Xue - improve ARM64 support
7 // ----------------------------------------------------------------------------
8 //
9 // Original Author
10 // David N. Williams
11 //
12 // License
13 // Public Domain
14 //
15 // Description
16 // Alternate, nondefault handling of IEEE 754 floating-point exceptions
17 // in OS X, based on the GNU functions feenableexcept(), fedisableeexcept()
18 // and fegetexcept() [in libm]
19 //
20 // http://www-personal.umich.edu/~williams/archive/computation/fe-handling-example.c
21 // ============================================================================
22 
23 #ifndef Foam_feexceptErsatz_H
24 #define Foam_feexceptErsatz_H
25 
26 #ifdef __APPLE__
27 #include <fenv.h>
28 
29 // Workaround for Apple Silicon - has SIGILL (illegal instruction) not SIGFPE
30 #if defined __arm64__
31 #undef SIGFPE
32 #define SIGFPE SIGILL
33 #endif
34 
35 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
36 
37 inline int feenableexcept(unsigned int excepts)
38 {
39  static fenv_t fenv;
40  unsigned int new_excepts = excepts & FE_ALL_EXCEPT;
41  unsigned int old_excepts; // previous masks
42 
43  if (fegetenv(&fenv))
44  {
45  return -1;
46  }
47 
48 #if defined __arm64__
49  old_excepts = fenv.__fpsr & FE_ALL_EXCEPT;
50 
51  fenv.__fpsr |= new_excepts;
52  fenv.__fpcr |= (new_excepts << 8);
53 #else
54  old_excepts = fenv.__control & FE_ALL_EXCEPT;
55 
56  fenv.__control &= ~new_excepts;
57  fenv.__mxcsr &= ~(new_excepts << 7);
58 #endif
59 
60  return fesetenv(&fenv) ? -1 : old_excepts;
61 }
62 
63 
64 inline int fedisableexcept(unsigned int excepts)
65 {
66  static fenv_t fenv;
67  unsigned int new_excepts = excepts & FE_ALL_EXCEPT;
68  unsigned int old_excepts; // all previous masks
69 
70  if (fegetenv(&fenv))
71  {
72  return -1;
73  }
74 
75 #if defined __arm64__
76  old_excepts = fenv.__fpsr & FE_ALL_EXCEPT;
77 
78  fenv.__fpsr &= ~new_excepts;
79  fenv.__fpcr &= ~(new_excepts << 8);
80 #else
81  old_excepts = fenv.__control & FE_ALL_EXCEPT;
82 
83  fenv.__control |= new_excepts;
84  fenv.__mxcsr |= (new_excepts << 7);
85 #endif
86 
87  return fesetenv(&fenv) ? -1 : old_excepts;
88 }
89 
90 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
91 
92 #endif // __APPLE__
93 #endif
94 
95 // ************************************************************************* //