• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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: src/lib/msun/i387/fenv.h,v 1.4 2005/03/17 22:21:46 das Exp $
27  */
28 
29 #ifndef	_FENV_H_
30 #define	_FENV_H_
31 
32 #include <sys/cdefs.h>
33 #include <sys/_types.h>
34 
35 /*
36  * To preserve binary compatibility with FreeBSD 5.3, we pack the
37  * mxcsr into some reserved fields, rather than changing sizeof(fenv_t).
38  */
39 typedef struct {
40 	__uint16_t	__control;
41 	__uint16_t      __mxcsr_hi;
42 	__uint16_t	__status;
43 	__uint16_t      __mxcsr_lo;
44 	__uint32_t	__tag;
45 	char		__other[16];
46 } fenv_t;
47 
48 #define	__get_mxcsr(env)	(((env).__mxcsr_hi << 16) |	\
49 				 ((env).__mxcsr_lo))
50 #define	__set_mxcsr(env, x)	do {				\
51 	(env).__mxcsr_hi = (__uint32_t)(x) >> 16;		\
52 	(env).__mxcsr_lo = (__uint16_t)(x);			\
53 } while (0)
54 
55 typedef	__uint16_t	fexcept_t;
56 
57 /* Exception flags */
58 #define	FE_INVALID	0x01
59 #define	FE_DENORMAL	0x02
60 #define	FE_DIVBYZERO	0x04
61 #define	FE_OVERFLOW	0x08
62 #define	FE_UNDERFLOW	0x10
63 #define	FE_INEXACT	0x20
64 #define	FE_ALL_EXCEPT	(FE_DIVBYZERO | FE_DENORMAL | FE_INEXACT | \
65 			 FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW)
66 
67 /* Rounding modes */
68 #define	FE_TONEAREST	0x0000
69 #define	FE_DOWNWARD	0x0400
70 #define	FE_UPWARD	0x0800
71 #define	FE_TOWARDZERO	0x0c00
72 #define	_ROUND_MASK	(FE_TONEAREST | FE_DOWNWARD | \
73 			 FE_UPWARD | FE_TOWARDZERO)
74 
75 /*
76  * As compared to the x87 control word, the SSE unit's control word
77  * has the rounding control bits offset by 3 and the exception mask
78  * bits offset by 7.
79  */
80 #define	_SSE_ROUND_SHIFT	3
81 #define	_SSE_EMASK_SHIFT	7
82 
83 /* After testing for SSE support once, we cache the result in __has_sse. */
84 enum __sse_support { __SSE_YES, __SSE_NO, __SSE_UNK };
85 extern enum __sse_support __has_sse;
86 int __test_sse(void);
87 #ifdef __SSE__
88 #define	__HAS_SSE()	1
89 #else
90 #define	__HAS_SSE()	(__has_sse == __SSE_YES ||			\
91 			 (__has_sse == __SSE_UNK && __test_sse()))
92 #endif
93 
94 __BEGIN_DECLS
95 
96 /* Default floating-point environment */
97 extern const fenv_t	__fe_dfl_env;
98 #define	FE_DFL_ENV	(&__fe_dfl_env)
99 
100 #define	__fldcw(__cw)		__asm __volatile("fldcw %0" : : "m" (__cw))
101 #define	__fldenv(__env)		__asm __volatile("fldenv %0" : : "m" (__env))
102 #define	__fnclex()		__asm __volatile("fnclex")
103 #define	__fnstenv(__env)	__asm __volatile("fnstenv %0" : "=m" (*(__env)))
104 #define	__fnstcw(__cw)		__asm __volatile("fnstcw %0" : "=m" (*(__cw)))
105 #define	__fnstsw(__sw)		__asm __volatile("fnstsw %0" : "=am" (*(__sw)))
106 #define	__fwait()		__asm __volatile("fwait")
107 #define	__ldmxcsr(__csr)	__asm __volatile("ldmxcsr %0" : : "m" (__csr))
108 #define	__stmxcsr(__csr)	__asm __volatile("stmxcsr %0" : "=m" (*(__csr)))
109 
110 static __inline int
feclearexcept(int __excepts)111 feclearexcept(int __excepts)
112 {
113 	fenv_t __env;
114 	int __mxcsr;
115 
116 	if (__excepts == FE_ALL_EXCEPT) {
117 		__fnclex();
118 	} else {
119 		__fnstenv(&__env);
120 		__env.__status &= ~__excepts;
121 		__fldenv(__env);
122 	}
123 	if (__HAS_SSE()) {
124 		__stmxcsr(&__mxcsr);
125 		__mxcsr &= ~__excepts;
126 		__ldmxcsr(__mxcsr);
127 	}
128 	return (0);
129 }
130 
131 static __inline int
fegetexceptflag(fexcept_t * __flagp,int __excepts)132 fegetexceptflag(fexcept_t *__flagp, int __excepts)
133 {
134 	int __mxcsr, __status;
135 
136 	__fnstsw(&__status);
137 	if (__HAS_SSE())
138 		__stmxcsr(&__mxcsr);
139 	else
140 		__mxcsr = 0;
141 	*__flagp = (__mxcsr | __status) & __excepts;
142 	return (0);
143 }
144 
145 int fesetexceptflag(const fexcept_t *__flagp, int __excepts);
146 int feraiseexcept(int __excepts);
147 
148 static __inline int
fetestexcept(int __excepts)149 fetestexcept(int __excepts)
150 {
151 	int __mxcsr, __status;
152 
153 	__fnstsw(&__status);
154 	if (__HAS_SSE())
155 		__stmxcsr(&__mxcsr);
156 	else
157 		__mxcsr = 0;
158 	return ((__status | __mxcsr) & __excepts);
159 }
160 
161 static __inline int
fegetround(void)162 fegetround(void)
163 {
164 	int __control;
165 
166 	/*
167 	 * We assume that the x87 and the SSE unit agree on the
168 	 * rounding mode.  Reading the control word on the x87 turns
169 	 * out to be about 5 times faster than reading it on the SSE
170 	 * unit on an Opteron 244.
171 	 */
172 	__fnstcw(&__control);
173 	return (__control & _ROUND_MASK);
174 }
175 
176 static __inline int
fesetround(int __round)177 fesetround(int __round)
178 {
179 	int __mxcsr, __control;
180 
181 	if (__round & ~_ROUND_MASK)
182 		return (-1);
183 
184 	__fnstcw(&__control);
185 	__control &= ~_ROUND_MASK;
186 	__control |= __round;
187 	__fldcw(__control);
188 
189 	if (__HAS_SSE()) {
190 		__stmxcsr(&__mxcsr);
191 		__mxcsr &= ~(_ROUND_MASK << _SSE_ROUND_SHIFT);
192 		__mxcsr |= __round << _SSE_ROUND_SHIFT;
193 		__ldmxcsr(__mxcsr);
194 	}
195 
196 	return (0);
197 }
198 
199 int fegetenv(fenv_t *__envp);
200 int feholdexcept(fenv_t *__envp);
201 
202 static __inline int
fesetenv(const fenv_t * __envp)203 fesetenv(const fenv_t *__envp)
204 {
205 	fenv_t __env = *__envp;
206 	int __mxcsr;
207 
208 	__mxcsr = __get_mxcsr(__env);
209 	__set_mxcsr(__env, 0xffffffff);
210 	__fldenv(__env);
211 	if (__HAS_SSE())
212 		__ldmxcsr(__mxcsr);
213 	return (0);
214 }
215 
216 int feupdateenv(const fenv_t *__envp);
217 
218 #if __BSD_VISIBLE
219 
220 int feenableexcept(int __mask);
221 int fedisableexcept(int __mask);
222 
223 static __inline int
fegetexcept(void)224 fegetexcept(void)
225 {
226 	int __control;
227 
228 	/*
229 	 * We assume that the masks for the x87 and the SSE unit are
230 	 * the same.
231 	 */
232 	__fnstcw(&__control);
233 	return (~__control & FE_ALL_EXCEPT);
234 }
235 
236 #endif /* __BSD_VISIBLE */
237 
238 __END_DECLS
239 
240 #endif	/* !_FENV_H_ */
241