xref: /freebsd/lib/msun/arm/fenv.c (revision 3a92d97ff0f22d21608e1c19b83104c4937523b6)
1 /*-
2  * Copyright (c) 2004 David Schultz <das@FreeBSD.ORG>
3  * Copyright (c) 2013 Andrew Turner <andrew@FreeBSD.ORG>
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  * $FreeBSD$
28  */
29 
30 #define	__fenv_static
31 #include "fenv.h"
32 
33 /* When SOFTFP_ABI is defined we are using the softfp ABI. */
34 #if defined(__VFP_FP__) && !defined(__ARM_PCS_VFP)
35 #define SOFTFP_ABI
36 #endif
37 
38 
39 #ifndef FENV_MANGLE
40 /*
41  * Hopefully the system ID byte is immutable, so it's valid to use
42  * this as a default environment.
43  */
44 const fenv_t __fe_dfl_env = 0;
45 #endif
46 
47 
48 /* If this is a non-mangled softfp version special processing is required */
49 #if defined(FENV_MANGLE) || !defined(SOFTFP_ABI)
50 
51 /*
52  * The following macros map between the softfloat emulator's flags and
53  * the hardware's FPSR.  The hardware this file was written for doesn't
54  * have rounding control bits, so we stick those in the system ID byte.
55  */
56 #ifndef __ARM_PCS_VFP
57 #define	__set_env(env, flags, mask, rnd) env = ((flags)			\
58 						| (mask)<<_FPUSW_SHIFT	\
59 						| (rnd) << 24)
60 #define	__env_flags(env)		((env) & FE_ALL_EXCEPT)
61 #define	__env_mask(env)			(((env) >> _FPUSW_SHIFT)	\
62 						& FE_ALL_EXCEPT)
63 #define	__env_round(env)		(((env) >> 24) & _ROUND_MASK)
64 #include "fenv-softfloat.h"
65 #endif
66 
67 #ifdef __GNUC_GNU_INLINE__
68 #error "This file must be compiled with C99 'inline' semantics"
69 #endif
70 
71 extern inline int feclearexcept(int __excepts);
72 extern inline int fegetexceptflag(fexcept_t *__flagp, int __excepts);
73 extern inline int fesetexceptflag(const fexcept_t *__flagp, int __excepts);
74 extern inline int feraiseexcept(int __excepts);
75 extern inline int fetestexcept(int __excepts);
76 extern inline int fegetround(void);
77 extern inline int fesetround(int __round);
78 extern inline int fegetenv(fenv_t *__envp);
79 extern inline int feholdexcept(fenv_t *__envp);
80 extern inline int fesetenv(const fenv_t *__envp);
81 extern inline int feupdateenv(const fenv_t *__envp);
82 extern inline int feenableexcept(int __mask);
83 extern inline int fedisableexcept(int __mask);
84 extern inline int fegetexcept(void);
85 
86 #else /* !FENV_MANGLE && SOFTFP_ABI */
87 /* Set by libc when the VFP unit is enabled */
88 extern int _libc_arm_fpu_present;
89 
90 int __softfp_feclearexcept(int __excepts);
91 int __softfp_fegetexceptflag(fexcept_t *__flagp, int __excepts);
92 int __softfp_fesetexceptflag(const fexcept_t *__flagp, int __excepts);
93 int __softfp_feraiseexcept(int __excepts);
94 int __softfp_fetestexcept(int __excepts);
95 int __softfp_fegetround(void);
96 int __softfp_fesetround(int __round);
97 int __softfp_fegetenv(fenv_t *__envp);
98 int __softfp_feholdexcept(fenv_t *__envp);
99 int __softfp_fesetenv(const fenv_t *__envp);
100 int __softfp_feupdateenv(const fenv_t *__envp);
101 int __softfp_feenableexcept(int __mask);
102 int __softfp_fedisableexcept(int __mask);
103 int __softfp_fegetexcept(void);
104 
105 int __vfp_feclearexcept(int __excepts);
106 int __vfp_fegetexceptflag(fexcept_t *__flagp, int __excepts);
107 int __vfp_fesetexceptflag(const fexcept_t *__flagp, int __excepts);
108 int __vfp_feraiseexcept(int __excepts);
109 int __vfp_fetestexcept(int __excepts);
110 int __vfp_fegetround(void);
111 int __vfp_fesetround(int __round);
112 int __vfp_fegetenv(fenv_t *__envp);
113 int __vfp_feholdexcept(fenv_t *__envp);
114 int __vfp_fesetenv(const fenv_t *__envp);
115 int __vfp_feupdateenv(const fenv_t *__envp);
116 int __vfp_feenableexcept(int __mask);
117 int __vfp_fedisableexcept(int __mask);
118 int __vfp_fegetexcept(void);
119 
120 static int
121 __softfp_round_to_vfp(int round)
122 {
123 
124 	switch (round) {
125 	case FE_TONEAREST:
126 	default:
127 		return VFP_FE_TONEAREST;
128 	case FE_TOWARDZERO:
129 		return VFP_FE_TOWARDZERO;
130 	case FE_UPWARD:
131 		return VFP_FE_UPWARD;
132 	case FE_DOWNWARD:
133 		return VFP_FE_DOWNWARD;
134 	}
135 }
136 
137 static int
138 __softfp_round_from_vfp(int round)
139 {
140 
141 	switch (round) {
142 	case VFP_FE_TONEAREST:
143 	default:
144 		return FE_TONEAREST;
145 	case VFP_FE_TOWARDZERO:
146 		return FE_TOWARDZERO;
147 	case VFP_FE_UPWARD:
148 		return FE_UPWARD;
149 	case VFP_FE_DOWNWARD:
150 		return FE_DOWNWARD;
151 	}
152 }
153 
154 int feclearexcept(int __excepts)
155 {
156 
157 	if (_libc_arm_fpu_present)
158 		__vfp_feclearexcept(__excepts);
159 	__softfp_feclearexcept(__excepts);
160 
161 	return (0);
162 }
163 
164 int fegetexceptflag(fexcept_t *__flagp, int __excepts)
165 {
166 	fexcept_t __vfp_flagp;
167 
168 	__vfp_flagp = 0;
169 	if (_libc_arm_fpu_present)
170 		__vfp_fegetexceptflag(&__vfp_flagp, __excepts);
171 	__softfp_fegetexceptflag(__flagp, __excepts);
172 
173 	*__flagp |= __vfp_flagp;
174 
175 	return (0);
176 }
177 
178 int fesetexceptflag(const fexcept_t *__flagp, int __excepts)
179 {
180 
181 	if (_libc_arm_fpu_present)
182 		__vfp_fesetexceptflag(__flagp, __excepts);
183 	__softfp_fesetexceptflag(__flagp, __excepts);
184 
185 	return (0);
186 }
187 
188 int feraiseexcept(int __excepts)
189 {
190 
191 	if (_libc_arm_fpu_present)
192 		__vfp_feraiseexcept(__excepts);
193 	__softfp_feraiseexcept(__excepts);
194 
195 	return (0);
196 }
197 
198 int fetestexcept(int __excepts)
199 {
200 	int __got_excepts;
201 
202 	__got_excepts = 0;
203 	if (_libc_arm_fpu_present)
204 		__got_excepts = __vfp_fetestexcept(__excepts);
205 	__got_excepts |= __softfp_fetestexcept(__excepts);
206 
207 	return (__got_excepts);
208 }
209 
210 int fegetround(void)
211 {
212 
213 	if (_libc_arm_fpu_present)
214 		return __softfp_round_from_vfp(__vfp_fegetround());
215 	return __softfp_fegetround();
216 }
217 
218 int fesetround(int __round)
219 {
220 
221 	if (_libc_arm_fpu_present)
222 		__vfp_fesetround(__softfp_round_to_vfp(__round));
223 	__softfp_fesetround(__round);
224 
225 	return (0);
226 }
227 
228 int fegetenv(fenv_t *__envp)
229 {
230 	fenv_t __vfp_envp;
231 
232 	__vfp_envp = 0;
233 	if (_libc_arm_fpu_present)
234 		__vfp_fegetenv(&__vfp_envp);
235 	__softfp_fegetenv(__envp);
236 	*__envp |= __vfp_envp;
237 
238 	return (0);
239 }
240 
241 int feholdexcept(fenv_t *__envp)
242 {
243 	fenv_t __vfp_envp;
244 
245 	__vfp_envp = 0;
246 	if (_libc_arm_fpu_present)
247 		__vfp_feholdexcept(&__vfp_envp);
248 	__softfp_feholdexcept(__envp);
249 	*__envp |= __vfp_envp;
250 
251 	return (0);
252 }
253 
254 int fesetenv(const fenv_t *__envp)
255 {
256 
257 	if (_libc_arm_fpu_present)
258 		__vfp_fesetenv(__envp);
259 	__softfp_fesetenv(__envp);
260 
261 	return (0);
262 }
263 
264 int feupdateenv(const fenv_t *__envp)
265 {
266 
267 	if (_libc_arm_fpu_present)
268 		__vfp_feupdateenv(__envp);
269 	__softfp_feupdateenv(__envp);
270 
271 	return (0);
272 }
273 
274 int feenableexcept(int __mask)
275 {
276 	int __unmasked;
277 
278 	__unmasked = 0;
279 	if (_libc_arm_fpu_present)
280 		__unmasked = __vfp_feenableexcept(__mask);
281 	__unmasked |= __softfp_feenableexcept(__mask);
282 
283 	return (__unmasked);
284 }
285 
286 int fedisableexcept(int __mask)
287 {
288 	int __unmasked;
289 
290 	__unmasked = 0;
291 	if (_libc_arm_fpu_present)
292 		__unmasked = __vfp_fedisableexcept(__mask);
293 	__unmasked |= __softfp_fedisableexcept(__mask);
294 
295 	return (__unmasked);
296 }
297 
298 int fegetexcept(void)
299 {
300 	int __unmasked;
301 
302 	__unmasked = 0;
303 	if (_libc_arm_fpu_present)
304 		__unmasked = __vfp_fegetexcept();
305 	__unmasked |= __softfp_fegetexcept();
306 
307 	return (__unmasked);
308 }
309 
310 #endif
311 
312