xref: /netbsd-src/sys/arch/ia64/include/fenv.h (revision cddc78ea67e20759c213d3f50ea3bd06ade17338)
1 /*-
2  * Copyright (c) 2004-2005 David Schultz <das@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