YetAnotherCoupler 3.2.0_a
Loading...
Searching...
No Matches
feenableexcept.h
Go to the documentation of this file.
1// SPDX-FileCopyrightText: David N. Williams
2//
3// SPDX-License-Identifier: CC0-1.0
4
5/* Title: Floating-point exception handling example
6 Author: David N. Williams
7 File: fe-handlng-example.c
8 License: Public Domain
9 Version: 0.5.0
10 Started: 21-Sep-09
11 Revised: 22-Sep-09
12 Revised: 30-Sep-09 (comment typo)
13
14This code is an example of alternate, nondefault handling of
15IEEE 754 floating-point exceptions in OS X and Linux, based on
16the GNU functions feenableexcept(), fedisableeexcept(), and
17fegetexcept() [in libm], plus POSIX sigaction().
18
19The GNU functions above are not implemented in OS X Leopard,
20gcc 4.x, but are present in Linux. We implement them here for
21OS X, at least until the underlying mechanism is no longer
22supported by Apple.
23
24The mechanism is to use the POSIX functions fegetenv() and
25fesetenv(), which *are* present in OS X, to manipulate the ppc
26and intel floating-point control registers, after changing bits
27in fields corresponding to those registers in the fenv_t data
28type.
29
30Assembly language code to directly access the floating-point
31status and control registers for ppc and intel is also included.
32
33This example grew out of an update to legacy code for Apple
34ppc's. The original legacy code is in Listing 7-1 in "PowerPC
35Numerics", 2004:
36
37http://lists.apple.com/archives/unix-porting/2003/May/msg00026.html
38
39Another version of the ppc legacy code is here:
40
41http://developer.apple.com/documentation/Performance/Conceptual/Mac_OSX_Numerics/Mac_OSX_Numerics.pdf
42
43Terry Lambert pointed out that our naive update of the legacy
44example to Mac OS X Leopard made egregious unsupported use of
45system context structures in the handler. See his reply to
46
47http://lists.apple.com/archives/Darwin-dev/2009/Sep/msg00091.html
48
49*/
50
51#ifndef __APPLE__
52/* BEGIN quote
53http://graphviz.sourcearchive.com/documentation/2.16/gvrender__pango_8c-source.html
54*/
55/* _GNU_SOURCE is needed (supposedly) for the feenableexcept
56 * prototype to be defined in fenv.h on GNU systems.
57 * Presumably it will do no harm on other systems.
58 */
59#ifndef _GNU_SOURCE
60#define _GNU_SOURCE
61#endif
62
63/* We are not supposed to need __USE_GNU, but I can't see
64 * how to get the prototype for fedisableexcept from
65 * /usr/include/fenv.h without it.
66 */
67#ifndef __USE_GNU
68#define __USE_GNU
69#endif
70/* END quote */
71#endif // !__APPLE__
72
73#include <fenv.h>
74
75#ifdef __APPLE__
76
77// PPC
78#if (defined(__PPC64__) || defined(__ppc64__) || defined(_ARCH_PPC64))
79
80#define FE_EXCEPT_SHIFT 22 // shift flags right to get masks
81#define FM_ALL_EXCEPT FE_ALL_EXCEPT >> FE_EXCEPT_SHIFT
82
83static int
84feenableexcept (unsigned int excepts)
85{
86 static fenv_t fenv;
87 unsigned int new_excepts = (excepts & FE_ALL_EXCEPT) >> FE_EXCEPT_SHIFT,
88 old_excepts; // all previous masks
89
90 if ( fegetenv (&fenv) ) return -1;
91 old_excepts = (fenv & FM_ALL_EXCEPT) << FE_EXCEPT_SHIFT;
92
93 fenv = (fenv & ~new_excepts) | new_excepts;
94 return ( fesetenv (&fenv) ? -1 : old_excepts );
95}
96
97// INTEL
98#elif (defined(__x86_64__) || defined(_M_X64) || defined(i386) || defined(__i386__) || defined(__i386) || defined(_M_IX86))
99
100static int
101feenableexcept (unsigned int excepts)
102{
103 static fenv_t fenv;
104 unsigned int new_excepts = excepts & FE_ALL_EXCEPT,
105 old_excepts; // previous masks
106
107 if ( fegetenv (&fenv) ) return -1;
108 old_excepts = fenv.__control & FE_ALL_EXCEPT;
109
110 // unmask
111 fenv.__control &= ~new_excepts;
112 fenv.__mxcsr &= ~(new_excepts << 7);
113
114 return ( fesetenv (&fenv) ? -1 : old_excepts );
115}
116
117// ARM
118#elif (defined(__arm) || defined(__arm64) || defined(__aarch64__))
119
120#define FE_EXCEPT_SHIFT 8
121
122static int
123feenableexcept (unsigned int excepts)
124{
125 static fenv_t fenv;
126 if ( fegetenv (&fenv) ) return -1;
127 unsigned int old_excepts = ((fenv.__fpcr) >> FE_EXCEPT_SHIFT) & FE_ALL_EXCEPT;
128
129 unsigned int new_excepts = excepts & FE_ALL_EXCEPT;
130 fenv.__fpcr |= new_excepts << FE_EXCEPT_SHIFT;
131
132 return ( fesetenv (&fenv) ? -1 : old_excepts );
133}
134
135#else
136
137#error "feenableexcept.h: unknown hardware architecture"
138
139#endif // PPC, INTEL, or ARM enabling
140#endif // __APPLE__