xref: /freebsd/lib/msun/aarch64/fenv.h (revision b3e7694832e81d7a904a10f525f8797b753bf0d3)
18daa8167SAndrew Turner /*-
28daa8167SAndrew Turner  * Copyright (c) 2004-2005 David Schultz <das@FreeBSD.ORG>
38daa8167SAndrew Turner  * All rights reserved.
48daa8167SAndrew Turner  *
58daa8167SAndrew Turner  * Redistribution and use in source and binary forms, with or without
68daa8167SAndrew Turner  * modification, are permitted provided that the following conditions
78daa8167SAndrew Turner  * are met:
88daa8167SAndrew Turner  * 1. Redistributions of source code must retain the above copyright
98daa8167SAndrew Turner  *    notice, this list of conditions and the following disclaimer.
108daa8167SAndrew Turner  * 2. Redistributions in binary form must reproduce the above copyright
118daa8167SAndrew Turner  *    notice, this list of conditions and the following disclaimer in the
128daa8167SAndrew Turner  *    documentation and/or other materials provided with the distribution.
138daa8167SAndrew Turner  *
148daa8167SAndrew Turner  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
158daa8167SAndrew Turner  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
168daa8167SAndrew Turner  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
178daa8167SAndrew Turner  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
188daa8167SAndrew Turner  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
198daa8167SAndrew Turner  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
208daa8167SAndrew Turner  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
218daa8167SAndrew Turner  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
228daa8167SAndrew Turner  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
238daa8167SAndrew Turner  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
248daa8167SAndrew Turner  * SUCH DAMAGE.
258daa8167SAndrew Turner  */
268daa8167SAndrew Turner 
27*d5d97bedSMike Karels #ifdef __arm__
28*d5d97bedSMike Karels #include <arm/fenv.h>
29*d5d97bedSMike Karels #else /* __arm__ */
30*d5d97bedSMike Karels 
318daa8167SAndrew Turner #ifndef	_FENV_H_
328daa8167SAndrew Turner #define	_FENV_H_
338daa8167SAndrew Turner 
348daa8167SAndrew Turner #include <sys/_types.h>
358daa8167SAndrew Turner 
368daa8167SAndrew Turner #ifndef	__fenv_static
378daa8167SAndrew Turner #define	__fenv_static	static
388daa8167SAndrew Turner #endif
398daa8167SAndrew Turner 
4034cc08e3SAlex Richardson /* The high 32 bits contain fpcr, low 32 contain fpsr. */
418daa8167SAndrew Turner typedef	__uint64_t	fenv_t;
428daa8167SAndrew Turner typedef	__uint64_t	fexcept_t;
438daa8167SAndrew Turner 
448daa8167SAndrew Turner /* Exception flags */
458daa8167SAndrew Turner #define	FE_INVALID	0x00000001
468daa8167SAndrew Turner #define	FE_DIVBYZERO	0x00000002
478daa8167SAndrew Turner #define	FE_OVERFLOW	0x00000004
488daa8167SAndrew Turner #define	FE_UNDERFLOW	0x00000008
498daa8167SAndrew Turner #define	FE_INEXACT	0x00000010
508daa8167SAndrew Turner #define	FE_ALL_EXCEPT	(FE_DIVBYZERO | FE_INEXACT | \
518daa8167SAndrew Turner 			 FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW)
528daa8167SAndrew Turner 
538daa8167SAndrew Turner /*
548daa8167SAndrew Turner  * Rounding modes
558daa8167SAndrew Turner  *
568daa8167SAndrew Turner  * We can't just use the hardware bit values here, because that would
578daa8167SAndrew Turner  * make FE_UPWARD and FE_DOWNWARD negative, which is not allowed.
588daa8167SAndrew Turner  */
598daa8167SAndrew Turner #define	FE_TONEAREST	0x0
608daa8167SAndrew Turner #define	FE_UPWARD	0x1
618daa8167SAndrew Turner #define	FE_DOWNWARD	0x2
628daa8167SAndrew Turner #define	FE_TOWARDZERO	0x3
638daa8167SAndrew Turner #define	_ROUND_MASK	(FE_TONEAREST | FE_DOWNWARD | \
648daa8167SAndrew Turner 			 FE_UPWARD | FE_TOWARDZERO)
658daa8167SAndrew Turner #define	_ROUND_SHIFT	22
668daa8167SAndrew Turner 
678daa8167SAndrew Turner __BEGIN_DECLS
688daa8167SAndrew Turner 
698daa8167SAndrew Turner /* Default floating-point environment */
708daa8167SAndrew Turner extern const fenv_t	__fe_dfl_env;
718daa8167SAndrew Turner #define	FE_DFL_ENV	(&__fe_dfl_env)
728daa8167SAndrew Turner 
738daa8167SAndrew Turner /* We need to be able to map status flag positions to mask flag positions */
748daa8167SAndrew Turner #define _FPUSW_SHIFT	8
758daa8167SAndrew Turner #define	_ENABLE_MASK	(FE_ALL_EXCEPT << _FPUSW_SHIFT)
768daa8167SAndrew Turner 
7758853f4fSEd Maste #define	__mrs_fpcr(__r)	__asm __volatile("mrs %0, fpcr" : "=r" (__r))
7858853f4fSEd Maste #define	__msr_fpcr(__r)	__asm __volatile("msr fpcr, %0" : : "r" (__r))
798daa8167SAndrew Turner 
8058853f4fSEd Maste #define	__mrs_fpsr(__r)	__asm __volatile("mrs %0, fpsr" : "=r" (__r))
8158853f4fSEd Maste #define	__msr_fpsr(__r)	__asm __volatile("msr fpsr, %0" : : "r" (__r))
828daa8167SAndrew Turner 
838daa8167SAndrew Turner __fenv_static __inline int
feclearexcept(int __excepts)848daa8167SAndrew Turner feclearexcept(int __excepts)
858daa8167SAndrew Turner {
868daa8167SAndrew Turner 	fexcept_t __r;
878daa8167SAndrew Turner 
8858853f4fSEd Maste 	__mrs_fpsr(__r);
898daa8167SAndrew Turner 	__r &= ~__excepts;
908daa8167SAndrew Turner 	__msr_fpsr(__r);
918daa8167SAndrew Turner 	return (0);
928daa8167SAndrew Turner }
938daa8167SAndrew Turner 
948daa8167SAndrew Turner __fenv_static inline int
fegetexceptflag(fexcept_t * __flagp,int __excepts)958daa8167SAndrew Turner fegetexceptflag(fexcept_t *__flagp, int __excepts)
968daa8167SAndrew Turner {
978daa8167SAndrew Turner 	fexcept_t __r;
988daa8167SAndrew Turner 
9958853f4fSEd Maste 	__mrs_fpsr(__r);
1008daa8167SAndrew Turner 	*__flagp = __r & __excepts;
1018daa8167SAndrew Turner 	return (0);
1028daa8167SAndrew Turner }
1038daa8167SAndrew Turner 
1048daa8167SAndrew Turner __fenv_static inline int
fesetexceptflag(const fexcept_t * __flagp,int __excepts)1058daa8167SAndrew Turner fesetexceptflag(const fexcept_t *__flagp, int __excepts)
1068daa8167SAndrew Turner {
1078daa8167SAndrew Turner 	fexcept_t __r;
1088daa8167SAndrew Turner 
10958853f4fSEd Maste 	__mrs_fpsr(__r);
1108daa8167SAndrew Turner 	__r &= ~__excepts;
1118daa8167SAndrew Turner 	__r |= *__flagp & __excepts;
1128daa8167SAndrew Turner 	__msr_fpsr(__r);
1138daa8167SAndrew Turner 	return (0);
1148daa8167SAndrew Turner }
1158daa8167SAndrew Turner 
1168daa8167SAndrew Turner __fenv_static inline int
feraiseexcept(int __excepts)1178daa8167SAndrew Turner feraiseexcept(int __excepts)
1188daa8167SAndrew Turner {
1198daa8167SAndrew Turner 	fexcept_t __r;
1208daa8167SAndrew Turner 
12158853f4fSEd Maste 	__mrs_fpsr(__r);
1228daa8167SAndrew Turner 	__r |= __excepts;
1238daa8167SAndrew Turner 	__msr_fpsr(__r);
1248daa8167SAndrew Turner 	return (0);
1258daa8167SAndrew Turner }
1268daa8167SAndrew Turner 
1278daa8167SAndrew Turner __fenv_static inline int
fetestexcept(int __excepts)1288daa8167SAndrew Turner fetestexcept(int __excepts)
1298daa8167SAndrew Turner {
1308daa8167SAndrew Turner 	fexcept_t __r;
1318daa8167SAndrew Turner 
13258853f4fSEd Maste 	__mrs_fpsr(__r);
1338daa8167SAndrew Turner 	return (__r & __excepts);
1348daa8167SAndrew Turner }
1358daa8167SAndrew Turner 
1368daa8167SAndrew Turner __fenv_static inline int
fegetround(void)1378daa8167SAndrew Turner fegetround(void)
1388daa8167SAndrew Turner {
1398daa8167SAndrew Turner 	fenv_t __r;
1408daa8167SAndrew Turner 
14158853f4fSEd Maste 	__mrs_fpcr(__r);
1428daa8167SAndrew Turner 	return ((__r >> _ROUND_SHIFT) & _ROUND_MASK);
1438daa8167SAndrew Turner }
1448daa8167SAndrew Turner 
1458daa8167SAndrew Turner __fenv_static inline int
fesetround(int __round)1468daa8167SAndrew Turner fesetround(int __round)
1478daa8167SAndrew Turner {
1488daa8167SAndrew Turner 	fenv_t __r;
1498daa8167SAndrew Turner 
1508daa8167SAndrew Turner 	if (__round & ~_ROUND_MASK)
1518daa8167SAndrew Turner 		return (-1);
15258853f4fSEd Maste 	__mrs_fpcr(__r);
1538daa8167SAndrew Turner 	__r &= ~(_ROUND_MASK << _ROUND_SHIFT);
1548daa8167SAndrew Turner 	__r |= __round << _ROUND_SHIFT;
1558daa8167SAndrew Turner 	__msr_fpcr(__r);
1568daa8167SAndrew Turner 	return (0);
1578daa8167SAndrew Turner }
1588daa8167SAndrew Turner 
1598daa8167SAndrew Turner __fenv_static inline int
fegetenv(fenv_t * __envp)1608daa8167SAndrew Turner fegetenv(fenv_t *__envp)
1618daa8167SAndrew Turner {
16234cc08e3SAlex Richardson 	__uint64_t fpcr;
16334cc08e3SAlex Richardson 	__uint64_t fpsr;
1648daa8167SAndrew Turner 
16534cc08e3SAlex Richardson 	__mrs_fpcr(fpcr);
16634cc08e3SAlex Richardson 	__mrs_fpsr(fpsr);
16734cc08e3SAlex Richardson 	*__envp = fpsr | (fpcr << 32);
1688daa8167SAndrew Turner 
1698daa8167SAndrew Turner 	return (0);
1708daa8167SAndrew Turner }
1718daa8167SAndrew Turner 
1728daa8167SAndrew Turner __fenv_static inline int
feholdexcept(fenv_t * __envp)1738daa8167SAndrew Turner feholdexcept(fenv_t *__envp)
1748daa8167SAndrew Turner {
1758daa8167SAndrew Turner 	fenv_t __r;
1768daa8167SAndrew Turner 
17758853f4fSEd Maste 	__mrs_fpcr(__r);
17834cc08e3SAlex Richardson 	*__envp = __r << 32;
1798daa8167SAndrew Turner 	__r &= ~(_ENABLE_MASK);
1808daa8167SAndrew Turner 	__msr_fpcr(__r);
1818daa8167SAndrew Turner 
18258853f4fSEd Maste 	__mrs_fpsr(__r);
18334cc08e3SAlex Richardson 	*__envp |= (__uint32_t)__r;
18458853f4fSEd Maste 	__r &= ~(_ENABLE_MASK);
1858daa8167SAndrew Turner 	__msr_fpsr(__r);
1868daa8167SAndrew Turner 	return (0);
1878daa8167SAndrew Turner }
1888daa8167SAndrew Turner 
1898daa8167SAndrew Turner __fenv_static inline int
fesetenv(const fenv_t * __envp)1908daa8167SAndrew Turner fesetenv(const fenv_t *__envp)
1918daa8167SAndrew Turner {
1928daa8167SAndrew Turner 
19334cc08e3SAlex Richardson 	__msr_fpcr((*__envp) >> 32);
19434cc08e3SAlex Richardson 	__msr_fpsr((fenv_t)(__uint32_t)*__envp);
1958daa8167SAndrew Turner 	return (0);
1968daa8167SAndrew Turner }
1978daa8167SAndrew Turner 
1988daa8167SAndrew Turner __fenv_static inline int
feupdateenv(const fenv_t * __envp)1998daa8167SAndrew Turner feupdateenv(const fenv_t *__envp)
2008daa8167SAndrew Turner {
2018daa8167SAndrew Turner 	fexcept_t __r;
2028daa8167SAndrew Turner 
20358853f4fSEd Maste 	__mrs_fpsr(__r);
2048daa8167SAndrew Turner 	fesetenv(__envp);
2058daa8167SAndrew Turner 	feraiseexcept(__r & FE_ALL_EXCEPT);
2068daa8167SAndrew Turner 	return (0);
2078daa8167SAndrew Turner }
2088daa8167SAndrew Turner 
2098daa8167SAndrew Turner #if __BSD_VISIBLE
2108daa8167SAndrew Turner 
2118daa8167SAndrew Turner /* We currently provide no external definitions of the functions below. */
2128daa8167SAndrew Turner 
2138daa8167SAndrew Turner static inline int
feenableexcept(int __mask)2148daa8167SAndrew Turner feenableexcept(int __mask)
2158daa8167SAndrew Turner {
2168daa8167SAndrew Turner 	fenv_t __old_r, __new_r;
2178daa8167SAndrew Turner 
21858853f4fSEd Maste 	__mrs_fpcr(__old_r);
2198daa8167SAndrew Turner 	__new_r = __old_r | ((__mask & FE_ALL_EXCEPT) << _FPUSW_SHIFT);
2208daa8167SAndrew Turner 	__msr_fpcr(__new_r);
2218daa8167SAndrew Turner 	return ((__old_r >> _FPUSW_SHIFT) & FE_ALL_EXCEPT);
2228daa8167SAndrew Turner }
2238daa8167SAndrew Turner 
2248daa8167SAndrew Turner static inline int
fedisableexcept(int __mask)2258daa8167SAndrew Turner fedisableexcept(int __mask)
2268daa8167SAndrew Turner {
2278daa8167SAndrew Turner 	fenv_t __old_r, __new_r;
2288daa8167SAndrew Turner 
22958853f4fSEd Maste 	__mrs_fpcr(__old_r);
2308daa8167SAndrew Turner 	__new_r = __old_r & ~((__mask & FE_ALL_EXCEPT) << _FPUSW_SHIFT);
2318daa8167SAndrew Turner 	__msr_fpcr(__new_r);
2328daa8167SAndrew Turner 	return ((__old_r >> _FPUSW_SHIFT) & FE_ALL_EXCEPT);
2338daa8167SAndrew Turner }
2348daa8167SAndrew Turner 
2358daa8167SAndrew Turner static inline int
fegetexcept(void)2368daa8167SAndrew Turner fegetexcept(void)
2378daa8167SAndrew Turner {
2388daa8167SAndrew Turner 	fenv_t __r;
2398daa8167SAndrew Turner 
24058853f4fSEd Maste 	__mrs_fpcr(__r);
2418daa8167SAndrew Turner 	return ((__r & _ENABLE_MASK) >> _FPUSW_SHIFT);
2428daa8167SAndrew Turner }
2438daa8167SAndrew Turner 
2448daa8167SAndrew Turner #endif /* __BSD_VISIBLE */
2458daa8167SAndrew Turner 
2468daa8167SAndrew Turner __END_DECLS
2478daa8167SAndrew Turner 
2488daa8167SAndrew Turner #endif	/* !_FENV_H_ */
249*d5d97bedSMike Karels 
250*d5d97bedSMike Karels #endif /* __arm__ */
251