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