xref: /aosp_15_r20/bionic/libm/fenv-x86.c (revision 8d67ca893c1523eb926b9080dbe4e2ffd2a27ba1)
1*8d67ca89SAndroid Build Coastguard Worker /*-
2*8d67ca89SAndroid Build Coastguard Worker  * Copyright (c) 2004-2005 David Schultz <[email protected]>
3*8d67ca89SAndroid Build Coastguard Worker  * All rights reserved.
4*8d67ca89SAndroid Build Coastguard Worker  *
5*8d67ca89SAndroid Build Coastguard Worker  * Redistribution and use in source and binary forms, with or without
6*8d67ca89SAndroid Build Coastguard Worker  * modification, are permitted provided that the following conditions
7*8d67ca89SAndroid Build Coastguard Worker  * are met:
8*8d67ca89SAndroid Build Coastguard Worker  * 1. Redistributions of source code must retain the above copyright
9*8d67ca89SAndroid Build Coastguard Worker  *    notice, this list of conditions and the following disclaimer.
10*8d67ca89SAndroid Build Coastguard Worker  * 2. Redistributions in binary form must reproduce the above copyright
11*8d67ca89SAndroid Build Coastguard Worker  *    notice, this list of conditions and the following disclaimer in the
12*8d67ca89SAndroid Build Coastguard Worker  *    documentation and/or other materials provided with the distribution.
13*8d67ca89SAndroid Build Coastguard Worker  *
14*8d67ca89SAndroid Build Coastguard Worker  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15*8d67ca89SAndroid Build Coastguard Worker  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16*8d67ca89SAndroid Build Coastguard Worker  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17*8d67ca89SAndroid Build Coastguard Worker  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18*8d67ca89SAndroid Build Coastguard Worker  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19*8d67ca89SAndroid Build Coastguard Worker  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20*8d67ca89SAndroid Build Coastguard Worker  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21*8d67ca89SAndroid Build Coastguard Worker  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22*8d67ca89SAndroid Build Coastguard Worker  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23*8d67ca89SAndroid Build Coastguard Worker  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24*8d67ca89SAndroid Build Coastguard Worker  * SUCH DAMAGE.
25*8d67ca89SAndroid Build Coastguard Worker  *
26*8d67ca89SAndroid Build Coastguard Worker  * $FreeBSD: src/lib/msun/i387/fenv.c,v 1.2 2005/03/17 22:21:46 das Exp $
27*8d67ca89SAndroid Build Coastguard Worker  */
28*8d67ca89SAndroid Build Coastguard Worker 
29*8d67ca89SAndroid Build Coastguard Worker #include <sys/cdefs.h>
30*8d67ca89SAndroid Build Coastguard Worker #include <sys/types.h>
31*8d67ca89SAndroid Build Coastguard Worker #include "fenv.h"
32*8d67ca89SAndroid Build Coastguard Worker 
33*8d67ca89SAndroid Build Coastguard Worker #define ROUND_MASK   (FE_TONEAREST | FE_DOWNWARD | FE_UPWARD | FE_TOWARDZERO)
34*8d67ca89SAndroid Build Coastguard Worker 
35*8d67ca89SAndroid Build Coastguard Worker /*
36*8d67ca89SAndroid Build Coastguard Worker  * The hardware default control word for i387's and later coprocessors is
37*8d67ca89SAndroid Build Coastguard Worker  * 0x37F, giving:
38*8d67ca89SAndroid Build Coastguard Worker  *
39*8d67ca89SAndroid Build Coastguard Worker  *	round to nearest
40*8d67ca89SAndroid Build Coastguard Worker  *	64-bit precision
41*8d67ca89SAndroid Build Coastguard Worker  *	all exceptions masked.
42*8d67ca89SAndroid Build Coastguard Worker  *
43*8d67ca89SAndroid Build Coastguard Worker  * We modify the affine mode bit and precision bits in this to give:
44*8d67ca89SAndroid Build Coastguard Worker  *
45*8d67ca89SAndroid Build Coastguard Worker  *	affine mode for 287's (if they work at all) (1 in bitfield 1<<12)
46*8d67ca89SAndroid Build Coastguard Worker  *	53-bit precision (2 in bitfield 3<<8)
47*8d67ca89SAndroid Build Coastguard Worker  *
48*8d67ca89SAndroid Build Coastguard Worker  * 64-bit precision often gives bad results with high level languages
49*8d67ca89SAndroid Build Coastguard Worker  * because it makes the results of calculations depend on whether
50*8d67ca89SAndroid Build Coastguard Worker  * intermediate values are stored in memory or in FPU registers.
51*8d67ca89SAndroid Build Coastguard Worker  */
52*8d67ca89SAndroid Build Coastguard Worker #define	__INITIAL_NPXCW__	0x127F
53*8d67ca89SAndroid Build Coastguard Worker #define	__INITIAL_MXCSR__	0x1F80
54*8d67ca89SAndroid Build Coastguard Worker 
55*8d67ca89SAndroid Build Coastguard Worker /*
56*8d67ca89SAndroid Build Coastguard Worker  * As compared to the x87 control word, the SSE unit's control word
57*8d67ca89SAndroid Build Coastguard Worker  * has the rounding control bits offset by 3 and the exception mask
58*8d67ca89SAndroid Build Coastguard Worker  * bits offset by 7.
59*8d67ca89SAndroid Build Coastguard Worker  */
60*8d67ca89SAndroid Build Coastguard Worker #define _SSE_ROUND_SHIFT 3
61*8d67ca89SAndroid Build Coastguard Worker #define _SSE_EMASK_SHIFT 7
62*8d67ca89SAndroid Build Coastguard Worker 
63*8d67ca89SAndroid Build Coastguard Worker const fenv_t __fe_dfl_env = {
64*8d67ca89SAndroid Build Coastguard Worker   __INITIAL_NPXCW__, /*__control*/
65*8d67ca89SAndroid Build Coastguard Worker   0x0000,            /*__mxcsr_hi*/
66*8d67ca89SAndroid Build Coastguard Worker   0x0000,            /*__status*/
67*8d67ca89SAndroid Build Coastguard Worker   0x1f80,            /*__mxcsr_lo*/
68*8d67ca89SAndroid Build Coastguard Worker   0xffffffff,        /*__tag*/
69*8d67ca89SAndroid Build Coastguard Worker   { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
70*8d67ca89SAndroid Build Coastguard Worker     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff } /*__other*/
71*8d67ca89SAndroid Build Coastguard Worker };
72*8d67ca89SAndroid Build Coastguard Worker 
73*8d67ca89SAndroid Build Coastguard Worker #define __fldcw(__cw)           __asm volatile("fldcw %0" : : "m" (__cw))
74*8d67ca89SAndroid Build Coastguard Worker #define __fldenv(__env)         __asm volatile("fldenv %0" : : "m" (__env))
75*8d67ca89SAndroid Build Coastguard Worker #define __fldenvx(__env)        __asm volatile("fldenv %0" : : "m" (__env)  \
76*8d67ca89SAndroid Build Coastguard Worker                                 : "st", "st(1)", "st(2)", "st(3)", "st(4)",   \
77*8d67ca89SAndroid Build Coastguard Worker                                 "st(5)", "st(6)", "st(7)")
78*8d67ca89SAndroid Build Coastguard Worker #define __fnclex()              __asm volatile("fnclex")
79*8d67ca89SAndroid Build Coastguard Worker #define __fnstenv(__env)        __asm volatile("fnstenv %0" : "=m" (*(__env)))
80*8d67ca89SAndroid Build Coastguard Worker #define __fnstcw(__cw)          __asm volatile("fnstcw %0" : "=m" (*(__cw)))
81*8d67ca89SAndroid Build Coastguard Worker #define __fnstsw(__sw)          __asm volatile("fnstsw %0" : "=am" (*(__sw)))
82*8d67ca89SAndroid Build Coastguard Worker #define __fwait()               __asm volatile("fwait")
83*8d67ca89SAndroid Build Coastguard Worker #define __ldmxcsr(__csr)        __asm volatile("ldmxcsr %0" : : "m" (__csr))
84*8d67ca89SAndroid Build Coastguard Worker #define __stmxcsr(__csr)        __asm volatile("stmxcsr %0" : "=m" (*(__csr)))
85*8d67ca89SAndroid Build Coastguard Worker 
86*8d67ca89SAndroid Build Coastguard Worker /* After testing for SSE support once, we cache the result in __has_sse. */
87*8d67ca89SAndroid Build Coastguard Worker enum __sse_support { __SSE_YES, __SSE_NO, __SSE_UNK };
88*8d67ca89SAndroid Build Coastguard Worker #ifdef __SSE__
89*8d67ca89SAndroid Build Coastguard Worker #define __HAS_SSE()     1
90*8d67ca89SAndroid Build Coastguard Worker #else
91*8d67ca89SAndroid Build Coastguard Worker #define __HAS_SSE()     (__has_sse == __SSE_YES ||                      \
92*8d67ca89SAndroid Build Coastguard Worker                         (__has_sse == __SSE_UNK && __test_sse()))
93*8d67ca89SAndroid Build Coastguard Worker #endif
94*8d67ca89SAndroid Build Coastguard Worker 
95*8d67ca89SAndroid Build Coastguard Worker enum __sse_support __has_sse =
96*8d67ca89SAndroid Build Coastguard Worker #ifdef __SSE__
97*8d67ca89SAndroid Build Coastguard Worker   __SSE_YES;
98*8d67ca89SAndroid Build Coastguard Worker #else
99*8d67ca89SAndroid Build Coastguard Worker   __SSE_UNK;
100*8d67ca89SAndroid Build Coastguard Worker #endif
101*8d67ca89SAndroid Build Coastguard Worker 
102*8d67ca89SAndroid Build Coastguard Worker #ifndef __SSE__
103*8d67ca89SAndroid Build Coastguard Worker #define getfl(x)    __asm volatile("pushfl\n\tpopl %0" : "=mr" (*(x)))
104*8d67ca89SAndroid Build Coastguard Worker #define setfl(x)    __asm volatile("pushl %0\n\tpopfl" : : "g" (x))
105*8d67ca89SAndroid Build Coastguard Worker #define cpuid_dx(x) __asm volatile("pushl %%ebx\n\tmovl $1, %%eax\n\t"  \
106*8d67ca89SAndroid Build Coastguard Worker                     "cpuid\n\tpopl %%ebx"          \
107*8d67ca89SAndroid Build Coastguard Worker                     : "=d" (*(x)) : : "eax", "ecx")
108*8d67ca89SAndroid Build Coastguard Worker 
109*8d67ca89SAndroid Build Coastguard Worker /*
110*8d67ca89SAndroid Build Coastguard Worker  * Test for SSE support on this processor.  We need to do this because
111*8d67ca89SAndroid Build Coastguard Worker  * we need to use ldmxcsr/stmxcsr to get correct results if any part
112*8d67ca89SAndroid Build Coastguard Worker  * of the program was compiled to use SSE floating-point, but we can't
113*8d67ca89SAndroid Build Coastguard Worker  * use SSE on older processors.
114*8d67ca89SAndroid Build Coastguard Worker  */
115*8d67ca89SAndroid Build Coastguard Worker int
__test_sse(void)116*8d67ca89SAndroid Build Coastguard Worker __test_sse(void)
117*8d67ca89SAndroid Build Coastguard Worker {
118*8d67ca89SAndroid Build Coastguard Worker   int flag, nflag;
119*8d67ca89SAndroid Build Coastguard Worker   int dx_features;
120*8d67ca89SAndroid Build Coastguard Worker 
121*8d67ca89SAndroid Build Coastguard Worker   /* Am I a 486? */
122*8d67ca89SAndroid Build Coastguard Worker   getfl(&flag);
123*8d67ca89SAndroid Build Coastguard Worker   nflag = flag ^ 0x200000;
124*8d67ca89SAndroid Build Coastguard Worker   setfl(nflag);
125*8d67ca89SAndroid Build Coastguard Worker   getfl(&nflag);
126*8d67ca89SAndroid Build Coastguard Worker   if (flag != nflag) {
127*8d67ca89SAndroid Build Coastguard Worker     /* Not a 486, so CPUID should work. */
128*8d67ca89SAndroid Build Coastguard Worker     cpuid_dx(&dx_features);
129*8d67ca89SAndroid Build Coastguard Worker     if (dx_features & 0x2000000) {
130*8d67ca89SAndroid Build Coastguard Worker       __has_sse = __SSE_YES;
131*8d67ca89SAndroid Build Coastguard Worker       return (1);
132*8d67ca89SAndroid Build Coastguard Worker     }
133*8d67ca89SAndroid Build Coastguard Worker   }
134*8d67ca89SAndroid Build Coastguard Worker   __has_sse = __SSE_NO;
135*8d67ca89SAndroid Build Coastguard Worker   return (0);
136*8d67ca89SAndroid Build Coastguard Worker }
137*8d67ca89SAndroid Build Coastguard Worker #endif /* __SSE__ */
138*8d67ca89SAndroid Build Coastguard Worker 
139*8d67ca89SAndroid Build Coastguard Worker int
fesetexceptflag(const fexcept_t * flagp,int excepts)140*8d67ca89SAndroid Build Coastguard Worker fesetexceptflag(const fexcept_t *flagp, int excepts)
141*8d67ca89SAndroid Build Coastguard Worker {
142*8d67ca89SAndroid Build Coastguard Worker   fenv_t env;
143*8d67ca89SAndroid Build Coastguard Worker   __uint32_t mxcsr;
144*8d67ca89SAndroid Build Coastguard Worker 
145*8d67ca89SAndroid Build Coastguard Worker   excepts &= FE_ALL_EXCEPT;
146*8d67ca89SAndroid Build Coastguard Worker   if (excepts) { /* Do nothing if excepts is 0 */
147*8d67ca89SAndroid Build Coastguard Worker     __fnstenv(&env);
148*8d67ca89SAndroid Build Coastguard Worker     env.__status &= ~excepts;
149*8d67ca89SAndroid Build Coastguard Worker     env.__status |= *flagp & excepts;
150*8d67ca89SAndroid Build Coastguard Worker     __fnclex();
151*8d67ca89SAndroid Build Coastguard Worker     __fldenv(env);
152*8d67ca89SAndroid Build Coastguard Worker     if (__HAS_SSE()) {
153*8d67ca89SAndroid Build Coastguard Worker       __stmxcsr(&mxcsr);
154*8d67ca89SAndroid Build Coastguard Worker       mxcsr &= ~excepts;
155*8d67ca89SAndroid Build Coastguard Worker       mxcsr |= *flagp & excepts;
156*8d67ca89SAndroid Build Coastguard Worker       __ldmxcsr(mxcsr);
157*8d67ca89SAndroid Build Coastguard Worker     }
158*8d67ca89SAndroid Build Coastguard Worker   }
159*8d67ca89SAndroid Build Coastguard Worker 
160*8d67ca89SAndroid Build Coastguard Worker   return (0);
161*8d67ca89SAndroid Build Coastguard Worker }
162*8d67ca89SAndroid Build Coastguard Worker 
163*8d67ca89SAndroid Build Coastguard Worker int
feraiseexcept(int excepts)164*8d67ca89SAndroid Build Coastguard Worker feraiseexcept(int excepts)
165*8d67ca89SAndroid Build Coastguard Worker {
166*8d67ca89SAndroid Build Coastguard Worker   fexcept_t ex = excepts;
167*8d67ca89SAndroid Build Coastguard Worker 
168*8d67ca89SAndroid Build Coastguard Worker   fesetexceptflag(&ex, excepts);
169*8d67ca89SAndroid Build Coastguard Worker   __fwait();
170*8d67ca89SAndroid Build Coastguard Worker   return (0);
171*8d67ca89SAndroid Build Coastguard Worker }
172*8d67ca89SAndroid Build Coastguard Worker 
173*8d67ca89SAndroid Build Coastguard Worker int
fegetenv(fenv_t * envp)174*8d67ca89SAndroid Build Coastguard Worker fegetenv(fenv_t *envp)
175*8d67ca89SAndroid Build Coastguard Worker {
176*8d67ca89SAndroid Build Coastguard Worker   __uint32_t mxcsr;
177*8d67ca89SAndroid Build Coastguard Worker 
178*8d67ca89SAndroid Build Coastguard Worker   __fnstenv(envp);
179*8d67ca89SAndroid Build Coastguard Worker   /*
180*8d67ca89SAndroid Build Coastguard Worker    * fnstenv masks all exceptions, so we need to restore
181*8d67ca89SAndroid Build Coastguard Worker    * the old control word to avoid this side effect.
182*8d67ca89SAndroid Build Coastguard Worker    */
183*8d67ca89SAndroid Build Coastguard Worker   __fldcw(envp->__control);
184*8d67ca89SAndroid Build Coastguard Worker   if (__HAS_SSE()) {
185*8d67ca89SAndroid Build Coastguard Worker     __stmxcsr(&mxcsr);
186*8d67ca89SAndroid Build Coastguard Worker     envp->__mxcsr_hi = mxcsr >> 16;
187*8d67ca89SAndroid Build Coastguard Worker     envp->__mxcsr_lo = mxcsr & 0xffff;
188*8d67ca89SAndroid Build Coastguard Worker   }
189*8d67ca89SAndroid Build Coastguard Worker   return (0);
190*8d67ca89SAndroid Build Coastguard Worker }
191*8d67ca89SAndroid Build Coastguard Worker 
192*8d67ca89SAndroid Build Coastguard Worker int
feholdexcept(fenv_t * envp)193*8d67ca89SAndroid Build Coastguard Worker feholdexcept(fenv_t *envp)
194*8d67ca89SAndroid Build Coastguard Worker {
195*8d67ca89SAndroid Build Coastguard Worker   __uint32_t mxcsr;
196*8d67ca89SAndroid Build Coastguard Worker   fenv_t env;
197*8d67ca89SAndroid Build Coastguard Worker 
198*8d67ca89SAndroid Build Coastguard Worker   __fnstenv(&env);
199*8d67ca89SAndroid Build Coastguard Worker   *envp = env;
200*8d67ca89SAndroid Build Coastguard Worker   env.__status &= ~FE_ALL_EXCEPT;
201*8d67ca89SAndroid Build Coastguard Worker   env.__control |= FE_ALL_EXCEPT;
202*8d67ca89SAndroid Build Coastguard Worker   __fnclex();
203*8d67ca89SAndroid Build Coastguard Worker   __fldenv(env);
204*8d67ca89SAndroid Build Coastguard Worker   if (__HAS_SSE()) {
205*8d67ca89SAndroid Build Coastguard Worker     __stmxcsr(&mxcsr);
206*8d67ca89SAndroid Build Coastguard Worker     envp->__mxcsr_hi = mxcsr >> 16;
207*8d67ca89SAndroid Build Coastguard Worker     envp->__mxcsr_lo = mxcsr & 0xffff;
208*8d67ca89SAndroid Build Coastguard Worker     mxcsr &= ~FE_ALL_EXCEPT;
209*8d67ca89SAndroid Build Coastguard Worker     mxcsr |= FE_ALL_EXCEPT << _SSE_EMASK_SHIFT;
210*8d67ca89SAndroid Build Coastguard Worker     __ldmxcsr(mxcsr);
211*8d67ca89SAndroid Build Coastguard Worker   }
212*8d67ca89SAndroid Build Coastguard Worker   return (0);
213*8d67ca89SAndroid Build Coastguard Worker }
214*8d67ca89SAndroid Build Coastguard Worker 
215*8d67ca89SAndroid Build Coastguard Worker int
feupdateenv(const fenv_t * envp)216*8d67ca89SAndroid Build Coastguard Worker feupdateenv(const fenv_t *envp)
217*8d67ca89SAndroid Build Coastguard Worker {
218*8d67ca89SAndroid Build Coastguard Worker   __uint32_t mxcsr;
219*8d67ca89SAndroid Build Coastguard Worker   __uint16_t status;
220*8d67ca89SAndroid Build Coastguard Worker 
221*8d67ca89SAndroid Build Coastguard Worker   __fnstsw(&status);
222*8d67ca89SAndroid Build Coastguard Worker   if (__HAS_SSE()) {
223*8d67ca89SAndroid Build Coastguard Worker     __stmxcsr(&mxcsr);
224*8d67ca89SAndroid Build Coastguard Worker   } else {
225*8d67ca89SAndroid Build Coastguard Worker     mxcsr = 0;
226*8d67ca89SAndroid Build Coastguard Worker   }
227*8d67ca89SAndroid Build Coastguard Worker   fesetenv(envp);
228*8d67ca89SAndroid Build Coastguard Worker   feraiseexcept((mxcsr | status) & FE_ALL_EXCEPT);
229*8d67ca89SAndroid Build Coastguard Worker   return (0);
230*8d67ca89SAndroid Build Coastguard Worker }
231*8d67ca89SAndroid Build Coastguard Worker 
232*8d67ca89SAndroid Build Coastguard Worker int
feenableexcept(int mask)233*8d67ca89SAndroid Build Coastguard Worker feenableexcept(int mask)
234*8d67ca89SAndroid Build Coastguard Worker {
235*8d67ca89SAndroid Build Coastguard Worker   __uint32_t mxcsr;
236*8d67ca89SAndroid Build Coastguard Worker   __uint16_t control, omask;
237*8d67ca89SAndroid Build Coastguard Worker 
238*8d67ca89SAndroid Build Coastguard Worker   mask &= FE_ALL_EXCEPT;
239*8d67ca89SAndroid Build Coastguard Worker   __fnstcw(&control);
240*8d67ca89SAndroid Build Coastguard Worker   if (__HAS_SSE()) {
241*8d67ca89SAndroid Build Coastguard Worker     __stmxcsr(&mxcsr);
242*8d67ca89SAndroid Build Coastguard Worker   } else {
243*8d67ca89SAndroid Build Coastguard Worker     mxcsr = 0;
244*8d67ca89SAndroid Build Coastguard Worker   }
245*8d67ca89SAndroid Build Coastguard Worker   omask = ~(control | mxcsr >> _SSE_EMASK_SHIFT) & FE_ALL_EXCEPT;
246*8d67ca89SAndroid Build Coastguard Worker   if (mask) {
247*8d67ca89SAndroid Build Coastguard Worker     control &= ~mask;
248*8d67ca89SAndroid Build Coastguard Worker     __fldcw(control);
249*8d67ca89SAndroid Build Coastguard Worker     if (__HAS_SSE()) {
250*8d67ca89SAndroid Build Coastguard Worker       mxcsr &= ~(mask << _SSE_EMASK_SHIFT);
251*8d67ca89SAndroid Build Coastguard Worker       __ldmxcsr(mxcsr);
252*8d67ca89SAndroid Build Coastguard Worker     }
253*8d67ca89SAndroid Build Coastguard Worker   }
254*8d67ca89SAndroid Build Coastguard Worker   return (omask);
255*8d67ca89SAndroid Build Coastguard Worker }
256*8d67ca89SAndroid Build Coastguard Worker 
257*8d67ca89SAndroid Build Coastguard Worker int
fedisableexcept(int mask)258*8d67ca89SAndroid Build Coastguard Worker fedisableexcept(int mask)
259*8d67ca89SAndroid Build Coastguard Worker {
260*8d67ca89SAndroid Build Coastguard Worker   __uint32_t mxcsr;
261*8d67ca89SAndroid Build Coastguard Worker   __uint16_t control, omask;
262*8d67ca89SAndroid Build Coastguard Worker 
263*8d67ca89SAndroid Build Coastguard Worker   mask &= FE_ALL_EXCEPT;
264*8d67ca89SAndroid Build Coastguard Worker   __fnstcw(&control);
265*8d67ca89SAndroid Build Coastguard Worker   if (__HAS_SSE()) {
266*8d67ca89SAndroid Build Coastguard Worker     __stmxcsr(&mxcsr);
267*8d67ca89SAndroid Build Coastguard Worker   } else {
268*8d67ca89SAndroid Build Coastguard Worker     mxcsr = 0;
269*8d67ca89SAndroid Build Coastguard Worker   }
270*8d67ca89SAndroid Build Coastguard Worker   omask = ~(control | mxcsr >> _SSE_EMASK_SHIFT) & FE_ALL_EXCEPT;
271*8d67ca89SAndroid Build Coastguard Worker   if (mask) {
272*8d67ca89SAndroid Build Coastguard Worker     control |= mask;
273*8d67ca89SAndroid Build Coastguard Worker     __fldcw(control);
274*8d67ca89SAndroid Build Coastguard Worker     if (__HAS_SSE()) {
275*8d67ca89SAndroid Build Coastguard Worker       mxcsr |= mask << _SSE_EMASK_SHIFT;
276*8d67ca89SAndroid Build Coastguard Worker       __ldmxcsr(mxcsr);
277*8d67ca89SAndroid Build Coastguard Worker     }
278*8d67ca89SAndroid Build Coastguard Worker   }
279*8d67ca89SAndroid Build Coastguard Worker   return (omask);
280*8d67ca89SAndroid Build Coastguard Worker }
281*8d67ca89SAndroid Build Coastguard Worker 
282*8d67ca89SAndroid Build Coastguard Worker int
feclearexcept(int excepts)283*8d67ca89SAndroid Build Coastguard Worker feclearexcept(int excepts)
284*8d67ca89SAndroid Build Coastguard Worker {
285*8d67ca89SAndroid Build Coastguard Worker   fenv_t env;
286*8d67ca89SAndroid Build Coastguard Worker   __uint32_t mxcsr;
287*8d67ca89SAndroid Build Coastguard Worker 
288*8d67ca89SAndroid Build Coastguard Worker   excepts &= FE_ALL_EXCEPT;
289*8d67ca89SAndroid Build Coastguard Worker   if (excepts) { /* Do nothing if excepts is 0 */
290*8d67ca89SAndroid Build Coastguard Worker     __fnstenv(&env);
291*8d67ca89SAndroid Build Coastguard Worker     env.__status &= ~excepts;
292*8d67ca89SAndroid Build Coastguard Worker     __fnclex();
293*8d67ca89SAndroid Build Coastguard Worker     __fldenv(env);
294*8d67ca89SAndroid Build Coastguard Worker     if (__HAS_SSE()) {
295*8d67ca89SAndroid Build Coastguard Worker       __stmxcsr(&mxcsr);
296*8d67ca89SAndroid Build Coastguard Worker       mxcsr &= ~excepts;
297*8d67ca89SAndroid Build Coastguard Worker       __ldmxcsr(mxcsr);
298*8d67ca89SAndroid Build Coastguard Worker     }
299*8d67ca89SAndroid Build Coastguard Worker   }
300*8d67ca89SAndroid Build Coastguard Worker   return (0);
301*8d67ca89SAndroid Build Coastguard Worker }
302*8d67ca89SAndroid Build Coastguard Worker 
303*8d67ca89SAndroid Build Coastguard Worker int
fegetexceptflag(fexcept_t * flagp,int excepts)304*8d67ca89SAndroid Build Coastguard Worker fegetexceptflag(fexcept_t *flagp, int excepts)
305*8d67ca89SAndroid Build Coastguard Worker {
306*8d67ca89SAndroid Build Coastguard Worker   __uint32_t mxcsr;
307*8d67ca89SAndroid Build Coastguard Worker   __uint16_t status;
308*8d67ca89SAndroid Build Coastguard Worker 
309*8d67ca89SAndroid Build Coastguard Worker   excepts &= FE_ALL_EXCEPT;
310*8d67ca89SAndroid Build Coastguard Worker   __fnstsw(&status);
311*8d67ca89SAndroid Build Coastguard Worker   if (__HAS_SSE()) {
312*8d67ca89SAndroid Build Coastguard Worker     __stmxcsr(&mxcsr);
313*8d67ca89SAndroid Build Coastguard Worker   } else {
314*8d67ca89SAndroid Build Coastguard Worker     mxcsr = 0;
315*8d67ca89SAndroid Build Coastguard Worker   }
316*8d67ca89SAndroid Build Coastguard Worker   *flagp = (status | mxcsr) & excepts;
317*8d67ca89SAndroid Build Coastguard Worker   return (0);
318*8d67ca89SAndroid Build Coastguard Worker }
319*8d67ca89SAndroid Build Coastguard Worker 
320*8d67ca89SAndroid Build Coastguard Worker int
fetestexcept(int excepts)321*8d67ca89SAndroid Build Coastguard Worker fetestexcept(int excepts)
322*8d67ca89SAndroid Build Coastguard Worker {
323*8d67ca89SAndroid Build Coastguard Worker   __uint32_t mxcsr;
324*8d67ca89SAndroid Build Coastguard Worker   __uint16_t status;
325*8d67ca89SAndroid Build Coastguard Worker 
326*8d67ca89SAndroid Build Coastguard Worker   excepts &= FE_ALL_EXCEPT;
327*8d67ca89SAndroid Build Coastguard Worker   if (excepts) { /* Do nothing if excepts is 0 */
328*8d67ca89SAndroid Build Coastguard Worker     __fnstsw(&status);
329*8d67ca89SAndroid Build Coastguard Worker     if (__HAS_SSE()) {
330*8d67ca89SAndroid Build Coastguard Worker       __stmxcsr(&mxcsr);
331*8d67ca89SAndroid Build Coastguard Worker     } else {
332*8d67ca89SAndroid Build Coastguard Worker       mxcsr = 0;
333*8d67ca89SAndroid Build Coastguard Worker     }
334*8d67ca89SAndroid Build Coastguard Worker     return ((status | mxcsr) & excepts);
335*8d67ca89SAndroid Build Coastguard Worker   }
336*8d67ca89SAndroid Build Coastguard Worker   return (0);
337*8d67ca89SAndroid Build Coastguard Worker }
338*8d67ca89SAndroid Build Coastguard Worker 
339*8d67ca89SAndroid Build Coastguard Worker int
fegetround(void)340*8d67ca89SAndroid Build Coastguard Worker fegetround(void)
341*8d67ca89SAndroid Build Coastguard Worker {
342*8d67ca89SAndroid Build Coastguard Worker   __uint16_t control;
343*8d67ca89SAndroid Build Coastguard Worker 
344*8d67ca89SAndroid Build Coastguard Worker   /*
345*8d67ca89SAndroid Build Coastguard Worker    * We assume that the x87 and the SSE unit agree on the
346*8d67ca89SAndroid Build Coastguard Worker    * rounding mode.  Reading the control word on the x87 turns
347*8d67ca89SAndroid Build Coastguard Worker    * out to be about 5 times faster than reading it on the SSE
348*8d67ca89SAndroid Build Coastguard Worker    * unit on an Opteron 244.
349*8d67ca89SAndroid Build Coastguard Worker    */
350*8d67ca89SAndroid Build Coastguard Worker   __fnstcw(&control);
351*8d67ca89SAndroid Build Coastguard Worker   return (control & ROUND_MASK);
352*8d67ca89SAndroid Build Coastguard Worker }
353*8d67ca89SAndroid Build Coastguard Worker 
354*8d67ca89SAndroid Build Coastguard Worker int
fesetround(int round)355*8d67ca89SAndroid Build Coastguard Worker fesetround(int round)
356*8d67ca89SAndroid Build Coastguard Worker {
357*8d67ca89SAndroid Build Coastguard Worker   __uint32_t mxcsr;
358*8d67ca89SAndroid Build Coastguard Worker   __uint16_t control;
359*8d67ca89SAndroid Build Coastguard Worker 
360*8d67ca89SAndroid Build Coastguard Worker   if (round & ~ROUND_MASK) {
361*8d67ca89SAndroid Build Coastguard Worker     return (-1);
362*8d67ca89SAndroid Build Coastguard Worker   } else {
363*8d67ca89SAndroid Build Coastguard Worker     __fnstcw(&control);
364*8d67ca89SAndroid Build Coastguard Worker     control &= ~ROUND_MASK;
365*8d67ca89SAndroid Build Coastguard Worker     control |= round;
366*8d67ca89SAndroid Build Coastguard Worker     __fldcw(control);
367*8d67ca89SAndroid Build Coastguard Worker     if (__HAS_SSE()) {
368*8d67ca89SAndroid Build Coastguard Worker       __stmxcsr(&mxcsr);
369*8d67ca89SAndroid Build Coastguard Worker       mxcsr &= ~(ROUND_MASK << _SSE_ROUND_SHIFT);
370*8d67ca89SAndroid Build Coastguard Worker       mxcsr |= round << _SSE_ROUND_SHIFT;
371*8d67ca89SAndroid Build Coastguard Worker       __ldmxcsr(mxcsr);
372*8d67ca89SAndroid Build Coastguard Worker     }
373*8d67ca89SAndroid Build Coastguard Worker     return (0);
374*8d67ca89SAndroid Build Coastguard Worker   }
375*8d67ca89SAndroid Build Coastguard Worker }
376*8d67ca89SAndroid Build Coastguard Worker 
377*8d67ca89SAndroid Build Coastguard Worker int
fesetenv(const fenv_t * envp)378*8d67ca89SAndroid Build Coastguard Worker fesetenv(const fenv_t *envp)
379*8d67ca89SAndroid Build Coastguard Worker {
380*8d67ca89SAndroid Build Coastguard Worker   fenv_t env = *envp;
381*8d67ca89SAndroid Build Coastguard Worker   __uint32_t mxcsr;
382*8d67ca89SAndroid Build Coastguard Worker 
383*8d67ca89SAndroid Build Coastguard Worker   mxcsr = (env.__mxcsr_hi << 16) | (env.__mxcsr_lo);
384*8d67ca89SAndroid Build Coastguard Worker   env.__mxcsr_hi = 0xffff;
385*8d67ca89SAndroid Build Coastguard Worker   env.__mxcsr_lo = 0xffff;
386*8d67ca89SAndroid Build Coastguard Worker   /*
387*8d67ca89SAndroid Build Coastguard Worker    * XXX Using fldenvx() instead of fldenv() tells the compiler that this
388*8d67ca89SAndroid Build Coastguard Worker    * instruction clobbers the i387 register stack.  This happens because
389*8d67ca89SAndroid Build Coastguard Worker    * we restore the tag word from the saved environment.  Normally, this
390*8d67ca89SAndroid Build Coastguard Worker    * would happen anyway and we wouldn't care, because the ABI allows
391*8d67ca89SAndroid Build Coastguard Worker    * function calls to clobber the i387 regs.  However, fesetenv() is
392*8d67ca89SAndroid Build Coastguard Worker    * inlined, so we need to be more careful.
393*8d67ca89SAndroid Build Coastguard Worker    */
394*8d67ca89SAndroid Build Coastguard Worker   __fldenvx(env);
395*8d67ca89SAndroid Build Coastguard Worker   if (__HAS_SSE()) {
396*8d67ca89SAndroid Build Coastguard Worker     __ldmxcsr(mxcsr);
397*8d67ca89SAndroid Build Coastguard Worker   }
398*8d67ca89SAndroid Build Coastguard Worker   return (0);
399*8d67ca89SAndroid Build Coastguard Worker }
400*8d67ca89SAndroid Build Coastguard Worker 
401*8d67ca89SAndroid Build Coastguard Worker int
fegetexcept(void)402*8d67ca89SAndroid Build Coastguard Worker fegetexcept(void)
403*8d67ca89SAndroid Build Coastguard Worker {
404*8d67ca89SAndroid Build Coastguard Worker   __uint16_t control;
405*8d67ca89SAndroid Build Coastguard Worker 
406*8d67ca89SAndroid Build Coastguard Worker   /*
407*8d67ca89SAndroid Build Coastguard Worker    * We assume that the masks for the x87 and the SSE unit are
408*8d67ca89SAndroid Build Coastguard Worker    * the same.
409*8d67ca89SAndroid Build Coastguard Worker    */
410*8d67ca89SAndroid Build Coastguard Worker   __fnstcw(&control);
411*8d67ca89SAndroid Build Coastguard Worker   return (~control & FE_ALL_EXCEPT);
412*8d67ca89SAndroid Build Coastguard Worker }
413