xref: /freebsd/lib/msun/arm/fenv.c (revision 9aff62dee28239f84b4aa4a3429cf26dbbf770cc)
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 const femode_t __fe_dfl_mode = 0;
47 #endif
48 
49 
50 /* If this is a non-mangled softfp version special processing is required */
51 #if defined(FENV_MANGLE) || !defined(SOFTFP_ABI)
52 
53 /*
54  * The following macros map between the softfloat emulator's flags and
55  * the hardware's FPSR.  The hardware this file was written for doesn't
56  * have rounding control bits, so we stick those in the system ID byte.
57  */
58 #ifndef __ARM_PCS_VFP
59 #define	__set_env(env, flags, mask, rnd) env = ((flags)			\
60 						| (mask)<<_FPUSW_SHIFT	\
61 						| (rnd) << 24)
62 #define	__env_flags(env)		((env) & FE_ALL_EXCEPT)
63 #define	__env_mask(env)			(((env) >> _FPUSW_SHIFT)	\
64 						& FE_ALL_EXCEPT)
65 #define	__env_round(env)		(((env) >> 24) & _ROUND_MASK)
66 #include "fenv-softfloat.h"
67 #endif
68 
69 int
70 (feclearexcept)(int excepts)
71 {
72 	return (__feclearexcept_int(excepts));
73 }
74 
75 int
76 (fegetexceptflag)(fexcept_t *flagp, int excepts)
77 {
78 	return (__fegetexceptflag_int(flagp, excepts));
79 }
80 
81 int
82 (fesetexceptflag)(const fexcept_t *flagp, int excepts)
83 {
84 	return (__fesetexceptflag_int(flagp, excepts));
85 }
86 
87 int
88 (feraiseexcept)(int excepts)
89 {
90 	return (__feraiseexcept_int(excepts));
91 }
92 
93 int
94 (fetestexcept)(int excepts)
95 {
96 	return (__fetestexcept_int(excepts));
97 }
98 
99 int
100 (fegetround)(void)
101 {
102 	return (__fegetround_int());
103 }
104 
105 int
106 (fesetround)(int round)
107 {
108 	return (__fesetround_int(round));
109 }
110 
111 int
112 (fegetmode)(femode_t *modep)
113 {
114 	return (__fegetmode_int(modep));
115 }
116 
117 int
118 (fesetmode)(const femode_t *modep)
119 {
120 	return (__fesetmode_int(modep));
121 }
122 
123 int
124 (fegetenv)(fenv_t *envp)
125 {
126 	return (__fegetenv_int(envp));
127 }
128 
129 int
130 (feholdexcept)(fenv_t *envp)
131 {
132 	return (__feholdexcept_int(envp));
133 }
134 
135 int
136 (fesetenv)(const fenv_t *envp)
137 {
138 	return (__fesetenv_int(envp));
139 }
140 
141 int
142 (feupdateenv)(const fenv_t *envp)
143 {
144 	return (__feupdateenv_int(envp));
145 }
146 
147 int
148 (feenableexcept)(int mask)
149 {
150 	return (__feenableexcept_int(mask));
151 }
152 
153 int
154 (fedisableexcept)(int mask)
155 {
156 	return (__fedisableexcept_int(mask));
157 }
158 
159 int
160 (fegetexcept)(void)
161 {
162 	return (__fegetexcept_int());
163 }
164 
165 #else /* !FENV_MANGLE && SOFTFP_ABI */
166 /* Set by libc when the VFP unit is enabled */
167 extern int _libc_arm_fpu_present;
168 
169 int __softfp_feclearexcept(int __excepts);
170 int __softfp_fegetexceptflag(fexcept_t *__flagp, int __excepts);
171 int __softfp_fesetexceptflag(const fexcept_t *__flagp, int __excepts);
172 int __softfp_feraiseexcept(int __excepts);
173 int __softfp_fetestexcept(int __excepts);
174 int __softfp_fegetround(void);
175 int __softfp_fesetround(int __round);
176 int __softfp_fegetmode(femode_t *__modep);
177 int __softfp_fesetmode(const femode_t *__modep);
178 int __softfp_fegetenv(fenv_t *__envp);
179 int __softfp_feholdexcept(fenv_t *__envp);
180 int __softfp_fesetenv(const fenv_t *__envp);
181 int __softfp_feupdateenv(const fenv_t *__envp);
182 int __softfp_feenableexcept(int __mask);
183 int __softfp_fedisableexcept(int __mask);
184 int __softfp_fegetexcept(void);
185 
186 int __vfp_feclearexcept(int __excepts);
187 int __vfp_fegetexceptflag(fexcept_t *__flagp, int __excepts);
188 int __vfp_fesetexceptflag(const fexcept_t *__flagp, int __excepts);
189 int __vfp_feraiseexcept(int __excepts);
190 int __vfp_fetestexcept(int __excepts);
191 int __vfp_fegetround(void);
192 int __vfp_fesetround(int __round);
193 int __vfp_fegetmode(femode_t *__modep);
194 int __vfp_fesetmode(const femode_t *__modep);
195 int __vfp_fegetenv(fenv_t *__envp);
196 int __vfp_feholdexcept(fenv_t *__envp);
197 int __vfp_fesetenv(const fenv_t *__envp);
198 int __vfp_feupdateenv(const fenv_t *__envp);
199 int __vfp_feenableexcept(int __mask);
200 int __vfp_fedisableexcept(int __mask);
201 int __vfp_fegetexcept(void);
202 
203 static int
204 __softfp_round_to_vfp(int round)
205 {
206 
207 	switch (round) {
208 	case FE_TONEAREST:
209 	default:
210 		return VFP_FE_TONEAREST;
211 	case FE_TOWARDZERO:
212 		return VFP_FE_TOWARDZERO;
213 	case FE_UPWARD:
214 		return VFP_FE_UPWARD;
215 	case FE_DOWNWARD:
216 		return VFP_FE_DOWNWARD;
217 	}
218 }
219 
220 static int
221 __softfp_round_from_vfp(int round)
222 {
223 
224 	switch (round) {
225 	case VFP_FE_TONEAREST:
226 	default:
227 		return FE_TONEAREST;
228 	case VFP_FE_TOWARDZERO:
229 		return FE_TOWARDZERO;
230 	case VFP_FE_UPWARD:
231 		return FE_UPWARD;
232 	case VFP_FE_DOWNWARD:
233 		return FE_DOWNWARD;
234 	}
235 }
236 
237 int
238 (feclearexcept)(int __excepts)
239 {
240 
241 	if (_libc_arm_fpu_present)
242 		__vfp_feclearexcept(__excepts);
243 	__softfp_feclearexcept(__excepts);
244 
245 	return (0);
246 }
247 
248 int
249 (fegetexceptflag)(fexcept_t *__flagp, int __excepts)
250 {
251 	fexcept_t __vfp_flagp;
252 
253 	__vfp_flagp = 0;
254 	if (_libc_arm_fpu_present)
255 		__vfp_fegetexceptflag(&__vfp_flagp, __excepts);
256 	__softfp_fegetexceptflag(__flagp, __excepts);
257 
258 	*__flagp |= __vfp_flagp;
259 
260 	return (0);
261 }
262 
263 int
264 (fesetexceptflag)(const fexcept_t *__flagp, int __excepts)
265 {
266 
267 	if (_libc_arm_fpu_present)
268 		__vfp_fesetexceptflag(__flagp, __excepts);
269 	__softfp_fesetexceptflag(__flagp, __excepts);
270 
271 	return (0);
272 }
273 
274 int
275 (feraiseexcept)(int __excepts)
276 {
277 
278 	if (_libc_arm_fpu_present)
279 		__vfp_feraiseexcept(__excepts);
280 	__softfp_feraiseexcept(__excepts);
281 
282 	return (0);
283 }
284 
285 int
286 (fetestexcept)(int __excepts)
287 {
288 	int __got_excepts;
289 
290 	__got_excepts = 0;
291 	if (_libc_arm_fpu_present)
292 		__got_excepts = __vfp_fetestexcept(__excepts);
293 	__got_excepts |= __softfp_fetestexcept(__excepts);
294 
295 	return (__got_excepts);
296 }
297 
298 int
299 (fegetround)(void)
300 {
301 
302 	if (_libc_arm_fpu_present)
303 		return __softfp_round_from_vfp(__vfp_fegetround());
304 	return __softfp_fegetround();
305 }
306 
307 int
308 (fesetround)(int __round)
309 {
310 
311 	if (_libc_arm_fpu_present)
312 		__vfp_fesetround(__softfp_round_to_vfp(__round));
313 	__softfp_fesetround(__round);
314 
315 	return (0);
316 }
317 
318 int
319 (fegetmode)(femode_t *__modep)
320 {
321 	femode_t __vfp_modep;
322 
323 	__vfp_modep = 0;
324 	if (_libc_arm_fpu_present)
325 		__vfp_fegetmode(&__vfp_modep);
326 	__softfp_fegetmode(__modep);
327 	*__modep |= __vfp_modep;
328 
329 	return (0);
330 }
331 
332 int
333 (fesetmode)(const femode_t *__modep)
334 {
335 
336 	if (_libc_arm_fpu_present)
337 		__vfp_fesetmode(__modep);
338 	__softfp_fesetmode(__modep);
339 
340 	return (0);
341 }
342 
343 int
344 (fegetenv)(fenv_t *__envp)
345 {
346 	fenv_t __vfp_envp;
347 
348 	__vfp_envp = 0;
349 	if (_libc_arm_fpu_present)
350 		__vfp_fegetenv(&__vfp_envp);
351 	__softfp_fegetenv(__envp);
352 	*__envp |= __vfp_envp;
353 
354 	return (0);
355 }
356 
357 int
358 (feholdexcept)(fenv_t *__envp)
359 {
360 	fenv_t __vfp_envp;
361 
362 	__vfp_envp = 0;
363 	if (_libc_arm_fpu_present)
364 		__vfp_feholdexcept(&__vfp_envp);
365 	__softfp_feholdexcept(__envp);
366 	*__envp |= __vfp_envp;
367 
368 	return (0);
369 }
370 
371 int
372 (fesetenv)(const fenv_t *__envp)
373 {
374 
375 	if (_libc_arm_fpu_present)
376 		__vfp_fesetenv(__envp);
377 	__softfp_fesetenv(__envp);
378 
379 	return (0);
380 }
381 
382 int
383 (feupdateenv)(const fenv_t *__envp)
384 {
385 
386 	if (_libc_arm_fpu_present)
387 		__vfp_feupdateenv(__envp);
388 	__softfp_feupdateenv(__envp);
389 
390 	return (0);
391 }
392 
393 int
394 (feenableexcept)(int __mask)
395 {
396 	int __unmasked;
397 
398 	__unmasked = 0;
399 	if (_libc_arm_fpu_present)
400 		__unmasked = __vfp_feenableexcept(__mask);
401 	__unmasked |= __softfp_feenableexcept(__mask);
402 
403 	return (__unmasked);
404 }
405 
406 int
407 (fedisableexcept)(int __mask)
408 {
409 	int __unmasked;
410 
411 	__unmasked = 0;
412 	if (_libc_arm_fpu_present)
413 		__unmasked = __vfp_fedisableexcept(__mask);
414 	__unmasked |= __softfp_fedisableexcept(__mask);
415 
416 	return (__unmasked);
417 }
418 
419 int
420 (fegetexcept)(void)
421 {
422 	int __unmasked;
423 
424 	__unmasked = 0;
425 	if (_libc_arm_fpu_present)
426 		__unmasked = __vfp_fegetexcept();
427 	__unmasked |= __softfp_fegetexcept();
428 
429 	return (__unmasked);
430 }
431 
432 #endif
433