1/*-
2 * Copyright (c) 2004-2005 David Schultz <das@FreeBSD.ORG>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD$
27 */
28
29#ifndef	_FENV_H_
30#define	_FENV_H_
31
32#include <sys/_types.h>
33
34#ifndef	__fenv_static
35#define	__fenv_static	static
36#endif
37
38typedef	__uint64_t	fenv_t;
39typedef	__uint64_t	fexcept_t;
40
41/* Exception flags */
42#define	FE_INVALID	0x00000001
43#define	FE_DIVBYZERO	0x00000002
44#define	FE_OVERFLOW	0x00000004
45#define	FE_UNDERFLOW	0x00000008
46#define	FE_INEXACT	0x00000010
47#define	FE_ALL_EXCEPT	(FE_DIVBYZERO | FE_INEXACT | \
48			 FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW)
49
50/*
51 * Rounding modes
52 *
53 * We can't just use the hardware bit values here, because that would
54 * make FE_UPWARD and FE_DOWNWARD negative, which is not allowed.
55 */
56#define	FE_TONEAREST	0x0
57#define	FE_UPWARD	0x1
58#define	FE_DOWNWARD	0x2
59#define	FE_TOWARDZERO	0x3
60#define	_ROUND_MASK	(FE_TONEAREST | FE_DOWNWARD | \
61			 FE_UPWARD | FE_TOWARDZERO)
62#define	_ROUND_SHIFT	22
63
64__BEGIN_DECLS
65
66/* Default floating-point environment */
67extern const fenv_t	__fe_dfl_env;
68#define	FE_DFL_ENV	(&__fe_dfl_env)
69
70/* We need to be able to map status flag positions to mask flag positions */
71#define _FPUSW_SHIFT	8
72#define	_ENABLE_MASK	(FE_ALL_EXCEPT << _FPUSW_SHIFT)
73
74#define	__mrs_fpcr(__r)	__asm __volatile("mrs %0, fpcr" : "=r" (__r))
75#define	__msr_fpcr(__r)	__asm __volatile("msr fpcr, %0" : : "r" (__r))
76
77#define	__mrs_fpsr(__r)	__asm __volatile("mrs %0, fpsr" : "=r" (__r))
78#define	__msr_fpsr(__r)	__asm __volatile("msr fpsr, %0" : : "r" (__r))
79
80__fenv_static __inline int
81feclearexcept(int __excepts)
82{
83	fexcept_t __r;
84
85	__mrs_fpsr(__r);
86	__r &= ~__excepts;
87	__msr_fpsr(__r);
88	return (0);
89}
90
91__fenv_static inline int
92fegetexceptflag(fexcept_t *__flagp, int __excepts)
93{
94	fexcept_t __r;
95
96	__mrs_fpsr(__r);
97	*__flagp = __r & __excepts;
98	return (0);
99}
100
101__fenv_static inline int
102fesetexceptflag(const fexcept_t *__flagp, int __excepts)
103{
104	fexcept_t __r;
105
106	__mrs_fpsr(__r);
107	__r &= ~__excepts;
108	__r |= *__flagp & __excepts;
109	__msr_fpsr(__r);
110	return (0);
111}
112
113__fenv_static inline int
114feraiseexcept(int __excepts)
115{
116	fexcept_t __r;
117
118	__mrs_fpsr(__r);
119	__r |= __excepts;
120	__msr_fpsr(__r);
121	return (0);
122}
123
124__fenv_static inline int
125fetestexcept(int __excepts)
126{
127	fexcept_t __r;
128
129	__mrs_fpsr(__r);
130	return (__r & __excepts);
131}
132
133__fenv_static inline int
134fegetround(void)
135{
136	fenv_t __r;
137
138	__mrs_fpcr(__r);
139	return ((__r >> _ROUND_SHIFT) & _ROUND_MASK);
140}
141
142__fenv_static inline int
143fesetround(int __round)
144{
145	fenv_t __r;
146
147	if (__round & ~_ROUND_MASK)
148		return (-1);
149	__mrs_fpcr(__r);
150	__r &= ~(_ROUND_MASK << _ROUND_SHIFT);
151	__r |= __round << _ROUND_SHIFT;
152	__msr_fpcr(__r);
153	return (0);
154}
155
156__fenv_static inline int
157fegetenv(fenv_t *__envp)
158{
159	fenv_t __r;
160
161	__mrs_fpcr(__r);
162	*__envp = __r & _ENABLE_MASK;
163
164	__mrs_fpsr(__r);
165	*__envp |= __r & (FE_ALL_EXCEPT | (_ROUND_MASK << _ROUND_SHIFT));
166
167	return (0);
168}
169
170__fenv_static inline int
171feholdexcept(fenv_t *__envp)
172{
173	fenv_t __r;
174
175	__mrs_fpcr(__r);
176	*__envp = __r & _ENABLE_MASK;
177	__r &= ~(_ENABLE_MASK);
178	__msr_fpcr(__r);
179
180	__mrs_fpsr(__r);
181	*__envp |= __r & (FE_ALL_EXCEPT | (_ROUND_MASK << _ROUND_SHIFT));
182	__r &= ~(_ENABLE_MASK);
183	__msr_fpsr(__r);
184	return (0);
185}
186
187__fenv_static inline int
188fesetenv(const fenv_t *__envp)
189{
190
191	__msr_fpcr((*__envp) & _ENABLE_MASK);
192	__msr_fpsr((*__envp) & (FE_ALL_EXCEPT | (_ROUND_MASK << _ROUND_SHIFT)));
193	return (0);
194}
195
196__fenv_static inline int
197feupdateenv(const fenv_t *__envp)
198{
199	fexcept_t __r;
200
201	__mrs_fpsr(__r);
202	fesetenv(__envp);
203	feraiseexcept(__r & FE_ALL_EXCEPT);
204	return (0);
205}
206
207#if __BSD_VISIBLE
208
209/* We currently provide no external definitions of the functions below. */
210
211static inline int
212feenableexcept(int __mask)
213{
214	fenv_t __old_r, __new_r;
215
216	__mrs_fpcr(__old_r);
217	__new_r = __old_r | ((__mask & FE_ALL_EXCEPT) << _FPUSW_SHIFT);
218	__msr_fpcr(__new_r);
219	return ((__old_r >> _FPUSW_SHIFT) & FE_ALL_EXCEPT);
220}
221
222static inline int
223fedisableexcept(int __mask)
224{
225	fenv_t __old_r, __new_r;
226
227	__mrs_fpcr(__old_r);
228	__new_r = __old_r & ~((__mask & FE_ALL_EXCEPT) << _FPUSW_SHIFT);
229	__msr_fpcr(__new_r);
230	return ((__old_r >> _FPUSW_SHIFT) & FE_ALL_EXCEPT);
231}
232
233static inline int
234fegetexcept(void)
235{
236	fenv_t __r;
237
238	__mrs_fpcr(__r);
239	return ((__r & _ENABLE_MASK) >> _FPUSW_SHIFT);
240}
241
242#endif /* __BSD_VISIBLE */
243
244__END_DECLS
245
246#endif	/* !_FENV_H_ */
247