Basilisk CFD
Adaptive Cartesian mesh PDE framework
Loading...
Searching...
No Matches
fp_osx.h
Go to the documentation of this file.
1/** @file fp_osx.h
2 */
3/* Title: Floating-point exception handling example
4 Author: David N. Williams
5 File: fe-handlng-example.c
6 License: Public Domain
7 Version: 0.5.0
8 Started: 21-Sep-09
9 Revised: 22-Sep-09
10 Revised: 30-Sep-09 (comment typo)
11 Revised: 18 Oct-12 (chnaged char* to const char * on line 228, by R. Booth)
12 Revised: 17 Feb-15 (changed asm to __asm for being both C99 and
13 GNU99 compliant, by G. Kirstetter)
14 Revised: 14 Jun-18 (changed the defined() test condition, by G. Kirstetter)
15
16This code is an example of alternate, nondefault handling of
17IEEE 754 floating-point exceptions in OS X and Linux, based on
18the GNU functions feenableexcept(), fedisableeexcept(), and
19fegetexcept() [in libm], plus POSIX sigaction().
20
21The GNU functions above are not implemented in OS X Leopard,
22gcc 4.x, but are present in Linux. We implement them here for
23OS X, at least until the underlying mechanism is no longer
24supported by Apple.
25
26The mechanism is to use the POSIX functions fegetenv() and
27fesetenv(), which *are* present in OS X, to manipulate the ppc
28and intel floating-point control registers, after changing bits
29in fields corresponding to those registers in the fenv_t data
30type.
31
32Assembly language code to directly access the floating-point
33status and control registers for ppc and intel is also included.
34
35This example grew out of an update to legacy code for Apple
36ppc's. The original legacy code is in Listing 7-1 in "PowerPC
37Numerics", 2004:
38
39http://lists.apple.com/archives/unix-porting/2003/May/msg00026.html
40
41Another version of the ppc legacy code is here:
42
43http://developer.apple.com/documentation/Performance/Conceptual/Mac_OSX_Numerics/Mac_OSX_Numerics.pdf
44
45Terry Lambert pointed out that our naive update of the legacy
46example to Mac OS X Leopard made egregious unsupported use of
47system context structures in the handler. See his reply to
48
49http://lists.apple.com/archives/Darwin-dev/2009/Sep/msg00091.html
50
51The example in this file is more plain vanilla, and aims at
52alternate handling that does not return to the application, but
53rather aborts with a diagnostic message.
54
55To compile it under Mac OS X, execute:
56
57 cc -o fe-handling fe-handling-example.c
58
59To compile it under Linux, execute:
60
61 cc -DLINUX -lm -o fe-handling fe-handling-example.c
62*/
63
64#ifdef LINUX
65/* BEGIN quote
66http://graphviz.sourcearchive.com/documentation/2.16/gvrender__pango_8c-source.html
67*/
68/* _GNU_SOURCE is needed (supposedly) for the feenableexcept
69 * prototype to be defined in fenv.h on GNU systems.
70 * Presumably it will do no harm on other systems.
71 */
72#ifndef _GNU_SOURCE
73#define _GNU_SOURCE
74#endif
75
76/* We are not supposed to need __USE_GNU, but I can't see
77 * how to get the prototype for fedisableexcept from
78 * /usr/include/fenv.h without it.
79 */
80#ifndef __USE_GNU
81#define __USE_GNU
82#endif
83/* END quote */
84#endif // LINUX
85
86#include <fenv.h>
87
88#if defined(__ppc__) || defined(__ppc64__)
89#define DEFINED_PPC
90#endif
91
92#if defined(__i386__) || defined(__x86_64__)
93#define DEFINED_INTEL 1
94#endif
95
96#ifndef LINUX
97#if DEFINED_PPC
98
99#define FE_EXCEPT_SHIFT 22 // shift flags right to get masks
100#define FM_ALL_EXCEPT FE_ALL_EXCEPT >> FE_EXCEPT_SHIFT
101
102/* GNU C Library:
103http://www.gnu.org/software/libc/manual/html_node/Control-Functions.html
104
105 - Function: int fegetexcept (int excepts)
106
107 The function returns a bitmask of all currently enabled
108 exceptions. It returns -1 in case of failure.
109
110 The excepts argument appears in other functions in fenv.h,
111 and corresponds to the FE_xxx exception flag constants. It
112 is unclear whether the bitmask is for the flags or the masks.
113 We return that for the flags, which corresponds to the
114 excepts argument in feenableexcept(excepts) and
115 fedisableexcept(excepts). In GNU/Linux the argument is void,
116 and that's what we implement. Linux "man fegetenv" appears
117 to suggest that it's the mask corresponding to bits in
118 excepts that is returned.
119*/
120int
121fegetexcept (void)
122{
123 static fenv_t fenv;
124
125 return ( fegetenv (&fenv) ? -1 :
126 (
128 );
129}
130
131int
132feenableexcept (unsigned int excepts)
133{
134 static fenv_t fenv;
135 unsigned int new_excepts = (excepts & FE_ALL_EXCEPT) >> FE_EXCEPT_SHIFT,
136 old_excepts; // all previous masks
137
138 if ( fegetenv (&fenv) ) return -1;
140
142 return ( fesetenv (&fenv) ? -1 : old_excepts );
143}
144
145int
146fedisableexcept (unsigned int excepts)
147{
148 static fenv_t fenv;
149 unsigned int still_on = ~( (excepts & FE_ALL_EXCEPT) >> FE_EXCEPT_SHIFT ),
150 old_excepts; // previous masks
151
152 if ( fegetenv (&fenv) ) return -1;
154
155 fenv &= still_on;
156 return ( fesetenv (&fenv) ? -1 : old_excepts );
157}
158
159#elif (DEFINED_INTEL == 1)
160
161int
162fegetexcept (void)
163{
164 static fenv_t fenv;
165
166 return fegetenv (&fenv) ? -1 : (fenv.__control & FE_ALL_EXCEPT);
167}
168
169int
170feenableexcept (unsigned int excepts)
171{
172 static fenv_t fenv;
173 unsigned int new_excepts = excepts & FE_ALL_EXCEPT,
174 old_excepts; // previous masks
175
176 if ( fegetenv (&fenv) ) return -1;
177 old_excepts = fenv.__control & FE_ALL_EXCEPT;
178
179 // unmask
180 fenv.__control &= ~new_excepts;
181 fenv.__mxcsr &= ~(new_excepts << 7);
182
183 return ( fesetenv (&fenv) ? -1 : old_excepts );
184}
185
186int
187fedisableexcept (unsigned int excepts)
188{
189 static fenv_t fenv;
190 unsigned int new_excepts = excepts & FE_ALL_EXCEPT,
191 old_excepts; // all previous masks
192
193 if ( fegetenv (&fenv) ) return -1;
194 old_excepts = fenv.__control & FE_ALL_EXCEPT;
195
196 // mask
197 fenv.__control |= new_excepts;
198 fenv.__mxcsr |= new_excepts << 7;
199
200 return ( fesetenv (&fenv) ? -1 : old_excepts );
201}
202
203#else // not PPC and not INTEL
204
205// This is an unsupported architecture.
206// This could be ARM (for example) and should be completed somehow...
207// Volunteers welcome...
208
209int
210fegetexcept (void) { return 0; }
211
212int
213feenableexcept (unsigned int excepts) { return 0; }
214
215int
216fedisableexcept (unsigned int excepts) { return 0; }
217
218#endif // not PPC and no INTEL
219#endif // not LINUX
220
221#if DEFINED_PPC
222
223#define getfpscr(x) asm volatile ("mffs %0" : "=f" (x));
224#define setfpscr(x) asm volatile ("mtfsf 255,%0" : : "f" (x));
225
226typedef union {
227 struct {
228 unsigned long hi;
229 unsigned long lo;
230 } i;
231 double d;
232} hexdouble;
233
234#endif // DEFINED_PPC
235
236#if DEFINED_INTEL
237
238// x87 fpu
239#define getx87cr(x) __asm ("fnstcw %0" : "=m" (x));
240#define setx87cr(x) __asm ("fldcw %0" : "=m" (x));
241#define getx87sr(x) __asm ("fnstsw %0" : "=m" (x));
242
243// SIMD, gcc with Intel Core 2 Duo uses SSE2(4)
244#define getmxcsr(x) __asm ("stmxcsr %0" : "=m" (x));
245#define setmxcsr(x) __asm ("ldmxcsr %0" : "=m" (x));
246
247#endif // DEFINED_INTEL
248
249#include <signal.h>
250#include <stdio.h> // printf()
251#include <stdlib.h> // abort(), exit()
252
253static const char *fe_code_name[] = {
254 "FPE_NOOP",
255 "FPE_FLTDIV", "FPE_FLTINV", "FPE_FLTOVF", "FPE_FLTUND",
256 "FPE_FLTRES", "FPE_FLTSUB", "FPE_INTDIV", "FPE_INTOVF"
257 "FPE_UNKNOWN"
258};
259
260/* SAMPLE ALTERNATE FP EXCEPTION HANDLER
261
262 The sample handler just reports information about the
263 exception that invoked it, and aborts. It makes no attempt
264 to restore state and return to the application.
265
266 More sophisticated handling would have to confront at least
267 these issues:
268
269 * interface to the system context for restoring state
270 * imprecision of interrupts from hardware for the intel x87
271 fpu (but not the SIMD unit, nor the ppc)
272 * imprecision of interrupts from system software
273*/
274void
276{
277 int fe_code = sip->si_code;
278 unsigned int excepts = fetestexcept (FE_ALL_EXCEPT);
279
280 switch (fe_code)
281 {
282#ifdef FPE_NOOP // occurs in OS X
283 case FPE_NOOP: fe_code = 0; break;
284#endif
285 case FPE_FLTDIV: fe_code = 1; break; // divideByZero
286 case FPE_FLTINV: fe_code = 2; break; // invalid
287 case FPE_FLTOVF: fe_code = 3; break; // overflow
288 case FPE_FLTUND: fe_code = 4; break; // underflow
289 case FPE_FLTRES: fe_code = 5; break; // inexact
290 case FPE_FLTSUB: fe_code = 6; break; // invalid
291 case FPE_INTDIV: fe_code = 7; break; // overflow
292 case FPE_INTOVF: fe_code = 8; break; // underflow
293 default: fe_code = 9;
294 }
295
296 if ( sig == SIGFPE )
297 {
298#if DEFINED_INTEL
299 unsigned short x87cr,x87sr;
300 unsigned int mxcsr;
301
302 getx87cr (x87cr);
303 getx87sr (x87sr);
304 getmxcsr (mxcsr);
305 printf ("X87CR: 0x%04X\n", x87cr);
306 printf ("X87SR: 0x%04X\n", x87sr);
307 printf ("MXCSR: 0x%08X\n", mxcsr);
308#endif
309
310#if DEFINED_PPC
311 hexdouble t;
312
313 getfpscr (t.d);
314 printf ("FPSCR: 0x%08X\n", t.i.lo);
315#endif
316
317 printf ("signal: SIGFPE with code %s\n", fe_code_name[fe_code]);
318 printf ("invalid flag: 0x%04X\n", excepts & FE_INVALID);
319 printf ("divByZero flag: 0x%04X\n", excepts & FE_DIVBYZERO);
320 }
321 else printf ("Signal is not SIGFPE, it's %i.\n", sig);
322
323 abort();
324}
325
int x
Definition common.h:76
double d[2]
Definition embed.h:383
scalar int i
Definition embed.h:74
double t
Definition events.h:24
int fedisableexcept(unsigned int excepts)
Definition fp_osx.h:216
static const char * fe_code_name[]
Definition fp_osx.h:253
int feenableexcept(unsigned int excepts)
Definition fp_osx.h:213
void fhdl(int sig, siginfo_t *sip, ucontext_t *scp)
Definition fp_osx.h:275
int fegetexcept(void)
Definition fp_osx.h:210