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