fenv.h revision 1.4 1 /*-
2 * Copyright (c) 2004-2005 David Schultz <das (at) FreeBSD.ORG>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD: releng/10.1/lib/msun/ia64/fenv.h 226218 2011-10-10 15:43:09Z das $
27 */
28
29 #ifndef _IA64_FENV_H_
30 #define _IA64_FENV_H_
31
32 #include <sys/featuretest.h>
33 #include <sys/stdint.h>
34
35 #ifndef __fenv_static
36 #define __fenv_static static
37 #endif
38
39 typedef __uint64_t fenv_t;
40 typedef __uint16_t fexcept_t;
41
42 /* Exception flags */
43 #define FE_INVALID 0x01
44 #define FE_DENORMAL 0x02
45 #define FE_DIVBYZERO 0x04
46 #define FE_OVERFLOW 0x08
47 #define FE_UNDERFLOW 0x10
48 #define FE_INEXACT 0x20
49 #define FE_ALL_EXCEPT (FE_DIVBYZERO | FE_DENORMAL | FE_INEXACT | \
50 FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW)
51
52 /* Rounding modes */
53 #define FE_TONEAREST 0x0000
54 #define FE_DOWNWARD 0x0400
55 #define FE_UPWARD 0x0800
56 #define FE_TOWARDZERO 0x0c00
57 #define _ROUND_MASK (FE_TONEAREST | FE_DOWNWARD | \
58 FE_UPWARD | FE_TOWARDZERO)
59
60 __BEGIN_DECLS
61
62 /* Default floating-point environment */
63 extern const fenv_t __fe_dfl_env;
64 #define FE_DFL_ENV (&__fe_dfl_env)
65
66 #define _FPUSW_SHIFT 13
67
68 #define __stfpsr(__r) __asm __volatile("mov %0=ar.fpsr" : "=r" (*(__r)))
69 #define __ldfpsr(__r) __asm __volatile("mov ar.fpsr=%0;;" : : "r" (__r))
70
71 #if __GNUC_PREREQ__(8, 0)
72 #pragma GCC diagnostic push
73 #pragma GCC diagnostic ignored "-Wshadow"
74 #endif
75
76 __fenv_static inline int
77 feclearexcept(int __excepts)
78 {
79 fenv_t __fpsr;
80
81 __stfpsr(&__fpsr);
82 __fpsr &= ~((fenv_t)__excepts << _FPUSW_SHIFT);
83 __ldfpsr(__fpsr);
84 return (0);
85 }
86
87 __fenv_static inline int
88 fegetexceptflag(fexcept_t *__flagp, int __excepts)
89 {
90 fenv_t __fpsr;
91
92 __stfpsr(&__fpsr);
93 *__flagp = (fexcept_t)(__fpsr >> _FPUSW_SHIFT) & __excepts;
94 return (0);
95 }
96
97 __fenv_static inline int
98 fesetexceptflag(const fexcept_t *__flagp, int __excepts)
99 {
100 fenv_t __fpsr;
101
102 __stfpsr(&__fpsr);
103 __fpsr &= ~((fenv_t)__excepts << _FPUSW_SHIFT);
104 __fpsr |= (fenv_t)(__excepts & *__flagp) << _FPUSW_SHIFT;
105 __ldfpsr(__fpsr);
106 return (0);
107 }
108
109 /*
110 * It is worthwhile to use the inline version of this function iff it
111 * is called with arguments that are compile-time constants (due to
112 * dead code elimination). Unfortunately, gcc isn't smart enough to
113 * figure this out automatically, and there's no way to tell it.
114 * We assume that constant arguments will be the common case.
115 */
116 __fenv_static inline int
117 feraiseexcept(int __excepts)
118 {
119 volatile double d;
120
121 /*
122 * With a compiler that supports the FENV_ACCESS pragma
123 * properly, simple expressions like '0.0 / 0.0' should
124 * be sufficient to generate traps. Unfortunately, we
125 * need to bring a volatile variable into the equation
126 * to prevent incorrect optimizations.
127 */
128 if (__excepts & FE_INVALID) {
129 d = 0.0;
130 d = 0.0 / d;
131 }
132 if (__excepts & FE_DIVBYZERO) {
133 d = 0.0;
134 d = 1.0 / d;
135 }
136 if (__excepts & FE_OVERFLOW) {
137 d = 0x1.ffp1023;
138 d *= 2.0;
139 }
140 if (__excepts & FE_UNDERFLOW) {
141 d = 0x1p-1022;
142 d /= 0x1p1023;
143 }
144 if (__excepts & FE_INEXACT) {
145 d = 0x1p-1022;
146 d += 1.0;
147 }
148 return (0);
149 }
150
151 __fenv_static inline int
152 fetestexcept(int __excepts)
153 {
154 fenv_t __fpsr;
155
156 __stfpsr(&__fpsr);
157 return ((__fpsr >> _FPUSW_SHIFT) & __excepts);
158 }
159
160
161 __fenv_static inline int
162 fegetround(void)
163 {
164 fenv_t __fpsr;
165
166 __stfpsr(&__fpsr);
167 return (__fpsr & _ROUND_MASK);
168 }
169
170 __fenv_static inline int
171 fesetround(int __round)
172 {
173 fenv_t __fpsr;
174
175 if (__round & ~_ROUND_MASK)
176 return (-1);
177 __stfpsr(&__fpsr);
178 __fpsr &= ~_ROUND_MASK;
179 __fpsr |= __round;
180 __ldfpsr(__fpsr);
181 return (0);
182 }
183
184 __fenv_static inline int
185 fegetenv(fenv_t *__envp)
186 {
187
188 __stfpsr(__envp);
189 return (0);
190 }
191
192 __fenv_static inline int
193 feholdexcept(fenv_t *__envp)
194 {
195 fenv_t __fpsr;
196
197 __stfpsr(&__fpsr);
198 *__envp = __fpsr;
199 __fpsr &= ~((fenv_t)FE_ALL_EXCEPT << _FPUSW_SHIFT);
200 __fpsr |= FE_ALL_EXCEPT;
201 __ldfpsr(__fpsr);
202 return (0);
203 }
204
205 __fenv_static inline int
206 fesetenv(const fenv_t *__envp)
207 {
208
209 __ldfpsr(*__envp);
210 return (0);
211 }
212
213 int feupdateenv(const fenv_t *__envp);
214
215 #if __GNUC_PREREQ__(8, 0)
216 #pragma GCC diagnostic pop
217 #endif
218
219 #if defined(_NETBSD_SOURCE) || defined(_GNU_SOURCE)
220
221 __fenv_static inline int
222 feenableexcept(int __mask)
223 {
224 fenv_t __newfpsr, __oldfpsr;
225
226 __stfpsr(&__oldfpsr);
227 __newfpsr = __oldfpsr & ~(__mask & FE_ALL_EXCEPT);
228 __ldfpsr(__newfpsr);
229 return (~__oldfpsr & FE_ALL_EXCEPT);
230 }
231
232 __fenv_static inline int
233 fedisableexcept(int __mask)
234 {
235 fenv_t __newfpsr, __oldfpsr;
236
237 __stfpsr(&__oldfpsr);
238 __newfpsr = __oldfpsr | (__mask & FE_ALL_EXCEPT);
239 __ldfpsr(__newfpsr);
240 return (~__oldfpsr & FE_ALL_EXCEPT);
241 }
242
243 __fenv_static inline int
244 fegetexcept(void)
245 {
246 fenv_t __fpsr;
247
248 __stfpsr(&__fpsr);
249 return (~__fpsr & FE_ALL_EXCEPT);
250 }
251
252 #endif /* _NETBSD_SOURCE || _GNU_SOURCE */
253
254 __END_DECLS
255
256 #endif /* !_IA64_FENV_H_ */
257