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
feclearexcept(int __excepts)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
fegetexceptflag(fexcept_t * __flagp,int __excepts)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
fesetexceptflag(const fexcept_t * __flagp,int __excepts)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
feraiseexcept(int __excepts)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
fetestexcept(int __excepts)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
fegetround(void)162 fegetround(void)
163 {
164           fenv_t __fpsr;
165 
166           __stfpsr(&__fpsr);
167           return (__fpsr & _ROUND_MASK);
168 }
169 
170 __fenv_static inline int
fesetround(int __round)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
fegetenv(fenv_t * __envp)185 fegetenv(fenv_t *__envp)
186 {
187 
188           __stfpsr(__envp);
189           return (0);
190 }
191 
192 __fenv_static inline int
feholdexcept(fenv_t * __envp)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
fesetenv(const fenv_t * __envp)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
feenableexcept(int __mask)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
fedisableexcept(int __mask)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
fegetexcept(void)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