xref: /freebsd/lib/msun/arm/fenv.c (revision 7d8f797b725e3efc0a4256554654780df83c456c)
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 #include <machine/acle-compat.h>
34 
35 #if __ARM_ARCH >= 6
36 #define FENV_ARMv6
37 #endif
38 
39 /* When SOFTFP_ABI is defined we are using the softfp ABI. */
40 #if defined(__VFP_FP__) && !defined(__ARM_PCS_VFP)
41 #define SOFTFP_ABI
42 #endif
43 
44 
45 #ifndef FENV_MANGLE
46 /*
47  * Hopefully the system ID byte is immutable, so it's valid to use
48  * this as a default environment.
49  */
50 const fenv_t __fe_dfl_env = 0;
51 #endif
52 
53 
54 /* If this is a non-mangled softfp version special processing is required */
55 #if defined(FENV_MANGLE) || !defined(SOFTFP_ABI) || !defined(FENV_ARMv6)
56 
57 /*
58  * The following macros map between the softfloat emulator's flags and
59  * the hardware's FPSR.  The hardware this file was written for doesn't
60  * have rounding control bits, so we stick those in the system ID byte.
61  */
62 #ifndef __ARM_PCS_VFP
63 #define	__set_env(env, flags, mask, rnd) env = ((flags)			\
64 						| (mask)<<_FPUSW_SHIFT	\
65 						| (rnd) << 24)
66 #define	__env_flags(env)		((env) & FE_ALL_EXCEPT)
67 #define	__env_mask(env)			(((env) >> _FPUSW_SHIFT)	\
68 						& FE_ALL_EXCEPT)
69 #define	__env_round(env)		(((env) >> 24) & _ROUND_MASK)
70 #include "fenv-softfloat.h"
71 #endif
72 
73 #ifdef __GNUC_GNU_INLINE__
74 #error "This file must be compiled with C99 'inline' semantics"
75 #endif
76 
77 extern inline int feclearexcept(int __excepts);
78 extern inline int fegetexceptflag(fexcept_t *__flagp, int __excepts);
79 extern inline int fesetexceptflag(const fexcept_t *__flagp, int __excepts);
80 extern inline int feraiseexcept(int __excepts);
81 extern inline int fetestexcept(int __excepts);
82 extern inline int fegetround(void);
83 extern inline int fesetround(int __round);
84 extern inline int fegetenv(fenv_t *__envp);
85 extern inline int feholdexcept(fenv_t *__envp);
86 extern inline int fesetenv(const fenv_t *__envp);
87 extern inline int feupdateenv(const fenv_t *__envp);
88 extern inline int feenableexcept(int __mask);
89 extern inline int fedisableexcept(int __mask);
90 extern inline int fegetexcept(void);
91 
92 #else /* !FENV_MANGLE && SOFTFP_ABI */
93 /* Set by libc when the VFP unit is enabled */
94 extern int _libc_arm_fpu_present;
95 
96 int __softfp_feclearexcept(int __excepts);
97 int __softfp_fegetexceptflag(fexcept_t *__flagp, int __excepts);
98 int __softfp_fesetexceptflag(const fexcept_t *__flagp, int __excepts);
99 int __softfp_feraiseexcept(int __excepts);
100 int __softfp_fetestexcept(int __excepts);
101 int __softfp_fegetround(void);
102 int __softfp_fesetround(int __round);
103 int __softfp_fegetenv(fenv_t *__envp);
104 int __softfp_feholdexcept(fenv_t *__envp);
105 int __softfp_fesetenv(const fenv_t *__envp);
106 int __softfp_feupdateenv(const fenv_t *__envp);
107 int __softfp_feenableexcept(int __mask);
108 int __softfp_fedisableexcept(int __mask);
109 int __softfp_fegetexcept(void);
110 
111 int __vfp_feclearexcept(int __excepts);
112 int __vfp_fegetexceptflag(fexcept_t *__flagp, int __excepts);
113 int __vfp_fesetexceptflag(const fexcept_t *__flagp, int __excepts);
114 int __vfp_feraiseexcept(int __excepts);
115 int __vfp_fetestexcept(int __excepts);
116 int __vfp_fegetround(void);
117 int __vfp_fesetround(int __round);
118 int __vfp_fegetenv(fenv_t *__envp);
119 int __vfp_feholdexcept(fenv_t *__envp);
120 int __vfp_fesetenv(const fenv_t *__envp);
121 int __vfp_feupdateenv(const fenv_t *__envp);
122 int __vfp_feenableexcept(int __mask);
123 int __vfp_fedisableexcept(int __mask);
124 int __vfp_fegetexcept(void);
125 
126 static int
127 __softfp_round_to_vfp(int round)
128 {
129 
130 	switch (round) {
131 	case FE_TONEAREST:
132 	default:
133 		return VFP_FE_TONEAREST;
134 	case FE_TOWARDZERO:
135 		return VFP_FE_TOWARDZERO;
136 	case FE_UPWARD:
137 		return VFP_FE_UPWARD;
138 	case FE_DOWNWARD:
139 		return VFP_FE_DOWNWARD;
140 	}
141 }
142 
143 static int
144 __softfp_round_from_vfp(int round)
145 {
146 
147 	switch (round) {
148 	case VFP_FE_TONEAREST:
149 	default:
150 		return FE_TONEAREST;
151 	case VFP_FE_TOWARDZERO:
152 		return FE_TOWARDZERO;
153 	case VFP_FE_UPWARD:
154 		return FE_UPWARD;
155 	case VFP_FE_DOWNWARD:
156 		return FE_DOWNWARD;
157 	}
158 }
159 
160 int feclearexcept(int __excepts)
161 {
162 
163 	if (_libc_arm_fpu_present)
164 		__vfp_feclearexcept(__excepts);
165 	__softfp_feclearexcept(__excepts);
166 
167 	return (0);
168 }
169 
170 int fegetexceptflag(fexcept_t *__flagp, int __excepts)
171 {
172 	fexcept_t __vfp_flagp;
173 
174 	__vfp_flagp = 0;
175 	if (_libc_arm_fpu_present)
176 		__vfp_fegetexceptflag(&__vfp_flagp, __excepts);
177 	__softfp_fegetexceptflag(__flagp, __excepts);
178 
179 	*__flagp |= __vfp_flagp;
180 
181 	return (0);
182 }
183 
184 int fesetexceptflag(const fexcept_t *__flagp, int __excepts)
185 {
186 
187 	if (_libc_arm_fpu_present)
188 		__vfp_fesetexceptflag(__flagp, __excepts);
189 	__softfp_fesetexceptflag(__flagp, __excepts);
190 
191 	return (0);
192 }
193 
194 int feraiseexcept(int __excepts)
195 {
196 
197 	if (_libc_arm_fpu_present)
198 		__vfp_feraiseexcept(__excepts);
199 	__softfp_feraiseexcept(__excepts);
200 
201 	return (0);
202 }
203 
204 int fetestexcept(int __excepts)
205 {
206 	int __got_excepts;
207 
208 	__got_excepts = 0;
209 	if (_libc_arm_fpu_present)
210 		__got_excepts = __vfp_fetestexcept(__excepts);
211 	__got_excepts |= __softfp_fetestexcept(__excepts);
212 
213 	return (__got_excepts);
214 }
215 
216 int fegetround(void)
217 {
218 
219 	if (_libc_arm_fpu_present)
220 		return __softfp_round_from_vfp(__vfp_fegetround());
221 	return __softfp_fegetround();
222 }
223 
224 int fesetround(int __round)
225 {
226 
227 	if (_libc_arm_fpu_present)
228 		__vfp_fesetround(__softfp_round_to_vfp(__round));
229 	__softfp_fesetround(__round);
230 
231 	return (0);
232 }
233 
234 int fegetenv(fenv_t *__envp)
235 {
236 	fenv_t __vfp_envp;
237 
238 	__vfp_envp = 0;
239 	if (_libc_arm_fpu_present)
240 		__vfp_fegetenv(&__vfp_envp);
241 	__softfp_fegetenv(__envp);
242 	*__envp |= __vfp_envp;
243 
244 	return (0);
245 }
246 
247 int feholdexcept(fenv_t *__envp)
248 {
249 	fenv_t __vfp_envp;
250 
251 	__vfp_envp = 0;
252 	if (_libc_arm_fpu_present)
253 		__vfp_feholdexcept(&__vfp_envp);
254 	__softfp_feholdexcept(__envp);
255 	*__envp |= __vfp_envp;
256 
257 	return (0);
258 }
259 
260 int fesetenv(const fenv_t *__envp)
261 {
262 
263 	if (_libc_arm_fpu_present)
264 		__vfp_fesetenv(__envp);
265 	__softfp_fesetenv(__envp);
266 
267 	return (0);
268 }
269 
270 int feupdateenv(const fenv_t *__envp)
271 {
272 
273 	if (_libc_arm_fpu_present)
274 		__vfp_feupdateenv(__envp);
275 	__softfp_feupdateenv(__envp);
276 
277 	return (0);
278 }
279 
280 int feenableexcept(int __mask)
281 {
282 	int __unmasked;
283 
284 	__unmasked = 0;
285 	if (_libc_arm_fpu_present)
286 		__unmasked = __vfp_feenableexcept(__mask);
287 	__unmasked |= __softfp_feenableexcept(__mask);
288 
289 	return (__unmasked);
290 }
291 
292 int fedisableexcept(int __mask)
293 {
294 	int __unmasked;
295 
296 	__unmasked = 0;
297 	if (_libc_arm_fpu_present)
298 		__unmasked = __vfp_fedisableexcept(__mask);
299 	__unmasked |= __softfp_fedisableexcept(__mask);
300 
301 	return (__unmasked);
302 }
303 
304 int fegetexcept(void)
305 {
306 	int __unmasked;
307 
308 	__unmasked = 0;
309 	if (_libc_arm_fpu_present)
310 		__unmasked = __vfp_fegetexcept();
311 	__unmasked |= __softfp_fegetexcept();
312 
313 	return (__unmasked);
314 }
315 
316 #endif
317 
318