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