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