xref: /haiku/headers/posix/arch/sparc64/fenv.h (revision 13581b3d2a71545960b98fefebc5225b5bf29072)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2004-2005 David Schultz <das@FreeBSD.ORG>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  *
28  * $FreeBSD$
29  */
30 
31 #ifndef	_FENV_H_
32 #define	_FENV_H_
33 
34 #include <stdint.h>
35 #include <sys/cdefs.h>
36 #include <sys/types.h>
37 
38 #ifndef	__fenv_static
39 #define	__fenv_static	static
40 #endif
41 
42 typedef	uint64_t	fenv_t;
43 typedef	uint64_t	fexcept_t;
44 
45 /* Exception flags */
46 #define	FE_INVALID	0x00000200
47 #define	FE_DIVBYZERO	0x00000040
48 #define	FE_OVERFLOW	0x00000100
49 #define	FE_UNDERFLOW	0x00000080
50 #define	FE_INEXACT	0x00000020
51 #define	FE_ALL_EXCEPT	(FE_DIVBYZERO | FE_INEXACT | \
52 			 FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW)
53 
54 /*
55  * Rounding modes
56  *
57  * We can't just use the hardware bit values here, because that would
58  * make FE_UPWARD and FE_DOWNWARD negative, which is not allowed.
59  */
60 #define	FE_TONEAREST	0x0
61 #define	FE_TOWARDZERO	0x1
62 #define	FE_UPWARD	0x2
63 #define	FE_DOWNWARD	0x3
64 #define	_ROUND_MASK	(FE_TONEAREST | FE_DOWNWARD | \
65 			 FE_UPWARD | FE_TOWARDZERO)
66 #define	_ROUND_SHIFT	30
67 
68 __BEGIN_DECLS
69 
70 /* Default floating-point environment */
71 extern const fenv_t	__fe_dfl_env;
72 #define	FE_DFL_ENV	(&__fe_dfl_env)
73 
74 /* We need to be able to map status flag positions to mask flag positions */
75 #define _FPUSW_SHIFT	18
76 #define	_ENABLE_MASK	(FE_ALL_EXCEPT << _FPUSW_SHIFT)
77 
78 #define	__ldxfsr(__r)	__asm __volatile("ldx %0, %%fsr" : : "m" (__r))
79 #define	__stxfsr(__r)	__asm __volatile("stx %%fsr, %0" : "=m" (*(__r)))
80 
81 __fenv_static __inline int
82 feclearexcept(int __excepts)
83 {
84 	fexcept_t __r;
85 
86 	__stxfsr(&__r);
87 	__r &= ~__excepts;
88 	__ldxfsr(__r);
89 	return (0);
90 }
91 
92 __fenv_static inline int
93 fegetexceptflag(fexcept_t *__flagp, int __excepts)
94 {
95 	fexcept_t __r;
96 
97 	__stxfsr(&__r);
98 	*__flagp = __r & __excepts;
99 	return (0);
100 }
101 
102 __fenv_static inline int
103 fesetexceptflag(const fexcept_t *__flagp, int __excepts)
104 {
105 	fexcept_t __r;
106 
107 	__stxfsr(&__r);
108 	__r &= ~__excepts;
109 	__r |= *__flagp & __excepts;
110 	__ldxfsr(__r);
111 	return (0);
112 }
113 
114 /*
115  * It seems to be worthwhile to inline this function even when the
116  * arguments are not compile-time constants.  Perhaps this depends
117  * on the register window.
118  */
119 __fenv_static inline int
120 feraiseexcept(int __excepts)
121 {
122 	volatile double d;
123 
124 	/*
125 	 * With a compiler that supports the FENV_ACCESS pragma
126 	 * properly, simple expressions like '0.0 / 0.0' should
127 	 * be sufficient to generate traps.  Unfortunately, we
128 	 * need to bring a volatile variable into the equation
129 	 * to prevent incorrect optimizations.
130 	 */
131 	if (__excepts & FE_INVALID) {
132 		d = 0.0;
133 		d = 0.0 / d;
134 	}
135 	if (__excepts & FE_DIVBYZERO) {
136 		d = 0.0;
137 		d = 1.0 / d;
138 	}
139 	if (__excepts & FE_OVERFLOW) {
140 		d = 0x1.ffp1023;
141 		d *= 2.0;
142 	}
143 	if (__excepts & FE_UNDERFLOW) {
144 		d = 0x1p-1022;
145 		d /= 0x1p1023;
146 	}
147 	if (__excepts & FE_INEXACT) {
148 		d = 0x1p-1022;
149 		d += 1.0;
150 	}
151 	return (0);
152 }
153 
154 __fenv_static inline int
155 fetestexcept(int __excepts)
156 {
157 	fexcept_t __r;
158 
159 	__stxfsr(&__r);
160 	return (__r & __excepts);
161 }
162 
163 __fenv_static inline int
164 fegetround(void)
165 {
166 	fenv_t __r;
167 
168 	__stxfsr(&__r);
169 	return ((__r >> _ROUND_SHIFT) & _ROUND_MASK);
170 }
171 
172 __fenv_static inline int
173 fesetround(int __round)
174 {
175 	fenv_t __r;
176 
177 	if (__round & ~_ROUND_MASK)
178 		return (-1);
179 	__stxfsr(&__r);
180 	__r &= ~(_ROUND_MASK << _ROUND_SHIFT);
181 	__r |= __round << _ROUND_SHIFT;
182 	__ldxfsr(__r);
183 	return (0);
184 }
185 
186 __fenv_static inline int
187 fegetenv(fenv_t *__envp)
188 {
189 
190 	__stxfsr(__envp);
191 	return (0);
192 }
193 
194 __fenv_static inline int
195 feholdexcept(fenv_t *__envp)
196 {
197 	fenv_t __r;
198 
199 	__stxfsr(&__r);
200 	*__envp = __r;
201 	__r &= ~(FE_ALL_EXCEPT | _ENABLE_MASK);
202 	__ldxfsr(__r);
203 	return (0);
204 }
205 
206 __fenv_static inline int
207 fesetenv(const fenv_t *__envp)
208 {
209 
210 	__ldxfsr(*__envp);
211 	return (0);
212 }
213 
214 __fenv_static inline int
215 feupdateenv(const fenv_t *__envp)
216 {
217 	fexcept_t __r;
218 
219 	__stxfsr(&__r);
220 	__ldxfsr(*__envp);
221 	feraiseexcept(__r & FE_ALL_EXCEPT);
222 	return (0);
223 }
224 
225 #if __BSD_VISIBLE
226 
227 /* We currently provide no external definitions of the functions below. */
228 
229 static inline int
230 feenableexcept(int __mask)
231 {
232 	fenv_t __old_r, __new_r;
233 
234 	__stxfsr(&__old_r);
235 	__new_r = __old_r | ((__mask & FE_ALL_EXCEPT) << _FPUSW_SHIFT);
236 	__ldxfsr(__new_r);
237 	return ((__old_r >> _FPUSW_SHIFT) & FE_ALL_EXCEPT);
238 }
239 
240 static inline int
241 fedisableexcept(int __mask)
242 {
243 	fenv_t __old_r, __new_r;
244 
245 	__stxfsr(&__old_r);
246 	__new_r = __old_r & ~((__mask & FE_ALL_EXCEPT) << _FPUSW_SHIFT);
247 	__ldxfsr(__new_r);
248 	return ((__old_r >> _FPUSW_SHIFT) & FE_ALL_EXCEPT);
249 }
250 
251 static inline int
252 fegetexcept(void)
253 {
254 	fenv_t __r;
255 
256 	__stxfsr(&__r);
257 	return ((__r & _ENABLE_MASK) >> _FPUSW_SHIFT);
258 }
259 
260 #endif /* __BSD_VISIBLE */
261 
262 __END_DECLS
263 
264 #endif	/* !_FENV_H_ */
265