xref: /dflybsd-src/contrib/openbsd_libm/arch/amd64/fenv.c (revision dfbd094314808899b20815660c6497c88f7bbf76)
105a0b428SJohn Marino /*	$OpenBSD: fenv.c,v 1.4 2014/04/18 15:09:52 guenther Exp $	*/
205a0b428SJohn Marino /*	$NetBSD: fenv.c,v 1.1 2010/07/31 21:47:53 joerg Exp $	*/
305a0b428SJohn Marino 
405a0b428SJohn Marino /*-
505a0b428SJohn Marino  * Copyright (c) 2004-2005 David Schultz <das (at) FreeBSD.ORG>
605a0b428SJohn Marino  * All rights reserved.
705a0b428SJohn Marino  *
805a0b428SJohn Marino  * Redistribution and use in source and binary forms, with or without
905a0b428SJohn Marino  * modification, are permitted provided that the following conditions
1005a0b428SJohn Marino  * are met:
1105a0b428SJohn Marino  * 1. Redistributions of source code must retain the above copyright
1205a0b428SJohn Marino  *    notice, this list of conditions and the following disclaimer.
1305a0b428SJohn Marino  * 2. Redistributions in binary form must reproduce the above copyright
1405a0b428SJohn Marino  *    notice, this list of conditions and the following disclaimer in the
1505a0b428SJohn Marino  *    documentation and/or other materials provided with the distribution.
1605a0b428SJohn Marino  *
1705a0b428SJohn Marino  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1805a0b428SJohn Marino  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1905a0b428SJohn Marino  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2005a0b428SJohn Marino  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2105a0b428SJohn Marino  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2205a0b428SJohn Marino  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2305a0b428SJohn Marino  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2405a0b428SJohn Marino  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2505a0b428SJohn Marino  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2605a0b428SJohn Marino  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2705a0b428SJohn Marino  * SUCH DAMAGE.
2805a0b428SJohn Marino  */
2905a0b428SJohn Marino 
3005a0b428SJohn Marino #include <fenv.h>
3174b7c7a8SJohn Marino #include <machine/npx.h>
3205a0b428SJohn Marino 
3305a0b428SJohn Marino /*
3405a0b428SJohn Marino  * The following constant represents the default floating-point environment
3505a0b428SJohn Marino  * (that is, the one installed at program startup) and has type pointer to
3605a0b428SJohn Marino  * const-qualified fenv_t.
3705a0b428SJohn Marino  *
3805a0b428SJohn Marino  * It can be used as an argument to the functions within the <fenv.h> header
3905a0b428SJohn Marino  * that manage the floating-point environment, namely fesetenv() and
4005a0b428SJohn Marino  * feupdateenv().
4105a0b428SJohn Marino  *
4205a0b428SJohn Marino  * x87 fpu registers are 16bit wide. The upper bits, 31-16, are marked as
4305a0b428SJohn Marino  * RESERVED.
4405a0b428SJohn Marino  */
4505a0b428SJohn Marino fenv_t __fe_dfl_env = {
4605a0b428SJohn Marino 	{
47*dfbd0943SJohn Marino 		0xffff0000 | __INITIAL_FPUCW__,	/* Control word register */
4805a0b428SJohn Marino 		0xffff0000,			/* Status word register */
4905a0b428SJohn Marino 		0xffffffff,			/* Tag word register */
5005a0b428SJohn Marino 		{
5105a0b428SJohn Marino 			0x00000000,
5205a0b428SJohn Marino 			0x00000000,
5305a0b428SJohn Marino 			0x00000000,
5405a0b428SJohn Marino 			0xffff0000
5505a0b428SJohn Marino 		}
5605a0b428SJohn Marino 	},
5705a0b428SJohn Marino 	__INITIAL_MXCSR__			/* MXCSR register */
5805a0b428SJohn Marino };
5905a0b428SJohn Marino 
6005a0b428SJohn Marino 
6105a0b428SJohn Marino /*
6205a0b428SJohn Marino  * The feclearexcept() function clears the supported floating-point exceptions
6305a0b428SJohn Marino  * represented by `excepts'.
6405a0b428SJohn Marino  */
6505a0b428SJohn Marino int
feclearexcept(int excepts)6605a0b428SJohn Marino feclearexcept(int excepts)
6705a0b428SJohn Marino {
6805a0b428SJohn Marino 	fenv_t fenv;
6905a0b428SJohn Marino 	unsigned int mxcsr;
7005a0b428SJohn Marino 
7105a0b428SJohn Marino 	excepts &= FE_ALL_EXCEPT;
7205a0b428SJohn Marino 
7305a0b428SJohn Marino 	/* Store the current x87 floating-point environment */
7405a0b428SJohn Marino 	__asm__ volatile ("fnstenv %0" : "=m" (fenv));
7505a0b428SJohn Marino 
7605a0b428SJohn Marino 	/* Clear the requested floating-point exceptions */
7705a0b428SJohn Marino 	fenv.__x87.__status &= ~excepts;
7805a0b428SJohn Marino 
7905a0b428SJohn Marino 	/* Load the x87 floating-point environent */
8005a0b428SJohn Marino 	__asm__ volatile ("fldenv %0" : : "m" (fenv));
8105a0b428SJohn Marino 
8205a0b428SJohn Marino 	/* Same for SSE environment */
8305a0b428SJohn Marino 	__asm__ volatile ("stmxcsr %0" : "=m" (mxcsr));
8405a0b428SJohn Marino 	mxcsr &= ~excepts;
8505a0b428SJohn Marino 	__asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr));
8605a0b428SJohn Marino 
8705a0b428SJohn Marino 	return (0);
8805a0b428SJohn Marino }
8905a0b428SJohn Marino 
9005a0b428SJohn Marino /*
9105a0b428SJohn Marino  * The fegetexceptflag() function stores an implementation-defined
9205a0b428SJohn Marino  * representation of the states of the floating-point status flags indicated by
9305a0b428SJohn Marino  * the argument excepts in the object pointed to by the argument flagp.
9405a0b428SJohn Marino  */
9505a0b428SJohn Marino int
fegetexceptflag(fexcept_t * flagp,int excepts)9605a0b428SJohn Marino fegetexceptflag(fexcept_t *flagp, int excepts)
9705a0b428SJohn Marino {
9805a0b428SJohn Marino 	unsigned short status;
9905a0b428SJohn Marino 	unsigned int mxcsr;
10005a0b428SJohn Marino 
10105a0b428SJohn Marino 	excepts &= FE_ALL_EXCEPT;
10205a0b428SJohn Marino 
10305a0b428SJohn Marino 	/* Store the current x87 status register */
10405a0b428SJohn Marino 	__asm__ volatile ("fnstsw %0" : "=am" (status));
10505a0b428SJohn Marino 
10605a0b428SJohn Marino 	/* Store the MXCSR register */
10705a0b428SJohn Marino 	__asm__ volatile ("stmxcsr %0" : "=m" (mxcsr));
10805a0b428SJohn Marino 
10905a0b428SJohn Marino 	/* Store the results in flagp */
11005a0b428SJohn Marino 	*flagp = (status | mxcsr) & excepts;
11105a0b428SJohn Marino 
11205a0b428SJohn Marino 	return (0);
11305a0b428SJohn Marino }
11405a0b428SJohn Marino 
11505a0b428SJohn Marino /*
11605a0b428SJohn Marino  * The feraiseexcept() function raises the supported floating-point exceptions
11705a0b428SJohn Marino  * represented by the argument `excepts'.
11805a0b428SJohn Marino  *
11905a0b428SJohn Marino  * The standard explicitly allows us to execute an instruction that has the
12005a0b428SJohn Marino  * exception as a side effect, but we choose to manipulate the status register
12105a0b428SJohn Marino  * directly.
12205a0b428SJohn Marino  *
12305a0b428SJohn Marino  * The validation of input is being deferred to fesetexceptflag().
12405a0b428SJohn Marino  */
12505a0b428SJohn Marino int
feraiseexcept(int excepts)12605a0b428SJohn Marino feraiseexcept(int excepts)
12705a0b428SJohn Marino {
12805a0b428SJohn Marino 	excepts &= FE_ALL_EXCEPT;
12905a0b428SJohn Marino 
13005a0b428SJohn Marino 	fesetexceptflag((fexcept_t *)&excepts, excepts);
13105a0b428SJohn Marino 	__asm__ volatile ("fwait");
13205a0b428SJohn Marino 
13305a0b428SJohn Marino 	return (0);
13405a0b428SJohn Marino }
13505a0b428SJohn Marino 
13605a0b428SJohn Marino /*
13705a0b428SJohn Marino  * This function sets the floating-point status flags indicated by the argument
13805a0b428SJohn Marino  * `excepts' to the states stored in the object pointed to by `flagp'. It does
13905a0b428SJohn Marino  * NOT raise any floating-point exceptions, but only sets the state of the flags.
14005a0b428SJohn Marino  */
14105a0b428SJohn Marino int
fesetexceptflag(const fexcept_t * flagp,int excepts)14205a0b428SJohn Marino fesetexceptflag(const fexcept_t *flagp, int excepts)
14305a0b428SJohn Marino {
14405a0b428SJohn Marino 	fenv_t fenv;
14505a0b428SJohn Marino 	unsigned int mxcsr;
14605a0b428SJohn Marino 
14705a0b428SJohn Marino 	excepts &= FE_ALL_EXCEPT;
14805a0b428SJohn Marino 
14905a0b428SJohn Marino 	/* Store the current x87 floating-point environment */
15005a0b428SJohn Marino 	__asm__ volatile ("fnstenv %0" : "=m" (fenv));
15105a0b428SJohn Marino 
15205a0b428SJohn Marino 	/* Set the requested status flags */
15305a0b428SJohn Marino 	fenv.__x87.__status &= ~excepts;
15405a0b428SJohn Marino 	fenv.__x87.__status |= *flagp & excepts;
15505a0b428SJohn Marino 
15605a0b428SJohn Marino 	/* Load the x87 floating-point environent */
15705a0b428SJohn Marino 	__asm__ volatile ("fldenv %0" : : "m" (fenv));
15805a0b428SJohn Marino 
15905a0b428SJohn Marino 	/* Same for SSE environment */
16005a0b428SJohn Marino 	__asm__ volatile ("stmxcsr %0" : "=m" (mxcsr));
16105a0b428SJohn Marino 	mxcsr &= ~excepts;
16205a0b428SJohn Marino 	mxcsr |= *flagp & excepts;
16305a0b428SJohn Marino 	__asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr));
16405a0b428SJohn Marino 
16505a0b428SJohn Marino 	return (0);
16605a0b428SJohn Marino }
16705a0b428SJohn Marino 
16805a0b428SJohn Marino /*
16905a0b428SJohn Marino  * The fetestexcept() function determines which of a specified subset of the
17005a0b428SJohn Marino  * floating-point exception flags are currently set. The `excepts' argument
17105a0b428SJohn Marino  * specifies the floating-point status flags to be queried.
17205a0b428SJohn Marino  */
17305a0b428SJohn Marino int
fetestexcept(int excepts)17405a0b428SJohn Marino fetestexcept(int excepts)
17505a0b428SJohn Marino {
17605a0b428SJohn Marino 	unsigned short status;
17705a0b428SJohn Marino 	unsigned int mxcsr;
17805a0b428SJohn Marino 
17905a0b428SJohn Marino 	excepts &= FE_ALL_EXCEPT;
18005a0b428SJohn Marino 
18105a0b428SJohn Marino 	/* Store the current x87 status register */
18205a0b428SJohn Marino 	__asm__ volatile ("fnstsw %0" : "=am" (status));
18305a0b428SJohn Marino 
18405a0b428SJohn Marino 	/* Store the MXCSR register state */
18505a0b428SJohn Marino 	__asm__ volatile ("stmxcsr %0" : "=m" (mxcsr));
18605a0b428SJohn Marino 
18705a0b428SJohn Marino 	return ((status | mxcsr) & excepts);
18805a0b428SJohn Marino }
18905a0b428SJohn Marino 
19005a0b428SJohn Marino /*
19105a0b428SJohn Marino  * The fegetround() function gets the current rounding direction.
19205a0b428SJohn Marino  */
19305a0b428SJohn Marino int
fegetround(void)19405a0b428SJohn Marino fegetround(void)
19505a0b428SJohn Marino {
19605a0b428SJohn Marino 	unsigned short control;
19705a0b428SJohn Marino 
19805a0b428SJohn Marino 	/*
19905a0b428SJohn Marino 	 * We assume that the x87 and the SSE unit agree on the
20005a0b428SJohn Marino 	 * rounding mode.  Reading the control word on the x87 turns
20105a0b428SJohn Marino 	 * out to be about 5 times faster than reading it on the SSE
20205a0b428SJohn Marino 	 * unit on an Opteron 244.
20305a0b428SJohn Marino 	 */
20405a0b428SJohn Marino 	__asm__ volatile ("fnstcw %0" : "=m" (control));
20505a0b428SJohn Marino 
20605a0b428SJohn Marino 	return (control & _X87_ROUND_MASK);
20705a0b428SJohn Marino }
20805a0b428SJohn Marino 
20905a0b428SJohn Marino /*
21005a0b428SJohn Marino  * The fesetround() function establishes the rounding direction represented by
21105a0b428SJohn Marino  * its argument `round'. If the argument is not equal to the value of a rounding
21205a0b428SJohn Marino  * direction macro, the rounding direction is not changed.
21305a0b428SJohn Marino  */
21405a0b428SJohn Marino int
fesetround(int round)21505a0b428SJohn Marino fesetround(int round)
21605a0b428SJohn Marino {
21705a0b428SJohn Marino 	unsigned short control;
21805a0b428SJohn Marino 	unsigned int mxcsr;
21905a0b428SJohn Marino 
22005a0b428SJohn Marino 	/* Check whether requested rounding direction is supported */
22105a0b428SJohn Marino 	if (round & ~_X87_ROUND_MASK)
22205a0b428SJohn Marino 		return (-1);
22305a0b428SJohn Marino 
22405a0b428SJohn Marino 	/* Store the current x87 control word register */
22505a0b428SJohn Marino 	__asm__ volatile ("fnstcw %0" : "=m" (control));
22605a0b428SJohn Marino 
22705a0b428SJohn Marino 	/* Set the rounding direction */
22805a0b428SJohn Marino 	control &= ~_X87_ROUND_MASK;
22905a0b428SJohn Marino 	control |= round;
23005a0b428SJohn Marino 
23105a0b428SJohn Marino 	/* Load the x87 control word register */
23205a0b428SJohn Marino 	__asm__ volatile ("fldcw %0" : : "m" (control));
23305a0b428SJohn Marino 
23405a0b428SJohn Marino 	/* Same for the SSE environment */
23505a0b428SJohn Marino 	__asm__ volatile ("stmxcsr %0" : "=m" (mxcsr));
23605a0b428SJohn Marino 	mxcsr &= ~(_X87_ROUND_MASK << _SSE_ROUND_SHIFT);
23705a0b428SJohn Marino 	mxcsr |= round << _SSE_ROUND_SHIFT;
23805a0b428SJohn Marino 	__asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr));
23905a0b428SJohn Marino 
24005a0b428SJohn Marino 	return (0);
24105a0b428SJohn Marino }
24205a0b428SJohn Marino 
24305a0b428SJohn Marino /*
24405a0b428SJohn Marino  * The fegetenv() function attempts to store the current floating-point
24505a0b428SJohn Marino  * environment in the object pointed to by envp.
24605a0b428SJohn Marino  */
24705a0b428SJohn Marino int
fegetenv(fenv_t * envp)24805a0b428SJohn Marino fegetenv(fenv_t *envp)
24905a0b428SJohn Marino {
25005a0b428SJohn Marino 	/* Store the current x87 floating-point environment */
25105a0b428SJohn Marino 	__asm__ volatile ("fnstenv %0" : "=m" (*envp));
25205a0b428SJohn Marino 
25305a0b428SJohn Marino 	/* Store the MXCSR register state */
25405a0b428SJohn Marino 	__asm__ volatile ("stmxcsr %0" : "=m" (envp->__mxcsr));
25505a0b428SJohn Marino 
25605a0b428SJohn Marino 	/*
25705a0b428SJohn Marino 	 * When an FNSTENV instruction is executed, all pending exceptions are
25805a0b428SJohn Marino 	 * essentially lost (either the x87 FPU status register is cleared or
25905a0b428SJohn Marino 	 * all exceptions are masked).
26005a0b428SJohn Marino 	 *
26105a0b428SJohn Marino 	 * 8.6 X87 FPU EXCEPTION SYNCHRONIZATION -
26205a0b428SJohn Marino 	 * Intel(R) 64 and IA-32 Architectures Softare Developer's Manual - Vol1
26305a0b428SJohn Marino 	 */
26405a0b428SJohn Marino 	__asm__ volatile ("fldcw %0" : : "m" (envp->__x87.__control));
26505a0b428SJohn Marino 
26605a0b428SJohn Marino 	return (0);
26705a0b428SJohn Marino }
26805a0b428SJohn Marino 
26905a0b428SJohn Marino /*
27005a0b428SJohn Marino  * The feholdexcept() function saves the current floating-point environment
27105a0b428SJohn Marino  * in the object pointed to by envp, clears the floating-point status flags, and
27205a0b428SJohn Marino  * then installs a non-stop (continue on floating-point exceptions) mode, if
27305a0b428SJohn Marino  * available, for all floating-point exceptions.
27405a0b428SJohn Marino  */
27505a0b428SJohn Marino int
feholdexcept(fenv_t * envp)27605a0b428SJohn Marino feholdexcept(fenv_t *envp)
27705a0b428SJohn Marino {
27805a0b428SJohn Marino 	unsigned int mxcsr;
27905a0b428SJohn Marino 
28005a0b428SJohn Marino 	/* Store the current x87 floating-point environment */
28105a0b428SJohn Marino 	__asm__ volatile ("fnstenv %0" : "=m" (*envp));
28205a0b428SJohn Marino 
28305a0b428SJohn Marino 	/* Clear all exception flags in FPU */
28405a0b428SJohn Marino 	__asm__ volatile ("fnclex");
28505a0b428SJohn Marino 
28605a0b428SJohn Marino 	/* Store the MXCSR register state */
28705a0b428SJohn Marino 	__asm__ volatile ("stmxcsr %0" : "=m" (envp->__mxcsr));
28805a0b428SJohn Marino 
28905a0b428SJohn Marino 	/* Clear exception flags in MXCSR */
29005a0b428SJohn Marino 	mxcsr = envp->__mxcsr;
29105a0b428SJohn Marino 	mxcsr &= ~FE_ALL_EXCEPT;
29205a0b428SJohn Marino 
29305a0b428SJohn Marino 	/* Mask all exceptions */
29405a0b428SJohn Marino 	mxcsr |= FE_ALL_EXCEPT << _SSE_MASK_SHIFT;
29505a0b428SJohn Marino 
29605a0b428SJohn Marino 	/* Store the MXCSR register */
29705a0b428SJohn Marino 	__asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr));
29805a0b428SJohn Marino 
29905a0b428SJohn Marino 	return (0);
30005a0b428SJohn Marino }
30105a0b428SJohn Marino 
30205a0b428SJohn Marino /*
30305a0b428SJohn Marino  * The fesetenv() function attempts to establish the floating-point environment
30405a0b428SJohn Marino  * represented by the object pointed to by envp. The argument `envp' points
30505a0b428SJohn Marino  * to an object set by a call to fegetenv() or feholdexcept(), or equal a
30605a0b428SJohn Marino  * floating-point environment macro. The fesetenv() function does not raise
30705a0b428SJohn Marino  * floating-point exceptions, but only installs the state of the floating-point
30805a0b428SJohn Marino  * status flags represented through its argument.
30905a0b428SJohn Marino  */
31005a0b428SJohn Marino int
fesetenv(const fenv_t * envp)31105a0b428SJohn Marino fesetenv(const fenv_t *envp)
31205a0b428SJohn Marino {
31305a0b428SJohn Marino 	/* Load the x87 floating-point environent */
31405a0b428SJohn Marino 	__asm__ volatile ("fldenv %0" : : "m" (*envp));
31505a0b428SJohn Marino 
31605a0b428SJohn Marino 	/* Store the MXCSR register */
31705a0b428SJohn Marino 	__asm__ volatile ("ldmxcsr %0" : : "m" (envp->__mxcsr));
31805a0b428SJohn Marino 
31905a0b428SJohn Marino 	return (0);
32005a0b428SJohn Marino }
32105a0b428SJohn Marino 
32205a0b428SJohn Marino /*
32305a0b428SJohn Marino  * The feupdateenv() function saves the currently raised floating-point
32405a0b428SJohn Marino  * exceptions in its automatic storage, installs the floating-point environment
32505a0b428SJohn Marino  * represented by the object pointed to by `envp', and then raises the saved
32605a0b428SJohn Marino  * floating-point exceptions. The argument `envp' shall point to an object set
32705a0b428SJohn Marino  * by a call to feholdexcept() or fegetenv(), or equal a floating-point
32805a0b428SJohn Marino  * environment macro.
32905a0b428SJohn Marino  */
33005a0b428SJohn Marino int
feupdateenv(const fenv_t * envp)33105a0b428SJohn Marino feupdateenv(const fenv_t *envp)
33205a0b428SJohn Marino {
33305a0b428SJohn Marino 	unsigned short status;
33405a0b428SJohn Marino 	unsigned int mxcsr;
33505a0b428SJohn Marino 
33605a0b428SJohn Marino 	/* Store the x87 status register */
33705a0b428SJohn Marino 	__asm__ volatile ("fnstsw %0" : "=am" (status));
33805a0b428SJohn Marino 
33905a0b428SJohn Marino 	/* Store the MXCSR register */
34005a0b428SJohn Marino 	__asm__ volatile ("stmxcsr %0" : "=m" (mxcsr));
34105a0b428SJohn Marino 
34205a0b428SJohn Marino 	/* Install new floating-point environment */
34305a0b428SJohn Marino 	fesetenv(envp);
34405a0b428SJohn Marino 
34505a0b428SJohn Marino 	/* Raise any previously accumulated exceptions */
34605a0b428SJohn Marino 	feraiseexcept(status | mxcsr);
34705a0b428SJohn Marino 
34805a0b428SJohn Marino 	return (0);
34905a0b428SJohn Marino }
35005a0b428SJohn Marino 
35105a0b428SJohn Marino /*
35205a0b428SJohn Marino  * The following functions are extentions to the standard
35305a0b428SJohn Marino  */
35405a0b428SJohn Marino int
feenableexcept(int mask)35505a0b428SJohn Marino feenableexcept(int mask)
35605a0b428SJohn Marino {
35705a0b428SJohn Marino 	unsigned int mxcsr, omask;
35805a0b428SJohn Marino 	unsigned short control;
35905a0b428SJohn Marino 
36005a0b428SJohn Marino 	mask &= FE_ALL_EXCEPT;
36105a0b428SJohn Marino 
36205a0b428SJohn Marino 	__asm__ volatile ("fnstcw %0" : "=m" (control));
36305a0b428SJohn Marino 	__asm__ volatile ("stmxcsr %0" : "=m" (mxcsr));
36405a0b428SJohn Marino 
36505a0b428SJohn Marino 	omask = ~(control | (mxcsr >> _SSE_MASK_SHIFT)) & FE_ALL_EXCEPT;
36605a0b428SJohn Marino 	control &= ~mask;
36705a0b428SJohn Marino 	__asm__ volatile ("fldcw %0" : : "m" (control));
36805a0b428SJohn Marino 
36905a0b428SJohn Marino 	mxcsr &= ~(mask << _SSE_MASK_SHIFT);
37005a0b428SJohn Marino 	__asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr));
37105a0b428SJohn Marino 
37205a0b428SJohn Marino 	return (omask);
37305a0b428SJohn Marino }
37405a0b428SJohn Marino 
37505a0b428SJohn Marino int
fedisableexcept(int mask)37605a0b428SJohn Marino fedisableexcept(int mask)
37705a0b428SJohn Marino {
37805a0b428SJohn Marino 	unsigned int mxcsr, omask;
37905a0b428SJohn Marino 	unsigned short control;
38005a0b428SJohn Marino 
38105a0b428SJohn Marino 	mask &= FE_ALL_EXCEPT;
38205a0b428SJohn Marino 
38305a0b428SJohn Marino 	__asm__ volatile ("fnstcw %0" : "=m" (control));
38405a0b428SJohn Marino 	__asm__ volatile ("stmxcsr %0" : "=m" (mxcsr));
38505a0b428SJohn Marino 
38605a0b428SJohn Marino 	omask = ~(control | (mxcsr >> _SSE_MASK_SHIFT)) & FE_ALL_EXCEPT;
38705a0b428SJohn Marino 	control |= mask;
38805a0b428SJohn Marino 	__asm__ volatile ("fldcw %0" : : "m" (control));
38905a0b428SJohn Marino 
39005a0b428SJohn Marino 	mxcsr |= mask << _SSE_MASK_SHIFT;
39105a0b428SJohn Marino 	__asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr));
39205a0b428SJohn Marino 
39305a0b428SJohn Marino 	return (omask);
39405a0b428SJohn Marino }
39505a0b428SJohn Marino 
39605a0b428SJohn Marino int
fegetexcept(void)39705a0b428SJohn Marino fegetexcept(void)
39805a0b428SJohn Marino {
39905a0b428SJohn Marino 	unsigned short control;
40005a0b428SJohn Marino 
40105a0b428SJohn Marino 	/*
40205a0b428SJohn Marino 	 * We assume that the masks for the x87 and the SSE unit are
40305a0b428SJohn Marino 	 * the same.
40405a0b428SJohn Marino 	 */
40505a0b428SJohn Marino 	__asm__ volatile ("fnstcw %0" : "=m" (control));
40605a0b428SJohn Marino 
40705a0b428SJohn Marino 	return (~control & FE_ALL_EXCEPT);
40805a0b428SJohn Marino }
409