1*2c53affbSjmc /* $OpenBSD: fenv.c,v 1.7 2022/12/27 17:10:07 jmc Exp $ */
2b9557bebSmartynas /* $NetBSD: fenv.c,v 1.3 2010/08/01 06:34:38 taca Exp $ */
3b9557bebSmartynas
4b9557bebSmartynas /*-
5b9557bebSmartynas * Copyright (c) 2004-2005 David Schultz <das@FreeBSD.ORG>
6b9557bebSmartynas * All rights reserved.
7b9557bebSmartynas *
8b9557bebSmartynas * Redistribution and use in source and binary forms, with or without
9b9557bebSmartynas * modification, are permitted provided that the following conditions
10b9557bebSmartynas * are met:
11b9557bebSmartynas * 1. Redistributions of source code must retain the above copyright
12b9557bebSmartynas * notice, this list of conditions and the following disclaimer.
13b9557bebSmartynas * 2. Redistributions in binary form must reproduce the above copyright
14b9557bebSmartynas * notice, this list of conditions and the following disclaimer in the
15b9557bebSmartynas * documentation and/or other materials provided with the distribution.
16b9557bebSmartynas *
17b9557bebSmartynas * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18b9557bebSmartynas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19b9557bebSmartynas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20b9557bebSmartynas * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21b9557bebSmartynas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22b9557bebSmartynas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23b9557bebSmartynas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24b9557bebSmartynas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25b9557bebSmartynas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26b9557bebSmartynas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27b9557bebSmartynas * SUCH DAMAGE.
28b9557bebSmartynas */
29b9557bebSmartynas
3083e834beSderaadt #include <sys/types.h>
3183e834beSderaadt #include <sys/time.h>
32b9557bebSmartynas #include <sys/sysctl.h>
334a39ccd0Sderaadt #include <machine/cpu.h>
344a39ccd0Sderaadt #include <machine/npx.h>
35d6f349c8Smartynas
36b9557bebSmartynas #include <fenv.h>
37b9557bebSmartynas
38b9557bebSmartynas /*
39b9557bebSmartynas * The following constant represents the default floating-point environment
40b9557bebSmartynas * (that is, the one installed at program startup) and has type pointer to
41b9557bebSmartynas * const-qualified fenv_t.
42b9557bebSmartynas *
43b9557bebSmartynas * It can be used as an argument to the functions within the <fenv.h> header
44b9557bebSmartynas * that manage the floating-point environment, namely fesetenv() and
45b9557bebSmartynas * feupdateenv().
46b9557bebSmartynas *
47b9557bebSmartynas * x87 fpu registers are 16bit wide. The upper bits, 31-16, are marked as
48d6f349c8Smartynas * RESERVED.
49b9557bebSmartynas */
50b9557bebSmartynas fenv_t __fe_dfl_env = {
51b9557bebSmartynas {
52d6f349c8Smartynas 0xffff0000 | __INITIAL_NPXCW__, /* Control word register */
53d6f349c8Smartynas 0xffff0000, /* Status word register */
54d6f349c8Smartynas 0xffffffff, /* Tag word register */
55b9557bebSmartynas {
56d6f349c8Smartynas 0x00000000,
57d6f349c8Smartynas 0x00000000,
58d6f349c8Smartynas 0x00000000,
59d6f349c8Smartynas 0xffff0000
60b9557bebSmartynas }
61b9557bebSmartynas },
62b9557bebSmartynas __INITIAL_MXCSR__ /* MXCSR register */
63b9557bebSmartynas };
64b9557bebSmartynas
65b9557bebSmartynas /*
66b9557bebSmartynas * Test for SSE support on this processor.
67b9557bebSmartynas *
68b9557bebSmartynas * We need to use ldmxcsr/stmxcsr to get correct results if any part
69b9557bebSmartynas * of the program was compiled to use SSE floating-point, but we can't
70b9557bebSmartynas * use SSE on older processors.
71b9557bebSmartynas *
72b9557bebSmartynas * In order to do so, we need to query the processor capabilities via the CPUID
73b9557bebSmartynas * instruction. We can make it even simpler though, by querying the machdep.sse
74b9557bebSmartynas * sysctl.
75b9557bebSmartynas */
76b9557bebSmartynas static int __HAS_SSE = 0;
77b9557bebSmartynas
78b9557bebSmartynas static void __test_sse(void) __attribute__ ((constructor));
79b9557bebSmartynas
__test_sse(void)80b9557bebSmartynas static void __test_sse(void)
81b9557bebSmartynas {
82b9557bebSmartynas size_t oldlen = sizeof(__HAS_SSE);
83b9557bebSmartynas int mib[2] = { CTL_MACHDEP, CPU_SSE };
84b9557bebSmartynas int rv;
85b9557bebSmartynas
86b9557bebSmartynas rv = sysctl(mib, 2, &__HAS_SSE, &oldlen, NULL, 0);
87b9557bebSmartynas if (rv == -1)
88b9557bebSmartynas __HAS_SSE = 0;
89b9557bebSmartynas }
90b9557bebSmartynas
91b9557bebSmartynas /*
92b9557bebSmartynas * The feclearexcept() function clears the supported floating-point exceptions
93b9557bebSmartynas * represented by `excepts'.
94b9557bebSmartynas */
95b9557bebSmartynas int
feclearexcept(int excepts)96b9557bebSmartynas feclearexcept(int excepts)
97b9557bebSmartynas {
98d6f349c8Smartynas fenv_t fenv;
99d6f349c8Smartynas unsigned int mxcsr;
100b9557bebSmartynas
101d6f349c8Smartynas excepts &= FE_ALL_EXCEPT;
102b9557bebSmartynas
103d6f349c8Smartynas /* Store the current x87 floating-point environment */
104b5aa3b33Sguenther __asm__ volatile ("fnstenv %0" : "=m" (fenv));
105b9557bebSmartynas
106d6f349c8Smartynas /* Clear the requested floating-point exceptions */
107d6f349c8Smartynas fenv.__x87.__status &= ~excepts;
108b9557bebSmartynas
109*2c53affbSjmc /* Load the x87 floating-point environment */
110b5aa3b33Sguenther __asm__ volatile ("fldenv %0" : : "m" (fenv));
111d6f349c8Smartynas
112d6f349c8Smartynas /* Same for SSE environment */
113b9557bebSmartynas if (__HAS_SSE) {
114b5aa3b33Sguenther __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr));
115d6f349c8Smartynas mxcsr &= ~excepts;
116b5aa3b33Sguenther __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr));
117b9557bebSmartynas }
118b9557bebSmartynas
119b9557bebSmartynas return (0);
120b9557bebSmartynas }
1212f2c0062Sguenther DEF_STD(feclearexcept);
122b9557bebSmartynas
123b9557bebSmartynas /*
124b9557bebSmartynas * The fegetexceptflag() function stores an implementation-defined
125b9557bebSmartynas * representation of the states of the floating-point status flags indicated by
126b9557bebSmartynas * the argument excepts in the object pointed to by the argument flagp.
127b9557bebSmartynas */
128b9557bebSmartynas int
fegetexceptflag(fexcept_t * flagp,int excepts)129b9557bebSmartynas fegetexceptflag(fexcept_t *flagp, int excepts)
130b9557bebSmartynas {
131d6f349c8Smartynas unsigned short status;
132d6f349c8Smartynas unsigned int mxcsr = 0;
133b9557bebSmartynas
134d6f349c8Smartynas excepts &= FE_ALL_EXCEPT;
135b9557bebSmartynas
136d6f349c8Smartynas /* Store the current x87 status register */
137b5aa3b33Sguenther __asm__ volatile ("fnstsw %0" : "=am" (status));
138b9557bebSmartynas
139d6f349c8Smartynas /* Store the MXCSR register */
140b9557bebSmartynas if (__HAS_SSE)
141b5aa3b33Sguenther __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr));
142b9557bebSmartynas
143d6f349c8Smartynas /* Store the results in flagp */
144d6f349c8Smartynas *flagp = (status | mxcsr) & excepts;
145b9557bebSmartynas
146b9557bebSmartynas return (0);
147b9557bebSmartynas }
148b9557bebSmartynas
149b9557bebSmartynas /*
150b9557bebSmartynas * The feraiseexcept() function raises the supported floating-point exceptions
151b9557bebSmartynas * represented by the argument `excepts'.
152b9557bebSmartynas *
153b9557bebSmartynas * The standard explicitly allows us to execute an instruction that has the
154b9557bebSmartynas * exception as a side effect, but we choose to manipulate the status register
155b9557bebSmartynas * directly.
156b9557bebSmartynas *
157b9557bebSmartynas * The validation of input is being deferred to fesetexceptflag().
158b9557bebSmartynas */
159b9557bebSmartynas int
feraiseexcept(int excepts)160b9557bebSmartynas feraiseexcept(int excepts)
161b9557bebSmartynas {
162d6f349c8Smartynas excepts &= FE_ALL_EXCEPT;
163b9557bebSmartynas
164d6f349c8Smartynas fesetexceptflag((fexcept_t *)&excepts, excepts);
165b5aa3b33Sguenther __asm__ volatile ("fwait");
166b9557bebSmartynas
167b9557bebSmartynas return (0);
168b9557bebSmartynas }
1692f2c0062Sguenther DEF_STD(feraiseexcept);
170b9557bebSmartynas
171b9557bebSmartynas /*
172b9557bebSmartynas * This function sets the floating-point status flags indicated by the argument
173b9557bebSmartynas * `excepts' to the states stored in the object pointed to by `flagp'. It does
174b9557bebSmartynas * NOT raise any floating-point exceptions, but only sets the state of the flags.
175b9557bebSmartynas */
176b9557bebSmartynas int
fesetexceptflag(const fexcept_t * flagp,int excepts)177b9557bebSmartynas fesetexceptflag(const fexcept_t *flagp, int excepts)
178b9557bebSmartynas {
179d6f349c8Smartynas fenv_t fenv;
180d6f349c8Smartynas unsigned int mxcsr;
181b9557bebSmartynas
182d6f349c8Smartynas excepts &= FE_ALL_EXCEPT;
183b9557bebSmartynas
184d6f349c8Smartynas /* Store the current x87 floating-point environment */
185b5aa3b33Sguenther __asm__ volatile ("fnstenv %0" : "=m" (fenv));
186b9557bebSmartynas
187d6f349c8Smartynas /* Set the requested status flags */
188d6f349c8Smartynas fenv.__x87.__status &= ~excepts;
189d6f349c8Smartynas fenv.__x87.__status |= *flagp & excepts;
190b9557bebSmartynas
191*2c53affbSjmc /* Load the x87 floating-point environment */
192b5aa3b33Sguenther __asm__ volatile ("fldenv %0" : : "m" (fenv));
193d6f349c8Smartynas
194d6f349c8Smartynas /* Same for SSE environment */
195b9557bebSmartynas if (__HAS_SSE) {
196b5aa3b33Sguenther __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr));
197d6f349c8Smartynas mxcsr &= ~excepts;
198d6f349c8Smartynas mxcsr |= *flagp & excepts;
199b5aa3b33Sguenther __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr));
200b9557bebSmartynas }
201b9557bebSmartynas
202b9557bebSmartynas return (0);
203b9557bebSmartynas }
2042f2c0062Sguenther DEF_STD(fesetexceptflag);
205b9557bebSmartynas
206b9557bebSmartynas /*
207b9557bebSmartynas * The fetestexcept() function determines which of a specified subset of the
208b9557bebSmartynas * floating-point exception flags are currently set. The `excepts' argument
209b9557bebSmartynas * specifies the floating-point status flags to be queried.
210b9557bebSmartynas */
211b9557bebSmartynas int
fetestexcept(int excepts)212b9557bebSmartynas fetestexcept(int excepts)
213b9557bebSmartynas {
214d6f349c8Smartynas unsigned short status;
215d6f349c8Smartynas unsigned int mxcsr = 0;
216b9557bebSmartynas
217d6f349c8Smartynas excepts &= FE_ALL_EXCEPT;
218b9557bebSmartynas
219d6f349c8Smartynas /* Store the current x87 status register */
220b5aa3b33Sguenther __asm__ volatile ("fnstsw %0" : "=am" (status));
221b9557bebSmartynas
222d6f349c8Smartynas /* Store the MXCSR register state */
223b9557bebSmartynas if (__HAS_SSE)
224b5aa3b33Sguenther __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr));
225b9557bebSmartynas
226d6f349c8Smartynas return ((status | mxcsr) & excepts);
227b9557bebSmartynas }
2282f2c0062Sguenther DEF_STD(fetestexcept);
229b9557bebSmartynas
230d6f349c8Smartynas /*
231d6f349c8Smartynas * The fegetround() function gets the current rounding direction.
232d6f349c8Smartynas */
233b9557bebSmartynas int
fegetround(void)234b9557bebSmartynas fegetround(void)
235b9557bebSmartynas {
236d6f349c8Smartynas unsigned short control;
237b9557bebSmartynas
238b9557bebSmartynas /*
239b9557bebSmartynas * We assume that the x87 and the SSE unit agree on the
240b9557bebSmartynas * rounding mode. Reading the control word on the x87 turns
241b9557bebSmartynas * out to be about 5 times faster than reading it on the SSE
242b9557bebSmartynas * unit on an Opteron 244.
243b9557bebSmartynas */
244b5aa3b33Sguenther __asm__ volatile ("fnstcw %0" : "=m" (control));
245b9557bebSmartynas
246d6f349c8Smartynas return (control & _X87_ROUND_MASK);
247b9557bebSmartynas }
2482f2c0062Sguenther DEF_STD(fegetround);
249b9557bebSmartynas
250b9557bebSmartynas /*
251d6f349c8Smartynas * The fesetround() function establishes the rounding direction represented by
252d6f349c8Smartynas * its argument `round'. If the argument is not equal to the value of a rounding
253d6f349c8Smartynas * direction macro, the rounding direction is not changed.
254b9557bebSmartynas */
255b9557bebSmartynas int
fesetround(int round)256b9557bebSmartynas fesetround(int round)
257b9557bebSmartynas {
258d6f349c8Smartynas unsigned short control;
259d6f349c8Smartynas unsigned int mxcsr;
260b9557bebSmartynas
261d6f349c8Smartynas /* Check whether requested rounding direction is supported */
262d6f349c8Smartynas if (round & ~_X87_ROUND_MASK)
263b9557bebSmartynas return (-1);
264b9557bebSmartynas
265d6f349c8Smartynas /* Store the current x87 control word register */
266b5aa3b33Sguenther __asm__ volatile ("fnstcw %0" : "=m" (control));
267d6f349c8Smartynas
268d6f349c8Smartynas /* Set the rounding direction */
269d6f349c8Smartynas control &= ~_X87_ROUND_MASK;
270b9557bebSmartynas control |= round;
271b9557bebSmartynas
272d6f349c8Smartynas /* Load the x87 control word register */
273b5aa3b33Sguenther __asm__ volatile ("fldcw %0" : : "m" (control));
274d6f349c8Smartynas
275d6f349c8Smartynas /* Same for the SSE environment */
276b9557bebSmartynas if (__HAS_SSE) {
277b5aa3b33Sguenther __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr));
278d6f349c8Smartynas mxcsr &= ~(_X87_ROUND_MASK << _SSE_ROUND_SHIFT);
279d6f349c8Smartynas mxcsr |= round << _SSE_ROUND_SHIFT;
280b5aa3b33Sguenther __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr));
281b9557bebSmartynas }
282b9557bebSmartynas
283b9557bebSmartynas return (0);
284b9557bebSmartynas }
2852f2c0062Sguenther DEF_STD(fesetround);
286b9557bebSmartynas
287b9557bebSmartynas /*
288b9557bebSmartynas * The fegetenv() function attempts to store the current floating-point
289b9557bebSmartynas * environment in the object pointed to by envp.
290b9557bebSmartynas */
291b9557bebSmartynas int
fegetenv(fenv_t * envp)292b9557bebSmartynas fegetenv(fenv_t *envp)
293b9557bebSmartynas {
294d6f349c8Smartynas /* Store the current x87 floating-point environment */
295b5aa3b33Sguenther __asm__ volatile ("fnstenv %0" : "=m" (*envp));
296b9557bebSmartynas
297d6f349c8Smartynas /* Store the MXCSR register state */
298d6f349c8Smartynas if (__HAS_SSE)
299b5aa3b33Sguenther __asm__ volatile ("stmxcsr %0" : "=m" (envp->__mxcsr));
300b9557bebSmartynas
301b9557bebSmartynas /*
302d6f349c8Smartynas * When an FNSTENV instruction is executed, all pending exceptions are
303d6f349c8Smartynas * essentially lost (either the x87 FPU status register is cleared or
304d6f349c8Smartynas * all exceptions are masked).
305d6f349c8Smartynas *
306d6f349c8Smartynas * 8.6 X87 FPU EXCEPTION SYNCHRONIZATION -
307d6f349c8Smartynas * Intel(R) 64 and IA-32 Architectures Softare Developer's Manual - Vol1
308b9557bebSmartynas */
309b5aa3b33Sguenther __asm__ volatile ("fldcw %0" : : "m" (envp->__x87.__control));
310b9557bebSmartynas
311b9557bebSmartynas return (0);
312b9557bebSmartynas }
3132f2c0062Sguenther DEF_STD(fegetenv);
314b9557bebSmartynas
315b9557bebSmartynas /*
316d6f349c8Smartynas * The feholdexcept() function saves the current floating-point environment
317d6f349c8Smartynas * in the object pointed to by envp, clears the floating-point status flags, and
318b9557bebSmartynas * then installs a non-stop (continue on floating-point exceptions) mode, if
319b9557bebSmartynas * available, for all floating-point exceptions.
320b9557bebSmartynas */
321b9557bebSmartynas int
feholdexcept(fenv_t * envp)322b9557bebSmartynas feholdexcept(fenv_t *envp)
323b9557bebSmartynas {
324d6f349c8Smartynas unsigned int mxcsr;
325b9557bebSmartynas
326d6f349c8Smartynas /* Store the current x87 floating-point environment */
327b5aa3b33Sguenther __asm__ volatile ("fnstenv %0" : "=m" (*envp));
328b9557bebSmartynas
329d6f349c8Smartynas /* Clear all exception flags in FPU */
330b5aa3b33Sguenther __asm__ volatile ("fnclex");
331d6f349c8Smartynas
332b9557bebSmartynas if (__HAS_SSE) {
333d6f349c8Smartynas /* Store the MXCSR register state */
334b5aa3b33Sguenther __asm__ volatile ("stmxcsr %0" : "=m" (envp->__mxcsr));
335d6f349c8Smartynas
336d6f349c8Smartynas /* Clear exception flags in MXCSR */
337d6f349c8Smartynas mxcsr = envp->__mxcsr;
338b9557bebSmartynas mxcsr &= ~FE_ALL_EXCEPT;
339d6f349c8Smartynas
340d6f349c8Smartynas /* Mask all exceptions */
341d6f349c8Smartynas mxcsr |= FE_ALL_EXCEPT << _SSE_MASK_SHIFT;
342d6f349c8Smartynas
343d6f349c8Smartynas /* Store the MXCSR register */
344b5aa3b33Sguenther __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr));
345b9557bebSmartynas }
346b9557bebSmartynas
347b9557bebSmartynas return (0);
348b9557bebSmartynas }
3492f2c0062Sguenther DEF_STD(feholdexcept);
350b9557bebSmartynas
351b9557bebSmartynas /*
352b9557bebSmartynas * The fesetenv() function attempts to establish the floating-point environment
353b9557bebSmartynas * represented by the object pointed to by envp. The argument `envp' points
354b9557bebSmartynas * to an object set by a call to fegetenv() or feholdexcept(), or equal a
355b9557bebSmartynas * floating-point environment macro. The fesetenv() function does not raise
356b9557bebSmartynas * floating-point exceptions, but only installs the state of the floating-point
357b9557bebSmartynas * status flags represented through its argument.
358b9557bebSmartynas */
359b9557bebSmartynas int
fesetenv(const fenv_t * envp)360b9557bebSmartynas fesetenv(const fenv_t *envp)
361b9557bebSmartynas {
362*2c53affbSjmc /* Load the x87 floating-point environment */
363b5aa3b33Sguenther __asm__ volatile ("fldenv %0" : : "m" (*envp));
364b9557bebSmartynas
365d6f349c8Smartynas /* Store the MXCSR register */
366b9557bebSmartynas if (__HAS_SSE)
367b5aa3b33Sguenther __asm__ volatile ("ldmxcsr %0" : : "m" (envp->__mxcsr));
368b9557bebSmartynas
369b9557bebSmartynas return (0);
370b9557bebSmartynas }
3712f2c0062Sguenther DEF_STD(fesetenv);
372b9557bebSmartynas
373b9557bebSmartynas /*
374b9557bebSmartynas * The feupdateenv() function saves the currently raised floating-point
375b9557bebSmartynas * exceptions in its automatic storage, installs the floating-point environment
376b9557bebSmartynas * represented by the object pointed to by `envp', and then raises the saved
377b9557bebSmartynas * floating-point exceptions. The argument `envp' shall point to an object set
378b9557bebSmartynas * by a call to feholdexcept() or fegetenv(), or equal a floating-point
379b9557bebSmartynas * environment macro.
380b9557bebSmartynas */
381b9557bebSmartynas int
feupdateenv(const fenv_t * envp)382b9557bebSmartynas feupdateenv(const fenv_t *envp)
383b9557bebSmartynas {
384d6f349c8Smartynas unsigned short status;
385d6f349c8Smartynas unsigned int mxcsr = 0;
386b9557bebSmartynas
387d6f349c8Smartynas /* Store the x87 status register */
388b5aa3b33Sguenther __asm__ volatile ("fnstsw %0" : "=am" (status));
389b9557bebSmartynas
390d6f349c8Smartynas /* Store the MXCSR register */
391b9557bebSmartynas if (__HAS_SSE)
392b5aa3b33Sguenther __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr));
393b9557bebSmartynas
394d6f349c8Smartynas /* Install new floating-point environment */
395d6f349c8Smartynas fesetenv(envp);
396d6f349c8Smartynas
397d6f349c8Smartynas /* Raise any previously accumulated exceptions */
398d6f349c8Smartynas feraiseexcept(status | mxcsr);
399d6f349c8Smartynas
400b9557bebSmartynas return (0);
401b9557bebSmartynas }
4022f2c0062Sguenther DEF_STD(feupdateenv);
403b9557bebSmartynas
404b9557bebSmartynas /*
405*2c53affbSjmc * The following functions are extensions to the standard
406b9557bebSmartynas */
407b9557bebSmartynas int
feenableexcept(int mask)408b9557bebSmartynas feenableexcept(int mask)
409b9557bebSmartynas {
410d6f349c8Smartynas unsigned int mxcsr = 0, omask;
411d6f349c8Smartynas unsigned short control;
412b9557bebSmartynas
413b9557bebSmartynas mask &= FE_ALL_EXCEPT;
414b9557bebSmartynas
415b5aa3b33Sguenther __asm__ volatile ("fnstcw %0" : "=m" (control));
416d6f349c8Smartynas if (__HAS_SSE)
417b5aa3b33Sguenther __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr));
418d6f349c8Smartynas
419d6f349c8Smartynas omask = ~(control | (mxcsr >> _SSE_MASK_SHIFT)) & FE_ALL_EXCEPT;
420b9557bebSmartynas control &= ~mask;
421b5aa3b33Sguenther __asm__ volatile ("fldcw %0" : : "m" (control));
422d6f349c8Smartynas
423b9557bebSmartynas if (__HAS_SSE) {
424d6f349c8Smartynas mxcsr &= ~(mask << _SSE_MASK_SHIFT);
425b5aa3b33Sguenther __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr));
426b9557bebSmartynas }
427b9557bebSmartynas
428d6f349c8Smartynas return (omask);
429b9557bebSmartynas }
430b9557bebSmartynas
431b9557bebSmartynas int
fedisableexcept(int mask)432b9557bebSmartynas fedisableexcept(int mask)
433b9557bebSmartynas {
434d6f349c8Smartynas unsigned int mxcsr = 0, omask;
435d6f349c8Smartynas unsigned short control;
436b9557bebSmartynas
437b9557bebSmartynas mask &= FE_ALL_EXCEPT;
438b9557bebSmartynas
439b5aa3b33Sguenther __asm__ volatile ("fnstcw %0" : "=m" (control));
440d6f349c8Smartynas if (__HAS_SSE)
441b5aa3b33Sguenther __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr));
442d6f349c8Smartynas
443d6f349c8Smartynas omask = ~(control | (mxcsr >> _SSE_MASK_SHIFT)) & FE_ALL_EXCEPT;
444b9557bebSmartynas control |= mask;
445b5aa3b33Sguenther __asm__ volatile ("fldcw %0" : : "m" (control));
446d6f349c8Smartynas
447b9557bebSmartynas if (__HAS_SSE) {
448d6f349c8Smartynas mxcsr |= mask << _SSE_MASK_SHIFT;
449b5aa3b33Sguenther __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr));
450b9557bebSmartynas }
451b9557bebSmartynas
452d6f349c8Smartynas return (omask);
453b9557bebSmartynas }
454b9557bebSmartynas
455b9557bebSmartynas int
fegetexcept(void)456b9557bebSmartynas fegetexcept(void)
457b9557bebSmartynas {
458d6f349c8Smartynas unsigned short control;
459b9557bebSmartynas
460b9557bebSmartynas /*
461b9557bebSmartynas * We assume that the masks for the x87 and the SSE unit are
462b9557bebSmartynas * the same.
463b9557bebSmartynas */
464b5aa3b33Sguenther __asm__ volatile ("fnstcw %0" : "=m" (control));
465b9557bebSmartynas
466d6f349c8Smartynas return (~control & FE_ALL_EXCEPT);
467b9557bebSmartynas }
468