]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - lib/msun/i387/fenv.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / lib / msun / i387 / fenv.c
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 #include <sys/cdefs.h>
30 #include <sys/types.h>
31 #include <machine/npx.h>
32 #include "fenv.h"
33
34 const fenv_t __fe_dfl_env = {
35         __INITIAL_NPXCW__,
36         0x0000,
37         0x0000,
38         0x1f80,
39         0xffffffff,
40         { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
41           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff }
42 };
43
44 enum __sse_support __has_sse =
45 #ifdef __SSE__
46         __SSE_YES;
47 #else
48         __SSE_UNK;
49 #endif
50
51 #define getfl(x)        __asm __volatile("pushfl\n\tpopl %0" : "=mr" (*(x)))
52 #define setfl(x)        __asm __volatile("pushl %0\n\tpopfl" : : "g" (x))
53 #define cpuid_dx(x)     __asm __volatile("pushl %%ebx\n\tmovl $1, %%eax\n\t"  \
54                                          "cpuid\n\tpopl %%ebx"                \
55                                         : "=d" (*(x)) : : "eax", "ecx")
56
57 /*
58  * Test for SSE support on this processor.  We need to do this because
59  * we need to use ldmxcsr/stmxcsr to get correct results if any part
60  * of the program was compiled to use SSE floating-point, but we can't
61  * use SSE on older processors.
62  */
63 int
64 __test_sse(void)
65 {
66         int flag, nflag;
67         int dx_features;
68
69         /* Am I a 486? */
70         getfl(&flag);
71         nflag = flag ^ 0x200000;
72         setfl(nflag);
73         getfl(&nflag);
74         if (flag != nflag) {
75                 /* Not a 486, so CPUID should work. */
76                 cpuid_dx(&dx_features);
77                 if (dx_features & 0x2000000) {
78                         __has_sse = __SSE_YES;
79                         return (1);
80                 }
81         }
82         __has_sse = __SSE_NO;
83         return (0);
84 }
85
86 int
87 fesetexceptflag(const fexcept_t *flagp, int excepts)
88 {
89         fenv_t env;
90         __uint32_t mxcsr;
91
92         __fnstenv(&env);
93         env.__status &= ~excepts;
94         env.__status |= *flagp & excepts;
95         __fldenv(env);
96
97         if (__HAS_SSE()) {
98                 __stmxcsr(&mxcsr);
99                 mxcsr &= ~excepts;
100                 mxcsr |= *flagp & excepts;
101                 __ldmxcsr(mxcsr);
102         }
103
104         return (0);
105 }
106
107 int
108 feraiseexcept(int excepts)
109 {
110         fexcept_t ex = excepts;
111
112         fesetexceptflag(&ex, excepts);
113         __fwait();
114         return (0);
115 }
116
117 int
118 fegetenv(fenv_t *envp)
119 {
120         __uint32_t mxcsr;
121
122         __fnstenv(envp);
123         /*
124          * fnstenv masks all exceptions, so we need to restore
125          * the old control word to avoid this side effect.
126          */
127         __fldcw(envp->__control);
128         if (__HAS_SSE()) {
129                 __stmxcsr(&mxcsr);
130                 __set_mxcsr(*envp, mxcsr);
131         }
132         return (0);
133 }
134
135 int
136 feholdexcept(fenv_t *envp)
137 {
138         __uint32_t mxcsr;
139
140         __fnstenv(envp);
141         __fnclex();
142         if (__HAS_SSE()) {
143                 __stmxcsr(&mxcsr);
144                 __set_mxcsr(*envp, mxcsr);
145                 mxcsr &= ~FE_ALL_EXCEPT;
146                 mxcsr |= FE_ALL_EXCEPT << _SSE_EMASK_SHIFT;
147                 __ldmxcsr(mxcsr);
148         }
149         return (0);
150 }
151
152 int
153 feupdateenv(const fenv_t *envp)
154 {
155         __uint32_t mxcsr;
156         __uint16_t status;
157
158         __fnstsw(&status);
159         if (__HAS_SSE())
160                 __stmxcsr(&mxcsr);
161         else
162                 mxcsr = 0;
163         fesetenv(envp);
164         feraiseexcept((mxcsr | status) & FE_ALL_EXCEPT);
165         return (0);
166 }
167
168 int
169 __feenableexcept(int mask)
170 {
171         __uint32_t mxcsr, omask;
172         __uint16_t control;
173
174         mask &= FE_ALL_EXCEPT;
175         __fnstcw(&control);
176         if (__HAS_SSE())
177                 __stmxcsr(&mxcsr);
178         else
179                 mxcsr = 0;
180         omask = ~(control | mxcsr >> _SSE_EMASK_SHIFT) & FE_ALL_EXCEPT;
181         control &= ~mask;
182         __fldcw(control);
183         if (__HAS_SSE()) {
184                 mxcsr &= ~(mask << _SSE_EMASK_SHIFT);
185                 __ldmxcsr(mxcsr);
186         }
187         return (omask);
188 }
189
190 int
191 __fedisableexcept(int mask)
192 {
193         __uint32_t mxcsr, omask;
194         __uint16_t control;
195
196         mask &= FE_ALL_EXCEPT;
197         __fnstcw(&control);
198         if (__HAS_SSE())
199                 __stmxcsr(&mxcsr);
200         else
201                 mxcsr = 0;
202         omask = ~(control | mxcsr >> _SSE_EMASK_SHIFT) & FE_ALL_EXCEPT;
203         control |= mask;
204         __fldcw(control);
205         if (__HAS_SSE()) {
206                 mxcsr |= mask << _SSE_EMASK_SHIFT;
207                 __ldmxcsr(mxcsr);
208         }
209         return (omask);
210 }
211
212 __weak_reference(__feenableexcept, feenableexcept);
213 __weak_reference(__fedisableexcept, fedisableexcept);