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	0x00000200
43#define	FE_DIVBYZERO	0x00000040
44#define	FE_OVERFLOW	0x00000100
45#define	FE_UNDERFLOW	0x00000080
46#define	FE_INEXACT	0x00000020
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_TOWARDZERO	0x1
58#define	FE_UPWARD	0x2
59#define	FE_DOWNWARD	0x3
60#define	_ROUND_MASK	(FE_TONEAREST | FE_DOWNWARD | \
61			 FE_UPWARD | FE_TOWARDZERO)
62#define	_ROUND_SHIFT	30
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	18
72#define	_ENABLE_MASK	(FE_ALL_EXCEPT << _FPUSW_SHIFT)
73
74#define	__ldxfsr(__r)	__asm __volatile("ldx %0, %%fsr" : : "m" (__r))
75#define	__stxfsr(__r)	__asm __volatile("stx %%fsr, %0" : "=m" (*(__r)))
76
77__fenv_static __inline int
78feclearexcept(int __excepts)
79{
80	fexcept_t __r;
81
82	__stxfsr(&__r);
83	__r &= ~__excepts;
84	__ldxfsr(__r);
85	return (0);
86}
87
88__fenv_static inline int
89fegetexceptflag(fexcept_t *__flagp, int __excepts)
90{
91	fexcept_t __r;
92
93	__stxfsr(&__r);
94	*__flagp = __r & __excepts;
95	return (0);
96}
97
98__fenv_static inline int
99fesetexceptflag(const fexcept_t *__flagp, int __excepts)
100{
101	fexcept_t __r;
102
103	__stxfsr(&__r);
104	__r &= ~__excepts;
105	__r |= *__flagp & __excepts;
106	__ldxfsr(__r);
107	return (0);
108}
109
110/*
111 * It seems to be worthwhile to inline this function even when the
112 * arguments are not compile-time constants.  Perhaps this depends
113 * on the register window.
114 */
115__fenv_static inline int
116feraiseexcept(int __excepts)
117{
118	volatile double d;
119
120	/*
121	 * With a compiler that supports the FENV_ACCESS pragma
122	 * properly, simple expressions like '0.0 / 0.0' should
123	 * be sufficient to generate traps.  Unfortunately, we
124	 * need to bring a volatile variable into the equation
125	 * to prevent incorrect optimizations.
126	 */
127	if (__excepts & FE_INVALID) {
128		d = 0.0;
129		d = 0.0 / d;
130	}
131	if (__excepts & FE_DIVBYZERO) {
132		d = 0.0;
133		d = 1.0 / d;
134	}
135	if (__excepts & FE_OVERFLOW) {
136		d = 0x1.ffp1023;
137		d *= 2.0;
138	}
139	if (__excepts & FE_UNDERFLOW) {
140		d = 0x1p-1022;
141		d /= 0x1p1023;
142	}
143	if (__excepts & FE_INEXACT) {
144		d = 0x1p-1022;
145		d += 1.0;
146	}
147	return (0);
148}
149
150__fenv_static inline int
151fetestexcept(int __excepts)
152{
153	fexcept_t __r;
154
155	__stxfsr(&__r);
156	return (__r & __excepts);
157}
158
159__fenv_static inline int
160fegetround(void)
161{
162	fenv_t __r;
163
164	__stxfsr(&__r);
165	return ((__r >> _ROUND_SHIFT) & _ROUND_MASK);
166}
167
168__fenv_static inline int
169fesetround(int __round)
170{
171	fenv_t __r;
172
173	if (__round & ~_ROUND_MASK)
174		return (-1);
175	__stxfsr(&__r);
176	__r &= ~(_ROUND_MASK << _ROUND_SHIFT);
177	__r |= __round << _ROUND_SHIFT;
178	__ldxfsr(__r);
179	return (0);
180}
181
182__fenv_static inline int
183fegetenv(fenv_t *__envp)
184{
185
186	__stxfsr(__envp);
187	return (0);
188}
189
190__fenv_static inline int
191feholdexcept(fenv_t *__envp)
192{
193	fenv_t __r;
194
195	__stxfsr(&__r);
196	*__envp = __r;
197	__r &= ~(FE_ALL_EXCEPT | _ENABLE_MASK);
198	__ldxfsr(__r);
199	return (0);
200}
201
202__fenv_static inline int
203fesetenv(const fenv_t *__envp)
204{
205
206	__ldxfsr(*__envp);
207	return (0);
208}
209
210__fenv_static inline int
211feupdateenv(const fenv_t *__envp)
212{
213	fexcept_t __r;
214
215	__stxfsr(&__r);
216	__ldxfsr(*__envp);
217	feraiseexcept(__r & FE_ALL_EXCEPT);
218	return (0);
219}
220
221#if __BSD_VISIBLE
222
223/* We currently provide no external definitions of the functions below. */
224
225static inline int
226feenableexcept(int __mask)
227{
228	fenv_t __old_r, __new_r;
229
230	__stxfsr(&__old_r);
231	__new_r = __old_r | ((__mask & FE_ALL_EXCEPT) << _FPUSW_SHIFT);
232	__ldxfsr(__new_r);
233	return ((__old_r >> _FPUSW_SHIFT) & FE_ALL_EXCEPT);
234}
235
236static inline int
237fedisableexcept(int __mask)
238{
239	fenv_t __old_r, __new_r;
240
241	__stxfsr(&__old_r);
242	__new_r = __old_r & ~((__mask & FE_ALL_EXCEPT) << _FPUSW_SHIFT);
243	__ldxfsr(__new_r);
244	return ((__old_r >> _FPUSW_SHIFT) & FE_ALL_EXCEPT);
245}
246
247static inline int
248fegetexcept(void)
249{
250	fenv_t __r;
251
252	__stxfsr(&__r);
253	return ((__r & _ENABLE_MASK) >> _FPUSW_SHIFT);
254}
255
256#endif /* __BSD_VISIBLE */
257
258__END_DECLS
259
260#endif	/* !_FENV_H_ */
261