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