ieeefp.h revision 175234
1/*-
2 * Copyright (c) 2003 Peter Wemm.
3 * Copyright (c) 1990 Andrew Moore, Talke Studio
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 *    must display the following acknowledgement:
16 *	This product includes software developed by the University of
17 *	California, Berkeley and its contributors.
18 * 4. Neither the name of the University nor the names of its contributors
19 *    may be used to endorse or promote products derived from this software
20 *    without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 *
34 * 	from: @(#) ieeefp.h 	1.0 (Berkeley) 9/23/93
35 * $FreeBSD: head/sys/i386/include/ieeefp.h 175234 2008-01-11 18:59:35Z bde $
36 */
37
38#ifndef _MACHINE_IEEEFP_H_
39#define _MACHINE_IEEEFP_H_
40
41/*
42 * IEEE floating point type, constant and function definitions.
43 * XXX: FP*FLD and FP*OFF are undocumented pollution.
44 */
45
46#ifndef _SYS_CDEFS_H_
47#error this file needs sys/cdefs.h as a prerequisite
48#endif
49
50/*
51 * Rounding modes.
52 */
53typedef enum {
54	FP_RN=0,	/* round to nearest */
55	FP_RM,		/* round down towards minus infinity */
56	FP_RP,		/* round up towards plus infinity */
57	FP_RZ		/* truncate */
58} fp_rnd_t;
59
60/*
61 * Precision (i.e., rounding precision) modes.
62 */
63typedef enum {
64	FP_PS=0,	/* 24 bit (single-precision) */
65	FP_PRS,		/* reserved */
66	FP_PD,		/* 53 bit (double-precision) */
67	FP_PE		/* 64 bit (extended-precision) */
68} fp_prec_t;
69
70#define fp_except_t	int
71
72/*
73 * Exception bit masks.
74 */
75#define FP_X_INV	0x01	/* invalid operation */
76#define FP_X_DNML	0x02	/* denormal */
77#define FP_X_DZ		0x04	/* zero divide */
78#define FP_X_OFL	0x08	/* overflow */
79#define FP_X_UFL	0x10	/* underflow */
80#define FP_X_IMP	0x20	/* (im)precision */
81#define FP_X_STK	0x40	/* stack fault */
82
83/*
84 * FPU control word bit-field masks.
85 */
86#define FP_MSKS_FLD	0x3f	/* exception masks field */
87#define FP_PRC_FLD	0x300	/* precision control field */
88#define	FP_RND_FLD	0xc00	/* rounding control field */
89
90/*
91 * FPU status word bit-field masks.
92 */
93#define FP_STKY_FLD	0x3f	/* sticky flags field */
94
95/*
96 * FPU control word bit-field offsets (shift counts).
97 */
98#define FP_MSKS_OFF	0	/* exception masks offset */
99#define FP_PRC_OFF	8	/* precision control offset */
100#define	FP_RND_OFF	10	/* rounding control offset */
101
102/*
103 * FPU status word bit-field offsets (shift counts).
104 */
105#define FP_STKY_OFF	0	/* sticky flags offset */
106
107#ifdef __GNUCLIKE_ASM
108
109#define	__fldcw(addr)	__asm __volatile("fldcw %0" : : "m" (*(addr)))
110#define	__fldenv(addr)	__asm __volatile("fldenv %0" : : "m" (*(addr)))
111#define	__fnclex()	__asm __volatile("fnclex")
112#define	__fnstcw(addr)	__asm __volatile("fnstcw %0" : "=m" (*(addr)))
113#define	__fnstenv(addr)	__asm __volatile("fnstenv %0" : "=m" (*(addr)))
114#define	__fnstsw(addr)	__asm __volatile("fnstsw %0" : "=m" (*(addr)))
115
116/*
117 * Load the control word.  Be careful not to trap if there is a currently
118 * unmasked exception (ones that will become freshly unmasked are not a
119 * problem).  This case must be handled by a save/restore of the
120 * environment or even of the full x87 state.  Accessing the environment
121 * is very inefficient, so only do it when necessary.
122 */
123static __inline void
124__fnldcw(unsigned short _cw, unsigned short _newcw)
125{
126	struct {
127		unsigned _cw;
128		unsigned _other[6];
129	} _env;
130	unsigned short _sw;
131
132	if ((_cw & FP_MSKS_FLD) != FP_MSKS_FLD) {
133		__fnstsw(&_sw);
134		if (((_sw & ~_cw) & FP_STKY_FLD) != 0) {
135			__fnstenv(&_env);
136			_env._cw = _newcw;
137			__fldenv(&_env);
138			return;
139		}
140	}
141	__fldcw(&_newcw);
142}
143
144static __inline fp_rnd_t
145fpgetround(void)
146{
147	unsigned short _cw;
148
149	__fnstcw(&_cw);
150	return ((fp_rnd_t)((_cw & FP_RND_FLD) >> FP_RND_OFF));
151}
152
153static __inline fp_rnd_t
154fpsetround(fp_rnd_t _m)
155{
156	fp_rnd_t _p;
157	unsigned short _cw, _newcw;
158
159	__fnstcw(&_cw);
160	_p = (fp_rnd_t)((_cw & FP_RND_FLD) >> FP_RND_OFF);
161	_newcw = _cw & ~FP_RND_FLD;
162	_newcw |= (_m << FP_RND_OFF) & FP_RND_FLD;
163	__fnldcw(_cw, _newcw);
164	return (_p);
165}
166
167static __inline fp_prec_t
168fpgetprec(void)
169{
170	unsigned short _cw;
171
172	__fnstcw(&_cw);
173	return ((fp_prec_t)((_cw & FP_PRC_FLD) >> FP_PRC_OFF));
174}
175
176static __inline fp_prec_t
177fpsetprec(fp_prec_t _m)
178{
179	fp_prec_t _p;
180	unsigned short _cw, _newcw;
181
182	__fnstcw(&_cw);
183	_p = (fp_prec_t)((_cw & FP_PRC_FLD) >> FP_PRC_OFF);
184	_newcw = _cw & ~FP_PRC_FLD;
185	_newcw |= (_m << FP_PRC_OFF) & FP_PRC_FLD;
186	__fnldcw(_cw, _newcw);
187	return (_p);
188}
189
190/*
191 * Get or set the exception mask.
192 * Note that the x87 mask bits are inverted by the API -- a mask bit of 1
193 * means disable for x87 and SSE, but for fp*mask() it means enable.
194 */
195
196static __inline fp_except_t
197fpgetmask(void)
198{
199	unsigned short _cw;
200
201	__fnstcw(&_cw);
202	return ((~_cw & FP_MSKS_FLD) >> FP_MSKS_OFF);
203}
204
205static __inline fp_except_t
206fpsetmask(fp_except_t _m)
207{
208	fp_except_t _p;
209	unsigned short _cw, _newcw;
210
211	__fnstcw(&_cw);
212	_p = (~_cw & FP_MSKS_FLD) >> FP_MSKS_OFF;
213	_newcw = _cw & ~FP_MSKS_FLD;
214	_newcw |= (~_m << FP_MSKS_OFF) & FP_MSKS_FLD;
215	__fnldcw(_cw, _newcw);
216	return (_p);
217}
218
219static __inline fp_except_t
220fpgetsticky(void)
221{
222	unsigned _ex;
223	unsigned short _sw;
224
225	__fnstsw(&_sw);
226	_ex = (_sw & FP_STKY_FLD) >> FP_STKY_OFF;
227	return ((fp_except_t)_ex);
228}
229
230static __inline fp_except_t
231fpresetsticky(fp_except_t _m)
232{
233	struct {
234		unsigned _cw;
235		unsigned _sw;
236		unsigned _other[5];
237	} _env;
238	fp_except_t _p;
239
240	_m &= FP_STKY_FLD >> FP_STKY_OFF;
241	_p = fpgetsticky();
242	if ((_p & ~_m) == _p)
243		return (_p);
244	if ((_p & ~_m) == 0) {
245		__fnclex();
246		return (_p);
247	}
248	__fnstenv(&_env);
249	_env._sw &= ~_m;
250	__fldenv(&_env);
251	return (_p);
252}
253
254#endif /* __GNUCLIKE_ASM */
255
256/* Suppress prototypes in the MI header. */
257#define	_IEEEFP_INLINED_	1
258
259#endif /* !_MACHINE_IEEEFP_H_ */
260