Get rid of ASM_TYPE_DIRECTIVE{,_PREFIX}.
[platform/upstream/glibc.git] / sysdeps / i386 / fpu / fenv_private.h
1 #ifndef FENV_PRIVATE_H
2 #define FENV_PRIVATE_H 1
3
4 #include <fenv.h>
5 #include <fpu_control.h>
6
7 #ifdef __SSE2_MATH__
8 # define math_opt_barrier(x) \
9   ({ __typeof(x) __x;                                   \
10      if (sizeof (x) <= sizeof (double))                 \
11        __asm ("" : "=x" (__x) : "0" (x));               \
12      else                                               \
13        __asm ("" : "=t" (__x) : "0" (x));               \
14      __x; })
15 # define math_force_eval(x) \
16   do {                                                  \
17     if (sizeof (x) <= sizeof (double))                  \
18       __asm __volatile ("" : : "x" (x));                \
19     else                                                \
20       __asm __volatile ("" : : "f" (x));                \
21   } while (0)
22 #else
23 # define math_opt_barrier(x) \
24   ({ __typeof (x) __x;                                  \
25      __asm ("" : "=t" (__x) : "0" (x));                 \
26      __x; })
27 # define math_force_eval(x) \
28   do {                                                  \
29     __typeof (x) __x = (x);                             \
30     if (sizeof (x) <= sizeof (double))                  \
31       __asm __volatile ("" : : "m" (__x));              \
32     else                                                \
33       __asm __volatile ("" : : "f" (__x));              \
34   } while (0)
35 #endif
36
37 /* This file is used by both the 32- and 64-bit ports.  The 64-bit port
38    has a field in the fenv_t for the mxcsr; the 32-bit port does not.
39    Instead, we (ab)use the only 32-bit field extant in the struct.  */
40 #ifndef __x86_64__
41 # define __mxcsr        __eip
42 #endif
43
44
45 /* All of these functions are private to libm, and are all used in pairs
46    to save+change the fp state and restore the original state.  Thus we
47    need not care for both the 387 and the sse unit, only the one we're
48    actually using.  */
49
50 #if defined __AVX__ || defined SSE2AVX
51 # define STMXCSR "vstmxcsr"
52 # define LDMXCSR "vldmxcsr"
53 #else
54 # define STMXCSR "stmxcsr"
55 # define LDMXCSR "ldmxcsr"
56 #endif
57
58 static __always_inline void
59 libc_feholdexcept_sse (fenv_t *e)
60 {
61   unsigned int mxcsr;
62   asm (STMXCSR " %0" : "=m" (*&mxcsr));
63   e->__mxcsr = mxcsr;
64   mxcsr = (mxcsr | 0x1f80) & ~0x3f;
65   asm volatile (LDMXCSR " %0" : : "m" (*&mxcsr));
66 }
67
68 static __always_inline void
69 libc_feholdexcept_387 (fenv_t *e)
70 {
71   /* Recall that fnstenv has a side-effect of masking exceptions.
72      Clobber all of the fp registers so that the TOS field is 0.  */
73   asm volatile ("fnstenv %0; fnclex"
74                 : "=m"(*e)
75                 : : "st", "st(1)", "st(2)", "st(3)",
76                     "st(4)", "st(5)", "st(6)", "st(7)");
77 }
78
79 static __always_inline void
80 libc_feholdexcept_setround_sse (fenv_t *e, int r)
81 {
82   unsigned int mxcsr;
83   asm (STMXCSR " %0" : "=m" (*&mxcsr));
84   e->__mxcsr = mxcsr;
85   mxcsr = ((mxcsr | 0x1f80) & ~0x603f) | (r << 3);
86   asm volatile (LDMXCSR " %0" : : "m" (*&mxcsr));
87 }
88
89 /* Set both rounding mode and precision.  A convenience function for use
90    by libc_feholdexcept_setround and libc_feholdexcept_setround_53bit. */
91 static __always_inline void
92 libc_feholdexcept_setround_387_prec (fenv_t *e, int r)
93 {
94   libc_feholdexcept_387 (e);
95
96   fpu_control_t cw = e->__control_word;
97   cw &= ~(_FPU_RC_ZERO | _FPU_EXTENDED);
98   cw |= r | 0x3f;
99   _FPU_SETCW (cw);
100 }
101
102 static __always_inline void
103 libc_feholdexcept_setround_387 (fenv_t *e, int r)
104 {
105   libc_feholdexcept_setround_387_prec (e, r | _FPU_EXTENDED);
106 }
107
108 static __always_inline void
109 libc_feholdexcept_setround_387_53bit (fenv_t *e, int r)
110 {
111   libc_feholdexcept_setround_387_prec (e, r | _FPU_DOUBLE);
112 }
113
114 static __always_inline int
115 libc_fetestexcept_sse (int e)
116 {
117   unsigned int mxcsr;
118   asm volatile (STMXCSR " %0" : "=m" (*&mxcsr));
119   return mxcsr & e & FE_ALL_EXCEPT;
120 }
121
122 static __always_inline int
123 libc_fetestexcept_387 (int ex)
124 {
125   fexcept_t temp;
126   asm volatile ("fnstsw %0" : "=a" (temp));
127   return temp & ex & FE_ALL_EXCEPT;
128 }
129
130 static __always_inline void
131 libc_fesetenv_sse (fenv_t *e)
132 {
133   asm volatile (LDMXCSR " %0" : : "m" (e->__mxcsr));
134 }
135
136 static __always_inline void
137 libc_fesetenv_387 (fenv_t *e)
138 {
139   /* Clobber all fp registers so that the TOS value we saved earlier is
140      compatible with the current state of the compiler.  */
141   asm volatile ("fldenv %0"
142                 : : "m" (*e)
143                 : "st", "st(1)", "st(2)", "st(3)",
144                   "st(4)", "st(5)", "st(6)", "st(7)");
145 }
146
147 static __always_inline int
148 libc_feupdateenv_test_sse (fenv_t *e, int ex)
149 {
150   unsigned int mxcsr, old_mxcsr, cur_ex;
151   asm volatile (STMXCSR " %0" : "=m" (*&mxcsr));
152   cur_ex = mxcsr & FE_ALL_EXCEPT;
153
154   /* Merge current exceptions with the old environment.  */
155   old_mxcsr = e->__mxcsr;
156   mxcsr = old_mxcsr | cur_ex;
157   asm volatile (LDMXCSR " %0" : : "m" (*&mxcsr));
158
159   /* Raise SIGFPE for any new exceptions since the hold.  Expect that
160      the normal environment has all exceptions masked.  */
161   if (__builtin_expect ((old_mxcsr >> 7) & cur_ex, 0))
162     __feraiseexcept (cur_ex);
163
164   /* Test for exceptions raised since the hold.  */
165   return cur_ex & ex;
166 }
167
168 static __always_inline int
169 libc_feupdateenv_test_387 (fenv_t *e, int ex)
170 {
171   fexcept_t cur_ex;
172
173   /* Save current exceptions.  */
174   asm volatile ("fnstsw %0" : "=a" (cur_ex));
175   cur_ex &= FE_ALL_EXCEPT;
176
177   /* Reload original environment.  */
178   libc_fesetenv_387 (e);
179
180   /* Merge current exceptions.  */
181   __feraiseexcept (cur_ex);
182
183   /* Test for exceptions raised since the hold.  */
184   return cur_ex & ex;
185 }
186
187 static __always_inline void
188 libc_feupdateenv_sse (fenv_t *e)
189 {
190   libc_feupdateenv_test_sse (e, 0);
191 }
192
193 static __always_inline void
194 libc_feupdateenv_387 (fenv_t *e)
195 {
196   libc_feupdateenv_test_387 (e, 0);
197 }
198
199 static __always_inline void
200 libc_feholdsetround_sse (fenv_t *e, int r)
201 {
202   unsigned int mxcsr;
203   asm (STMXCSR " %0" : "=m" (*&mxcsr));
204   e->__mxcsr = mxcsr;
205   mxcsr = (mxcsr & ~0x6000) | (r << 3);
206   asm volatile (LDMXCSR " %0" : : "m" (*&mxcsr));
207 }
208
209 static __always_inline void
210 libc_feholdsetround_387_prec (fenv_t *e, int r)
211 {
212   fpu_control_t cw;
213
214   _FPU_GETCW (cw);
215   e->__control_word = cw;
216   cw &= ~(_FPU_RC_ZERO | _FPU_EXTENDED);
217   cw |= r;
218   _FPU_SETCW (cw);
219 }
220
221 static __always_inline void
222 libc_feholdsetround_387 (fenv_t *e, int r)
223 {
224   libc_feholdsetround_387_prec (e, r | _FPU_EXTENDED);
225 }
226
227 static __always_inline void
228 libc_feholdsetround_387_53bit (fenv_t *e, int r)
229 {
230   libc_feholdsetround_387_prec (e, r | _FPU_DOUBLE);
231 }
232
233 static __always_inline void
234 libc_feresetround_sse (fenv_t *e)
235 {
236   unsigned int mxcsr;
237   asm (STMXCSR " %0" : "=m" (*&mxcsr));
238   mxcsr = (mxcsr & ~0x6000) | (e->__mxcsr & 0x6000);
239   asm volatile (LDMXCSR " %0" : : "m" (*&mxcsr));
240 }
241
242 static __always_inline void
243 libc_feresetround_387 (fenv_t *e)
244 {
245   _FPU_SETCW (e->__control_word);
246 }
247
248 #ifdef __SSE_MATH__
249 # define libc_feholdexceptf             libc_feholdexcept_sse
250 # define libc_feholdexcept_setroundf    libc_feholdexcept_setround_sse
251 # define libc_fetestexceptf             libc_fetestexcept_sse
252 # define libc_fesetenvf                 libc_fesetenv_sse
253 # define libc_feupdateenv_testf         libc_feupdateenv_test_sse
254 # define libc_feupdateenvf              libc_feupdateenv_sse
255 # define libc_feholdsetroundf           libc_feholdsetround_sse
256 # define libc_feresetroundf             libc_feresetround_sse
257 #else
258 # define libc_feholdexceptf             libc_feholdexcept_387
259 # define libc_feholdexcept_setroundf    libc_feholdexcept_setround_387
260 # define libc_fetestexceptf             libc_fetestexcept_387
261 # define libc_fesetenvf                 libc_fesetenv_387
262 # define libc_feupdateenv_testf         libc_feupdateenv_test_387
263 # define libc_feupdateenvf              libc_feupdateenv_387
264 # define libc_feholdsetroundf           libc_feholdsetround_387
265 # define libc_feresetroundf             libc_feresetround_387
266 #endif /* __SSE_MATH__ */
267
268 #ifdef __SSE2_MATH__
269 # define libc_feholdexcept              libc_feholdexcept_sse
270 # define libc_feholdexcept_setround     libc_feholdexcept_setround_sse
271 # define libc_fetestexcept              libc_fetestexcept_sse
272 # define libc_fesetenv                  libc_fesetenv_sse
273 # define libc_feupdateenv_test          libc_feupdateenv_test_sse
274 # define libc_feupdateenv               libc_feupdateenv_sse
275 # define libc_feholdsetround            libc_feholdsetround_sse
276 # define libc_feresetround              libc_feresetround_sse
277 #else
278 # define libc_feholdexcept              libc_feholdexcept_387
279 # define libc_feholdexcept_setround     libc_feholdexcept_setround_387
280 # define libc_fetestexcept              libc_fetestexcept_387
281 # define libc_fesetenv                  libc_fesetenv_387
282 # define libc_feupdateenv_test          libc_feupdateenv_test_387
283 # define libc_feupdateenv               libc_feupdateenv_387
284 # define libc_feholdsetround            libc_feholdsetround_387
285 # define libc_feresetround              libc_feresetround_387
286 #endif /* __SSE2_MATH__ */
287
288 #define libc_feholdexceptl              libc_feholdexcept_387
289 #define libc_feholdexcept_setroundl     libc_feholdexcept_setround_387
290 #define libc_fetestexceptl              libc_fetestexcept_387
291 #define libc_fesetenvl                  libc_fesetenv_387
292 #define libc_feupdateenv_testl          libc_feupdateenv_test_387
293 #define libc_feupdateenvl               libc_feupdateenv_387
294 #define libc_feholdsetroundl            libc_feholdsetround_387
295 #define libc_feresetroundl              libc_feresetround_387
296
297 #ifndef __SSE2_MATH__
298 # define libc_feholdexcept_setround_53bit libc_feholdexcept_setround_387_53bit
299 # define libc_feholdsetround_53bit      libc_feholdsetround_387_53bit
300 #endif
301
302 #undef __mxcsr
303
304 #endif /* FENV_PRIVATE_H */