NeoPZ
fpo_exceptions.h
Go to the documentation of this file.
1 
7 #ifndef __FPO_EXCEPTIONS_H
8 #define __FPO_EXCEPTIONS_H
9 
10 #ifdef WIN32
11 
12 #include <float.h>
13 
14 #ifndef _EM_OVERFLOW
15 #define _EM_OVERFLOW EM_OVERFLOW
16 #endif//_EM_OVERFLOW
17 
18 #ifndef _EM_UNDERFLOW
19 #define _EM_UNDERFLOW EM_UNDERFLOW
20 #endif//_EM_UNDERFLOW
21 
22 #ifndef _EM_INVALID
23 #define _EM_INVALID EM_INVALID
24 #endif//_EM_INVALID
25 
26 #ifndef _EM_ZERODIVIDE
27 #define _EM_ZERODIVIDE EM_ZERODIVIDE
28 #endif//_EM_ZERODIVIDE
29 
30 #else
31 
32 #include <fenv.h>
33 
34 #ifdef MACOSX
35 
36 
37 inline int
38 fegetexcept (void)
39 {
40  static fenv_t fenv;
41 
42  return fegetenv (&fenv) ? -1 : (fenv.__control & FE_ALL_EXCEPT);
43 }
44 
45 inline int
46 feenableexcept (unsigned int excepts)
47 {
48  static fenv_t fenv;
49  unsigned int new_excepts = excepts & FE_ALL_EXCEPT,
50  old_excepts; // previous masks
51 
52  if ( fegetenv (&fenv) ) return -1;
53  old_excepts = fenv.__control & FE_ALL_EXCEPT;
54 
55  // unmask
56  fenv.__control &= ~new_excepts;
57  fenv.__mxcsr &= ~(new_excepts << 7);
58 
59  return ( fesetenv (&fenv) ? -1 : old_excepts );
60 }
61 
62 inline int
63 fedisableexcept (unsigned int excepts)
64 {
65  static fenv_t fenv;
66  unsigned int new_excepts = excepts & FE_ALL_EXCEPT,
67  old_excepts; // all previous masks
68 
69  if ( fegetenv (&fenv) ) return -1;
70  old_excepts = fenv.__control & FE_ALL_EXCEPT;
71 
72  // mask
73  fenv.__control |= new_excepts;
74  fenv.__mxcsr |= new_excepts << 7;
75 
76  return ( fesetenv (&fenv) ? -1 : old_excepts );
77 }
78 
79 
80 // x87 fpu
81 #define getx87cr(x) asm ("fnstcw %0" : "=m" (x));
82 #define setx87cr(x) asm ("fldcw %0" : "=m" (x));
83 #define getx87sr(x) asm ("fnstsw %0" : "=m" (x));
84 
85 // SIMD, gcc with Intel Core 2 Duo uses SSE2(4)
86 #define getmxcsr(x) asm ("stmxcsr %0" : "=m" (x));
87 #define setmxcsr(x) asm ("ldmxcsr %0" : "=m" (x));
88 
89 #include <signal.h>
90 #include <stdio.h> // printf()
91 #include <stdlib.h> // abort(), exit()
92 
93 static std::string fe_code_name[] = {
94  "FPE_NOOP",
95  "FPE_FLTDIV", "FPE_FLTINV", "FPE_FLTOVF", "FPE_FLTUND",
96  "FPE_FLTRES", "FPE_FLTSUB", "FPE_INTDIV", "FPE_INTOVF"
97  "FPE_UNKNOWN"
98 };
99 
100 /* SAMPLE ALTERNATE FP EXCEPTION HANDLER
101 
102  The sample handler just reports information about the
103  exception that invoked it, and aborts. It makes no attempt
104  to restore state and return to the application.
105 
106  More sophisticated handling would have to confront at least
107  these issues:
108 
109  * interface to the system context for restoring state
110  * imprecision of interrupts from hardware for the intel x87
111  fpu (but not the SIMD unit, nor the ppc)
112  * imprecision of interrupts from system software
113  */
114 inline void
115 fhdl ( int sig, siginfo_t *sip, ucontext_t *scp )
116 {
117  int fe_code = sip->si_code;
118  unsigned int excepts = fetestexcept (FE_ALL_EXCEPT);
119 
120  switch (fe_code)
121  {
122 #ifdef FPE_NOOP // occurs in OS X
123  case FPE_NOOP: fe_code = 0; break;
124 #endif
125  case FPE_FLTDIV: fe_code = 1; break; // divideByZero
126  case FPE_FLTINV: fe_code = 2; break; // invalid
127  case FPE_FLTOVF: fe_code = 3; break; // overflow
128  case FPE_FLTUND: fe_code = 4; break; // underflow
129  case FPE_FLTRES: fe_code = 5; break; // inexact
130  case FPE_FLTSUB: fe_code = 6; break; // invalid
131  case FPE_INTDIV: fe_code = 7; break; // overflow
132  case FPE_INTOVF: fe_code = 8; break; // underflow
133  default: fe_code = 9;
134  }
135 
136  if ( sig == SIGFPE )
137  {
138  unsigned short x87cr,x87sr;
139  unsigned int mxcsr;
140 
141  getx87cr (x87cr);
142  getx87sr (x87sr);
143  getmxcsr (mxcsr);
144  printf ("X87CR: 0x%04X\n", x87cr);
145  printf ("X87SR: 0x%04X\n", x87sr);
146  printf ("MXCSR: 0x%08X\n", mxcsr);
147 
148 
149  printf ("signal: SIGFPE with code %s\n", fe_code_name[fe_code].c_str());
150  printf ("invalid flag: 0x%04X\n", excepts & FE_INVALID);
151  printf ("divByZero flag: 0x%04X\n", excepts & FE_DIVBYZERO);
152  }
153  else printf ("Signal is not SIGFPE, it's %i.\n", sig);
154  abort();
155 }
156 #endif //MACOSX
157 //#endif //DEBUG
158 
159 #endif //WIN32
160 
161 
163  private:
164 #ifdef WIN32
165  unsigned int fPrevConfig;
166 #else
167  fenv_t fPrevConfig;
168 #endif //WIN32
169 public:
171 #ifdef WIN32
172  _controlfp_s(&fPrevConfig, 0, 0);//saves current state of fpu
173  _controlfp(1, _EM_OVERFLOW);
174  _controlfp(1, _EM_INVALID);
175  _controlfp(1, _EM_ZERODIVIDE);
176 #else
177  fegetenv(&fPrevConfig);//saves current state of fpu
178  feraiseexcept(FE_INVALID | FE_OVERFLOW | FE_DIVBYZERO);
179 #endif //WIN32
180  }
181 
183 #ifdef WIN32
184  unsigned int temp;
185  _controlfp_s(&temp, fPrevConfig, _MCW_EM);//restores previous sates of fpu
186 #else
187  fesetenv(&fPrevConfig);//restores previous sates of fpu
188 #endif //WIN32
189  }
190 };
191 
192 
193 #endif //__FPO_EXCEPTIONS_H