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