fenv.h revision 1.10 1 /* $NetBSD: fenv.h,v 1.10 2024/10/30 15:56:11 riastradh Exp $ */
2
3 /*-
4 * Copyright (c) 2015 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Christos Zoulas.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #ifndef _M68K_FENV_H_
33 #define _M68K_FENV_H_
34
35 #include <sys/featuretest.h>
36 #include <sys/stdint.h>
37
38 #include <m68k/float.h>
39 #include <m68k/fpreg.h>
40
41 /* Exception bits, from FPSR */
42 #define FE_INEXACT FPSR_AINEX
43 #define FE_DIVBYZERO FPSR_ADZ
44 #define FE_UNDERFLOW FPSR_AUNFL
45 #define FE_OVERFLOW FPSR_AOVFL
46 #define FE_INVALID FPSR_AIOP
47
48 #define FE_ALL_EXCEPT \
49 (FE_INEXACT | FE_DIVBYZERO | FE_UNDERFLOW | FE_OVERFLOW | FE_INVALID)
50
51 /* Rounding modes, from FPCR */
52 #define FE_TONEAREST FPCR_NEAR
53 #define FE_TOWARDZERO FPCR_ZERO
54 #define FE_DOWNWARD FPCR_MINF
55 #define FE_UPWARD FPCR_PINF
56
57 #define _ROUND_MASK \
58 (FE_TONEAREST | FE_TOWARDZERO | FE_DOWNWARD | FE_UPWARD)
59
60 #if defined(__HAVE_68881__)
61
62 #ifndef __fenv_static
63 #define __fenv_static static
64 #endif
65
66 typedef uint32_t fexcept_t;
67
68 /* same layout as fmovem */
69 typedef struct {
70 uint32_t fpcr;
71 uint32_t fpsr;
72 uint32_t fppc;
73 } fenv_t;
74
75 #define FE_DFL_ENV ((fenv_t *) -1)
76
77 #define __get_fpcr(__fpcr) \
78 __asm__ __volatile__ ("fmove%.l %!,%0" : "=dm" (__fpcr))
79 #define __set_fpcr(__fpcr) \
80 __asm__ __volatile__ ("fmove%.l %0,%!" : : "dm" (__fpcr))
81
82 #define __get_fpsr(__fpsr) \
83 __asm__ __volatile__ ("fmove%.l %/fpsr,%0" : "=dm" (__fpsr))
84 #define __set_fpsr(__fpsr) \
85 __asm__ __volatile__ ("fmove%.l %0,%/fpsr" : : "dm" (__fpsr))
86
87 #define __fmul(__s, __t, __d) \
88 do { \
89 __t d = __d; \
90 __asm__ __volatile__ ("fmul" __s "; fnop" : "=f" (d) : "0" (d)); \
91 } while (/*CONSTCOND*/0)
92
93 #define __fdiv(__s, __t, __d) \
94 do { \
95 __t d = __d; \
96 __asm__ __volatile__ ("fdiv" __s "; fnop" : "=f" (d) : "0" (d)); \
97 } while (/*CONSTCOND*/0)
98
99 #define __fetox(__s, __t, __d) \
100 do { \
101 __t d = __d; \
102 __asm__ __volatile__ ("fetox" __s "; fnop" : "=f" (d) : "0" (d)); \
103 } while (/*CONSTCOND*/0)
104
105 #define __fgetenv(__envp) \
106 __asm__ __volatile__ ("fmovem%.l %/fpcr/%/fpsr/%/fpiar,%0" : "=m" (__envp))
107
108 #define __fsetenv(__envp) \
109 __asm__ __volatile__ ("fmovem%.l %0,%/fpcr/%/fpsr/%/fpiar" : : "m" (__envp))
110
111 __BEGIN_DECLS
112
113 #if __GNUC_PREREQ__(8, 0)
114 #pragma GCC diagnostic push
115 #pragma GCC diagnostic ignored "-Wshadow"
116 #endif
117
118 __fenv_static inline int
119 feclearexcept(int __excepts)
120 {
121 fexcept_t __fpsr;
122
123 __excepts &= FE_ALL_EXCEPT;
124
125 __get_fpsr(__fpsr);
126 __fpsr &= ~__excepts;
127 __set_fpsr(__fpsr);
128
129 return 0;
130 }
131
132 __fenv_static inline int
133 fegetexceptflag(fexcept_t *__flagp, int __excepts)
134 {
135 fexcept_t __fpsr;
136
137 __get_fpsr(__fpsr);
138
139 *__flagp = __fpsr & __excepts & FE_ALL_EXCEPT;
140
141 return 0;
142 }
143
144 __fenv_static inline int
145 fesetexceptflag(const fexcept_t *__flagp, int __excepts)
146 {
147 fexcept_t __fpsr;
148
149 __get_fpsr(__fpsr);
150
151 __fpsr &= ~(__excepts & FE_ALL_EXCEPT);
152 __fpsr |= *__flagp & __excepts & FE_ALL_EXCEPT;
153
154 __set_fpsr(__fpsr);
155
156 return 0;
157 }
158
159 __fenv_static inline int
160 feraiseexcept(int __excepts)
161 {
162 if (__excepts & FE_INVALID) /* Inf * 0 */
163 __fmul("%.s %#0r0,%0", double, __builtin_huge_val());
164
165 if (__excepts & FE_DIVBYZERO) /* 1.0 / 0 */
166 __fdiv("%.s %#0r0,%0", double, 1.0);
167
168 if (__excepts & FE_OVERFLOW) /* MAX * MAX */
169 __fmul("%.x %0,%0", long double, LDBL_MAX);
170
171 if (__excepts & FE_UNDERFLOW) /* e ^ -MAX */
172 __fetox("%.x %0", long double, -LDBL_MAX);
173
174 if (__excepts & FE_INEXACT) /* 1 / 3 */
175 __fdiv("%.s %#0r3,%0", long double, 1.0);
176
177 return 0;
178 }
179
180 __fenv_static inline int
181 fetestexcept(int __excepts)
182 {
183 fexcept_t __fpsr;
184
185 __get_fpsr(__fpsr);
186
187 return __fpsr & __excepts & FE_ALL_EXCEPT;
188 }
189
190 __fenv_static inline int
191 fegetround(void)
192 {
193 fexcept_t __fpcr;
194
195 __get_fpcr(__fpcr);
196 return __fpcr & _ROUND_MASK;
197 }
198
199 __fenv_static inline int
200 fesetround(int __round)
201 {
202 fexcept_t __fpcr;
203
204 if (__round & ~_ROUND_MASK)
205 return -1;
206
207 __get_fpcr(__fpcr);
208
209 __fpcr &= ~_ROUND_MASK;
210 __fpcr |= __round;
211
212 __set_fpcr(__fpcr);
213
214 return 0;
215 }
216
217 __fenv_static inline int
218 fegetenv(fenv_t *__envp)
219 {
220 __fgetenv(*__envp);
221
222 return 0;
223 }
224
225 __fenv_static inline int
226 feholdexcept(fenv_t *__envp)
227 {
228 fexcept_t __fpcr, __fpsr;
229
230 __fgetenv(*__envp);
231 __fpsr = __envp->fpsr & ~FE_ALL_EXCEPT;
232 __set_fpsr(__fpsr); /* clear all */
233 __fpcr = __envp->fpcr & ~(FE_ALL_EXCEPT << 6);
234 __set_fpcr(__fpcr); /* set non/stop */
235
236 return 0;
237 }
238
239 __fenv_static inline int
240 fesetenv(const fenv_t *__envp)
241 {
242 fenv_t __tenv;
243
244 __fgetenv(__tenv);
245
246 if (__envp == FE_DFL_ENV) {
247 __tenv.fpcr |=
248 __envp->fpcr & ((FE_ALL_EXCEPT << 6) | FE_UPWARD);
249 __tenv.fpsr |= __envp->fpsr & FE_ALL_EXCEPT;
250 }
251
252 __fsetenv(__tenv);
253
254 return 0;
255 }
256
257 __fenv_static inline int
258 feupdateenv(const fenv_t *__envp)
259 {
260 fexcept_t __fpsr;
261
262 __get_fpsr(__fpsr);
263 __fpsr &= FE_ALL_EXCEPT;
264 fesetenv(__envp);
265 feraiseexcept((int)__fpsr);
266 return 0;
267 }
268
269 #if __GNUC_PREREQ__(8, 0)
270 #pragma GCC diagnostic pop
271 #endif
272
273 #if defined(_NETBSD_SOURCE) || defined(_GNU_SOURCE)
274
275 __fenv_static inline int
276 feenableexcept(int __mask)
277 {
278 fexcept_t __fpcr, __oldmask;
279
280 __get_fpcr(__fpcr);
281 __oldmask = (__fpcr >> 6) & FE_ALL_EXCEPT;
282 __fpcr |= (__mask & FE_ALL_EXCEPT) << 6;
283 __set_fpcr(__fpcr);
284
285 return __oldmask;
286 }
287
288 __fenv_static inline int
289 fedisableexcept(int __mask)
290 {
291 fexcept_t __fpcr, __oldmask;
292
293 __get_fpcr(__fpcr);
294 __oldmask = (__fpcr >> 6) & FE_ALL_EXCEPT;
295 __fpcr &= ~((__mask & FE_ALL_EXCEPT) << 6);
296 __set_fpcr(__fpcr);
297
298 return __oldmask;
299 }
300
301 __fenv_static inline int
302 fegetexcept(void)
303 {
304 fexcept_t __fpcr;
305
306 __get_fpcr(__fpcr);
307
308 return (__fpcr >> 6) & FE_ALL_EXCEPT;
309 }
310
311 #endif /* _NETBSD_SOURCE || _GNU_SOURCE */
312
313 __END_DECLS
314
315 #endif /* __HAVE_68881__ */
316
317 #endif /* _M68K_FENV_H_ */
318