xref: /freebsd/lib/msun/aarch64/fenv.h (revision 58853f4fb9bbf18035ecc8b8f33c660bf209aec9)
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  * $FreeBSD$
278daa8167SAndrew Turner  */
288daa8167SAndrew Turner 
298daa8167SAndrew Turner #ifndef	_FENV_H_
308daa8167SAndrew Turner #define	_FENV_H_
318daa8167SAndrew Turner 
328daa8167SAndrew Turner #include <sys/_types.h>
338daa8167SAndrew Turner 
348daa8167SAndrew Turner #ifndef	__fenv_static
358daa8167SAndrew Turner #define	__fenv_static	static
368daa8167SAndrew Turner #endif
378daa8167SAndrew Turner 
388daa8167SAndrew Turner typedef	__uint64_t	fenv_t;
398daa8167SAndrew Turner typedef	__uint64_t	fexcept_t;
408daa8167SAndrew Turner 
418daa8167SAndrew Turner /* Exception flags */
428daa8167SAndrew Turner #define	FE_INVALID	0x00000001
438daa8167SAndrew Turner #define	FE_DIVBYZERO	0x00000002
448daa8167SAndrew Turner #define	FE_OVERFLOW	0x00000004
458daa8167SAndrew Turner #define	FE_UNDERFLOW	0x00000008
468daa8167SAndrew Turner #define	FE_INEXACT	0x00000010
478daa8167SAndrew Turner #define	FE_ALL_EXCEPT	(FE_DIVBYZERO | FE_INEXACT | \
488daa8167SAndrew Turner 			 FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW)
498daa8167SAndrew Turner 
508daa8167SAndrew Turner /*
518daa8167SAndrew Turner  * Rounding modes
528daa8167SAndrew Turner  *
538daa8167SAndrew Turner  * We can't just use the hardware bit values here, because that would
548daa8167SAndrew Turner  * make FE_UPWARD and FE_DOWNWARD negative, which is not allowed.
558daa8167SAndrew Turner  */
568daa8167SAndrew Turner #define	FE_TONEAREST	0x0
578daa8167SAndrew Turner #define	FE_UPWARD	0x1
588daa8167SAndrew Turner #define	FE_DOWNWARD	0x2
598daa8167SAndrew Turner #define	FE_TOWARDZERO	0x3
608daa8167SAndrew Turner #define	_ROUND_MASK	(FE_TONEAREST | FE_DOWNWARD | \
618daa8167SAndrew Turner 			 FE_UPWARD | FE_TOWARDZERO)
628daa8167SAndrew Turner #define	_ROUND_SHIFT	22
638daa8167SAndrew Turner 
648daa8167SAndrew Turner __BEGIN_DECLS
658daa8167SAndrew Turner 
668daa8167SAndrew Turner /* Default floating-point environment */
678daa8167SAndrew Turner extern const fenv_t	__fe_dfl_env;
688daa8167SAndrew Turner #define	FE_DFL_ENV	(&__fe_dfl_env)
698daa8167SAndrew Turner 
708daa8167SAndrew Turner /* We need to be able to map status flag positions to mask flag positions */
718daa8167SAndrew Turner #define _FPUSW_SHIFT	8
728daa8167SAndrew Turner #define	_ENABLE_MASK	(FE_ALL_EXCEPT << _FPUSW_SHIFT)
738daa8167SAndrew Turner 
74*58853f4fSEd Maste #define	__mrs_fpcr(__r)	__asm __volatile("mrs %0, fpcr" : "=r" (__r))
75*58853f4fSEd Maste #define	__msr_fpcr(__r)	__asm __volatile("msr fpcr, %0" : : "r" (__r))
768daa8167SAndrew Turner 
77*58853f4fSEd Maste #define	__mrs_fpsr(__r)	__asm __volatile("mrs %0, fpsr" : "=r" (__r))
78*58853f4fSEd Maste #define	__msr_fpsr(__r)	__asm __volatile("msr fpsr, %0" : : "r" (__r))
798daa8167SAndrew Turner 
808daa8167SAndrew Turner __fenv_static __inline int
818daa8167SAndrew Turner feclearexcept(int __excepts)
828daa8167SAndrew Turner {
838daa8167SAndrew Turner 	fexcept_t __r;
848daa8167SAndrew Turner 
85*58853f4fSEd Maste 	__mrs_fpsr(__r);
868daa8167SAndrew Turner 	__r &= ~__excepts;
878daa8167SAndrew Turner 	__msr_fpsr(__r);
888daa8167SAndrew Turner 	return (0);
898daa8167SAndrew Turner }
908daa8167SAndrew Turner 
918daa8167SAndrew Turner __fenv_static inline int
928daa8167SAndrew Turner fegetexceptflag(fexcept_t *__flagp, int __excepts)
938daa8167SAndrew Turner {
948daa8167SAndrew Turner 	fexcept_t __r;
958daa8167SAndrew Turner 
96*58853f4fSEd Maste 	__mrs_fpsr(__r);
978daa8167SAndrew Turner 	*__flagp = __r & __excepts;
988daa8167SAndrew Turner 	return (0);
998daa8167SAndrew Turner }
1008daa8167SAndrew Turner 
1018daa8167SAndrew Turner __fenv_static inline int
1028daa8167SAndrew Turner fesetexceptflag(const fexcept_t *__flagp, int __excepts)
1038daa8167SAndrew Turner {
1048daa8167SAndrew Turner 	fexcept_t __r;
1058daa8167SAndrew Turner 
106*58853f4fSEd Maste 	__mrs_fpsr(__r);
1078daa8167SAndrew Turner 	__r &= ~__excepts;
1088daa8167SAndrew Turner 	__r |= *__flagp & __excepts;
1098daa8167SAndrew Turner 	__msr_fpsr(__r);
1108daa8167SAndrew Turner 	return (0);
1118daa8167SAndrew Turner }
1128daa8167SAndrew Turner 
1138daa8167SAndrew Turner __fenv_static inline int
1148daa8167SAndrew Turner feraiseexcept(int __excepts)
1158daa8167SAndrew Turner {
1168daa8167SAndrew Turner 	fexcept_t __r;
1178daa8167SAndrew Turner 
118*58853f4fSEd Maste 	__mrs_fpsr(__r);
1198daa8167SAndrew Turner 	__r |= __excepts;
1208daa8167SAndrew Turner 	__msr_fpsr(__r);
1218daa8167SAndrew Turner 	return (0);
1228daa8167SAndrew Turner }
1238daa8167SAndrew Turner 
1248daa8167SAndrew Turner __fenv_static inline int
1258daa8167SAndrew Turner fetestexcept(int __excepts)
1268daa8167SAndrew Turner {
1278daa8167SAndrew Turner 	fexcept_t __r;
1288daa8167SAndrew Turner 
129*58853f4fSEd Maste 	__mrs_fpsr(__r);
1308daa8167SAndrew Turner 	return (__r & __excepts);
1318daa8167SAndrew Turner }
1328daa8167SAndrew Turner 
1338daa8167SAndrew Turner __fenv_static inline int
1348daa8167SAndrew Turner fegetround(void)
1358daa8167SAndrew Turner {
1368daa8167SAndrew Turner 	fenv_t __r;
1378daa8167SAndrew Turner 
138*58853f4fSEd Maste 	__mrs_fpcr(__r);
1398daa8167SAndrew Turner 	return ((__r >> _ROUND_SHIFT) & _ROUND_MASK);
1408daa8167SAndrew Turner }
1418daa8167SAndrew Turner 
1428daa8167SAndrew Turner __fenv_static inline int
1438daa8167SAndrew Turner fesetround(int __round)
1448daa8167SAndrew Turner {
1458daa8167SAndrew Turner 	fenv_t __r;
1468daa8167SAndrew Turner 
1478daa8167SAndrew Turner 	if (__round & ~_ROUND_MASK)
1488daa8167SAndrew Turner 		return (-1);
149*58853f4fSEd Maste 	__mrs_fpcr(__r);
1508daa8167SAndrew Turner 	__r &= ~(_ROUND_MASK << _ROUND_SHIFT);
1518daa8167SAndrew Turner 	__r |= __round << _ROUND_SHIFT;
1528daa8167SAndrew Turner 	__msr_fpcr(__r);
1538daa8167SAndrew Turner 	return (0);
1548daa8167SAndrew Turner }
1558daa8167SAndrew Turner 
1568daa8167SAndrew Turner __fenv_static inline int
1578daa8167SAndrew Turner fegetenv(fenv_t *__envp)
1588daa8167SAndrew Turner {
159*58853f4fSEd Maste 	fenv_t __r;
1608daa8167SAndrew Turner 
161*58853f4fSEd Maste 	__mrs_fpcr(__r);
1628daa8167SAndrew Turner 	*__envp = __r & _ENABLE_MASK;
1638daa8167SAndrew Turner 
164*58853f4fSEd Maste 	__mrs_fpsr(__r);
1658daa8167SAndrew Turner 	*__envp |= __r & (FE_ALL_EXCEPT | (_ROUND_MASK << _ROUND_SHIFT));
1668daa8167SAndrew Turner 
1678daa8167SAndrew Turner 	return (0);
1688daa8167SAndrew Turner }
1698daa8167SAndrew Turner 
1708daa8167SAndrew Turner __fenv_static inline int
1718daa8167SAndrew Turner feholdexcept(fenv_t *__envp)
1728daa8167SAndrew Turner {
1738daa8167SAndrew Turner 	fenv_t __r;
1748daa8167SAndrew Turner 
175*58853f4fSEd Maste 	__mrs_fpcr(__r);
1768daa8167SAndrew Turner 	*__envp = __r & _ENABLE_MASK;
1778daa8167SAndrew Turner 	__r &= ~(_ENABLE_MASK);
1788daa8167SAndrew Turner 	__msr_fpcr(__r);
1798daa8167SAndrew Turner 
180*58853f4fSEd Maste 	__mrs_fpsr(__r);
1818daa8167SAndrew Turner 	*__envp |= __r & (FE_ALL_EXCEPT | (_ROUND_MASK << _ROUND_SHIFT));
182*58853f4fSEd Maste 	__r &= ~(_ENABLE_MASK);
1838daa8167SAndrew Turner 	__msr_fpsr(__r);
1848daa8167SAndrew Turner 	return (0);
1858daa8167SAndrew Turner }
1868daa8167SAndrew Turner 
1878daa8167SAndrew Turner __fenv_static inline int
1888daa8167SAndrew Turner fesetenv(const fenv_t *__envp)
1898daa8167SAndrew Turner {
1908daa8167SAndrew Turner 
1918daa8167SAndrew Turner 	__msr_fpcr((*__envp) & _ENABLE_MASK);
192*58853f4fSEd Maste 	__msr_fpsr((*__envp) & (FE_ALL_EXCEPT | (_ROUND_MASK << _ROUND_SHIFT)));
1938daa8167SAndrew Turner 	return (0);
1948daa8167SAndrew Turner }
1958daa8167SAndrew Turner 
1968daa8167SAndrew Turner __fenv_static inline int
1978daa8167SAndrew Turner feupdateenv(const fenv_t *__envp)
1988daa8167SAndrew Turner {
1998daa8167SAndrew Turner 	fexcept_t __r;
2008daa8167SAndrew Turner 
201*58853f4fSEd Maste 	__mrs_fpsr(__r);
2028daa8167SAndrew Turner 	fesetenv(__envp);
2038daa8167SAndrew Turner 	feraiseexcept(__r & FE_ALL_EXCEPT);
2048daa8167SAndrew Turner 	return (0);
2058daa8167SAndrew Turner }
2068daa8167SAndrew Turner 
2078daa8167SAndrew Turner #if __BSD_VISIBLE
2088daa8167SAndrew Turner 
2098daa8167SAndrew Turner /* We currently provide no external definitions of the functions below. */
2108daa8167SAndrew Turner 
2118daa8167SAndrew Turner static inline int
2128daa8167SAndrew Turner feenableexcept(int __mask)
2138daa8167SAndrew Turner {
2148daa8167SAndrew Turner 	fenv_t __old_r, __new_r;
2158daa8167SAndrew Turner 
216*58853f4fSEd Maste 	__mrs_fpcr(__old_r);
2178daa8167SAndrew Turner 	__new_r = __old_r | ((__mask & FE_ALL_EXCEPT) << _FPUSW_SHIFT);
2188daa8167SAndrew Turner 	__msr_fpcr(__new_r);
2198daa8167SAndrew Turner 	return ((__old_r >> _FPUSW_SHIFT) & FE_ALL_EXCEPT);
2208daa8167SAndrew Turner }
2218daa8167SAndrew Turner 
2228daa8167SAndrew Turner static inline int
2238daa8167SAndrew Turner fedisableexcept(int __mask)
2248daa8167SAndrew Turner {
2258daa8167SAndrew Turner 	fenv_t __old_r, __new_r;
2268daa8167SAndrew Turner 
227*58853f4fSEd Maste 	__mrs_fpcr(__old_r);
2288daa8167SAndrew Turner 	__new_r = __old_r & ~((__mask & FE_ALL_EXCEPT) << _FPUSW_SHIFT);
2298daa8167SAndrew Turner 	__msr_fpcr(__new_r);
2308daa8167SAndrew Turner 	return ((__old_r >> _FPUSW_SHIFT) & FE_ALL_EXCEPT);
2318daa8167SAndrew Turner }
2328daa8167SAndrew Turner 
2338daa8167SAndrew Turner static inline int
2348daa8167SAndrew Turner fegetexcept(void)
2358daa8167SAndrew Turner {
2368daa8167SAndrew Turner 	fenv_t __r;
2378daa8167SAndrew Turner 
238*58853f4fSEd Maste 	__mrs_fpcr(__r);
2398daa8167SAndrew Turner 	return ((__r & _ENABLE_MASK) >> _FPUSW_SHIFT);
2408daa8167SAndrew Turner }
2418daa8167SAndrew Turner 
2428daa8167SAndrew Turner #endif /* __BSD_VISIBLE */
2438daa8167SAndrew Turner 
2448daa8167SAndrew Turner __END_DECLS
2458daa8167SAndrew Turner 
2468daa8167SAndrew Turner #endif	/* !_FENV_H_ */
247