1 /*        $NetBSD: fenv.h,v 1.7 2024/10/30 15:56:11 riastradh Exp $   */
2 
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: head/lib/msun/mips/fenv.h 226218 2011-10-10 15:43:09Z das $
29  */
30 
31 #ifndef   _MIPS_FENV_H_
32 #define   _MIPS_FENV_H_
33 
34 #include <sys/featuretest.h>
35 #include <sys/stdint.h>
36 
37 /* Exception flags */
38 #define   FE_INEXACT          0x0004
39 #define   FE_UNDERFLOW        0x0008
40 #define   FE_OVERFLOW         0x0010
41 #define   FE_DIVBYZERO        0x0020
42 #define   FE_INVALID          0x0040
43 #define   FE_ALL_EXCEPT       (FE_DIVBYZERO | FE_INEXACT | \
44                                FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW)
45 
46 /* Rounding modes */
47 #define   FE_TONEAREST        0x0000
48 #define   FE_TOWARDZERO       0x0001
49 #define   FE_UPWARD 0x0002
50 #define   FE_DOWNWARD         0x0003
51 #define   _ROUND_MASK         (FE_TONEAREST | FE_DOWNWARD | \
52                                FE_UPWARD | FE_TOWARDZERO)
53 
54 #ifndef __mips_soft_float
55 
56 #ifndef   __fenv_static
57 #define   __fenv_static       static
58 #endif
59 
60 typedef   uint32_t  fpu_control_t __attribute__((__mode__(__SI__)));
61 typedef   fpu_control_t       fenv_t;
62 typedef   fpu_control_t       fexcept_t;
63 
64 __BEGIN_DECLS
65 
66 /* Default floating-point environment */
67 extern const fenv_t __fe_dfl_env;
68 #define   FE_DFL_ENV          (&__fe_dfl_env)
69 
70 /* We need to be able to map status flag positions to mask flag positions */
71 #define   _ENABLE_MASK        (FE_ALL_EXCEPT << _ENABLE_SHIFT)
72 #define   _ENABLE_SHIFT    5
73 
74 static inline fpu_control_t
__rfs(void)75 __rfs(void)
76 {
77           fpu_control_t __fpsr;
78 
79           __asm __volatile("cfc1 %0,$31" : "=r" (__fpsr));
80           return __fpsr;
81 }
82 
83 static inline void
__wfs(fpu_control_t __fpsr)84 __wfs(fpu_control_t __fpsr)
85 {
86 
87           __asm __volatile("ctc1 %0,$31" : : "r" (__fpsr));
88 }
89 
90 #if __GNUC_PREREQ__(8, 0)
91 #pragma GCC diagnostic push
92 #pragma GCC diagnostic ignored "-Wshadow"
93 #endif
94 
95 __fenv_static inline int
feclearexcept(int __excepts)96 feclearexcept(int __excepts)
97 {
98           fexcept_t __fpsr;
99 
100           __excepts &= FE_ALL_EXCEPT;
101           __fpsr = __rfs();
102           __fpsr &= ~(__excepts | (__excepts << _ENABLE_SHIFT));
103           __wfs(__fpsr);
104           return 0;
105 }
106 
107 __fenv_static inline int
fegetexceptflag(fexcept_t * __flagp,int __excepts)108 fegetexceptflag(fexcept_t *__flagp, int __excepts)
109 {
110           fexcept_t __fpsr;
111 
112           __fpsr = __rfs();
113           *__flagp = __fpsr & __excepts;
114           return (0);
115 }
116 
117 __fenv_static inline int
fesetexceptflag(const fexcept_t * __flagp,int __excepts)118 fesetexceptflag(const fexcept_t *__flagp, int __excepts)
119 {
120           fexcept_t __fpsr;
121 
122           __fpsr = __rfs();
123           __fpsr &= ~__excepts;
124           __fpsr |= *__flagp & __excepts;
125           __wfs(__fpsr);
126           return (0);
127 }
128 
129 __fenv_static inline int
feraiseexcept(int __excepts)130 feraiseexcept(int __excepts)
131 {
132           fexcept_t __ex = __excepts;
133 
134           fesetexceptflag(&__ex, __excepts);      /* XXX */
135           return (0);
136 }
137 
138 __fenv_static inline int
fetestexcept(int __excepts)139 fetestexcept(int __excepts)
140 {
141           fexcept_t __fpsr;
142 
143           __fpsr = __rfs();
144           return (__fpsr & __excepts);
145 }
146 
147 __fenv_static inline int
fegetround(void)148 fegetround(void)
149 {
150           fexcept_t __fpsr;
151 
152           __fpsr = __rfs();
153           return __fpsr & _ROUND_MASK;
154 }
155 
156 __fenv_static inline int
fesetround(int __round)157 fesetround(int __round)
158 {
159           fexcept_t __fpsr;
160 
161           if (__round & ~_ROUND_MASK)
162                     return 1;
163           __fpsr = __rfs();
164           __fpsr &= ~_ROUND_MASK;
165           __fpsr |= __round;
166           __wfs(__fpsr);
167 
168           return 0;
169 }
170 
171 __fenv_static inline int
fegetenv(fenv_t * __envp)172 fegetenv(fenv_t *__envp)
173 {
174 
175           *__envp = __rfs();
176           return (0);
177 }
178 
179 __fenv_static inline int
feholdexcept(fenv_t * __envp)180 feholdexcept(fenv_t *__envp)
181 {
182           fenv_t __env;
183 
184           __env = __rfs();
185           *__envp = __env;
186           __env &= ~(FE_ALL_EXCEPT | _ENABLE_MASK);
187           __wfs(__env);
188           return (0);
189 }
190 
191 __fenv_static inline int
fesetenv(const fenv_t * __envp)192 fesetenv(const fenv_t *__envp)
193 {
194 
195           __wfs(*__envp);
196           return (0);
197 }
198 
199 __fenv_static inline int
feupdateenv(const fenv_t * __envp)200 feupdateenv(const fenv_t *__envp)
201 {
202           fexcept_t __fpsr;
203 
204           __fpsr = __rfs();
205           __wfs(*__envp);
206           feraiseexcept(__fpsr & FE_ALL_EXCEPT);
207           return (0);
208 }
209 
210 #if __GNUC_PREREQ__(8, 0)
211 #pragma GCC diagnostic pop
212 #endif
213 
214 #if defined(_NETBSD_SOURCE) || defined(_GNU_SOURCE)
215 
216 __fenv_static inline int
feenableexcept(int __excepts)217 feenableexcept(int __excepts)
218 {
219           fenv_t __old_fpsr, __new_fpsr;
220 
221           __new_fpsr = __rfs();
222           __old_fpsr = (__new_fpsr & _ENABLE_MASK) >> _ENABLE_SHIFT;
223           __excepts &= FE_ALL_EXCEPT;
224           __new_fpsr |= __excepts << _ENABLE_SHIFT;
225           __wfs(__new_fpsr);
226           return __old_fpsr;
227 }
228 
229 __fenv_static inline int
fedisableexcept(int __excepts)230 fedisableexcept(int __excepts)
231 {
232           fenv_t __old_fpsr, __new_fpsr;
233 
234           __new_fpsr = __rfs();
235           __old_fpsr = (__new_fpsr & _ENABLE_MASK) >> _ENABLE_SHIFT;
236           __excepts &= FE_ALL_EXCEPT;
237           __new_fpsr &= ~(__excepts << _ENABLE_SHIFT);
238           __wfs(__new_fpsr);
239           return __old_fpsr;
240 }
241 
242 __fenv_static inline int
fegetexcept(void)243 fegetexcept(void)
244 {
245           fenv_t __fpsr;
246 
247           __fpsr = __rfs();
248           return ((__fpsr & _ENABLE_MASK) >> _ENABLE_SHIFT);
249 }
250 
251 #endif /* _NETBSD_SOURCE || _GNU_SOURCE */
252 
253 __END_DECLS
254 
255 #endif /* __mips_soft_float */
256 
257 #endif    /* !_FENV_H_ */
258