1*fa59e253Sriastradh /* $NetBSD: fenv.c,v 1.11 2024/02/20 03:53:48 riastradh Exp $ */
27f1183f2Sjoerg
37f1183f2Sjoerg /*-
47f1183f2Sjoerg * Copyright (c) 2004-2005 David Schultz <das (at) FreeBSD.ORG>
57f1183f2Sjoerg * All rights reserved.
67f1183f2Sjoerg *
77f1183f2Sjoerg * Redistribution and use in source and binary forms, with or without
87f1183f2Sjoerg * modification, are permitted provided that the following conditions
97f1183f2Sjoerg * are met:
107f1183f2Sjoerg * 1. Redistributions of source code must retain the above copyright
117f1183f2Sjoerg * notice, this list of conditions and the following disclaimer.
127f1183f2Sjoerg * 2. Redistributions in binary form must reproduce the above copyright
137f1183f2Sjoerg * notice, this list of conditions and the following disclaimer in the
147f1183f2Sjoerg * documentation and/or other materials provided with the distribution.
157f1183f2Sjoerg *
167f1183f2Sjoerg * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
177f1183f2Sjoerg * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
187f1183f2Sjoerg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
197f1183f2Sjoerg * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
207f1183f2Sjoerg * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
217f1183f2Sjoerg * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
227f1183f2Sjoerg * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
237f1183f2Sjoerg * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
247f1183f2Sjoerg * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
257f1183f2Sjoerg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
267f1183f2Sjoerg * SUCH DAMAGE.
277f1183f2Sjoerg */
287f1183f2Sjoerg
297f1183f2Sjoerg #include <sys/cdefs.h>
30*fa59e253Sriastradh __RCSID("$NetBSD: fenv.c,v 1.11 2024/02/20 03:53:48 riastradh Exp $");
317e30e943Schs
327e30e943Schs #include "namespace.h"
337f1183f2Sjoerg
347f1183f2Sjoerg #include <assert.h>
357f1183f2Sjoerg #include <fenv.h>
367f1183f2Sjoerg #include <stddef.h>
377f1183f2Sjoerg #include <string.h>
387f1183f2Sjoerg
397e30e943Schs #ifdef __weak_alias
407e30e943Schs __weak_alias(feclearexcept,_feclearexcept)
417e30e943Schs __weak_alias(fedisableexcept,_fedisableexcept)
427e30e943Schs __weak_alias(feenableexcept,_feenableexcept)
437e30e943Schs __weak_alias(fegetenv,_fegetenv)
447e30e943Schs __weak_alias(fegetexcept,_fegetexcept)
457e30e943Schs __weak_alias(fegetexceptflag,_fegetexceptflag)
467e30e943Schs __weak_alias(fegetround,_fegetround)
477e30e943Schs __weak_alias(feholdexcept,_feholdexcept)
487e30e943Schs __weak_alias(feraiseexcept,_feraiseexcept)
497e30e943Schs __weak_alias(fesetenv,_fesetenv)
507e30e943Schs __weak_alias(fesetexceptflag,_fesetexceptflag)
517e30e943Schs __weak_alias(fesetround,_fesetround)
527e30e943Schs __weak_alias(fetestexcept,_fetestexcept)
537e30e943Schs __weak_alias(feupdateenv,_feupdateenv)
547e30e943Schs #endif
557e30e943Schs
567f1183f2Sjoerg /* Load x87 Control Word */
577f1183f2Sjoerg #define __fldcw(__cw) __asm__ __volatile__ \
587f1183f2Sjoerg ("fldcw %0" : : "m" (__cw))
597f1183f2Sjoerg
607f1183f2Sjoerg /* No-Wait Store Control Word */
617f1183f2Sjoerg #define __fnstcw(__cw) __asm__ __volatile__ \
627f1183f2Sjoerg ("fnstcw %0" : "=m" (*(__cw)))
637f1183f2Sjoerg
647f1183f2Sjoerg /* No-Wait Store Status Word */
657f1183f2Sjoerg #define __fnstsw(__sw) __asm__ __volatile__ \
667f1183f2Sjoerg ("fnstsw %0" : "=am" (*(__sw)))
677f1183f2Sjoerg
687f1183f2Sjoerg /* No-Wait Clear Exception Flags */
697f1183f2Sjoerg #define __fnclex() __asm__ __volatile__ \
707f1183f2Sjoerg ("fnclex")
717f1183f2Sjoerg
727f1183f2Sjoerg /* Load x87 Environment */
737f1183f2Sjoerg #define __fldenv(__env) __asm__ __volatile__ \
747f1183f2Sjoerg ("fldenv %0" : : "m" (__env))
757f1183f2Sjoerg
767f1183f2Sjoerg /* No-Wait Store x87 environment */
777f1183f2Sjoerg #define __fnstenv(__env) __asm__ __volatile__ \
787f1183f2Sjoerg ("fnstenv %0" : "=m" (*(__env)))
797f1183f2Sjoerg
805cb75bffSriastradh /* Check for and handle pending unmasked x87 pending FPU exceptions */
815cb75bffSriastradh #define __fwait(__env) __asm__ __volatile__ \
825cb75bffSriastradh ("fwait")
835cb75bffSriastradh
847f1183f2Sjoerg /* Load the MXCSR register */
857f1183f2Sjoerg #define __ldmxcsr(__mxcsr) __asm__ __volatile__ \
867f1183f2Sjoerg ("ldmxcsr %0" : : "m" (__mxcsr))
877f1183f2Sjoerg
887f1183f2Sjoerg /* Store the MXCSR register state */
897f1183f2Sjoerg #define __stmxcsr(__mxcsr) __asm__ __volatile__ \
907f1183f2Sjoerg ("stmxcsr %0" : "=m" (*(__mxcsr)))
917f1183f2Sjoerg
927f1183f2Sjoerg /*
937f1183f2Sjoerg * The following constant represents the default floating-point environment
947f1183f2Sjoerg * (that is, the one installed at program startup) and has type pointer to
957f1183f2Sjoerg * const-qualified fenv_t.
967f1183f2Sjoerg *
977f1183f2Sjoerg * It can be used as an argument to the functions within the <fenv.h> header
987f1183f2Sjoerg * that manage the floating-point environment, namely fesetenv() and
997f1183f2Sjoerg * feupdateenv().
1007f1183f2Sjoerg *
1017f1183f2Sjoerg * x87 fpu registers are 16bit wide. The upper bits, 31-16, are marked as
1027f1183f2Sjoerg * RESERVED. We provide a partial floating-point environment, where we
1037f1183f2Sjoerg * define only the lower bits. The reserved bits are extracted and set by
1047f1183f2Sjoerg * the consumers of FE_DFL_ENV, during runtime.
1057f1183f2Sjoerg */
1067f1183f2Sjoerg fenv_t __fe_dfl_env = {
1077f1183f2Sjoerg {
1087f1183f2Sjoerg __NetBSD_NPXCW__, /* Control word register */
1097f1183f2Sjoerg 0x00000000, /* Status word register */
1107f1183f2Sjoerg 0x0000ffff, /* Tag word register */
1117f1183f2Sjoerg {
1127f1183f2Sjoerg 0x00000000,
1137f1183f2Sjoerg 0x00000000,
1147f1183f2Sjoerg 0x00000000,
1157f1183f2Sjoerg 0x00000000,
1167f1183f2Sjoerg },
1177f1183f2Sjoerg },
1187f1183f2Sjoerg __INITIAL_MXCSR__ /* MXCSR register */
1197f1183f2Sjoerg };
1207f1183f2Sjoerg #define FE_DFL_ENV ((const fenv_t *) &__fe_dfl_env)
1217f1183f2Sjoerg
1220c8d18a9Sjoerg static void __init_libm(void) __attribute__ ((constructor, used));
1230c8d18a9Sjoerg
__init_libm(void)1240c8d18a9Sjoerg static void __init_libm(void)
1250c8d18a9Sjoerg {
1260c8d18a9Sjoerg uint16_t control;
1270c8d18a9Sjoerg
1280c8d18a9Sjoerg __fnstcw(&control);
1290c8d18a9Sjoerg __fe_dfl_env.x87.control = control;
1300c8d18a9Sjoerg }
1310c8d18a9Sjoerg
1327f1183f2Sjoerg
1337f1183f2Sjoerg /*
1347f1183f2Sjoerg * The feclearexcept() function clears the supported floating-point exceptions
1357f1183f2Sjoerg * represented by `excepts'.
1367f1183f2Sjoerg */
1377f1183f2Sjoerg int
feclearexcept(int excepts)1387f1183f2Sjoerg feclearexcept(int excepts)
1397f1183f2Sjoerg {
1407f1183f2Sjoerg fenv_t fenv;
1417f1183f2Sjoerg int ex;
1427f1183f2Sjoerg
1437f1183f2Sjoerg _DIAGASSERT((excepts & ~FE_ALL_EXCEPT) == 0);
1447f1183f2Sjoerg
1457f1183f2Sjoerg ex = excepts & FE_ALL_EXCEPT;
1467f1183f2Sjoerg
1477f1183f2Sjoerg /* Store the current x87 floating-point environment */
1487f1183f2Sjoerg __fnstenv(&fenv);
1497f1183f2Sjoerg
1507f1183f2Sjoerg /* Clear the requested floating-point exceptions */
1517f1183f2Sjoerg fenv.x87.status &= ~ex;
1527f1183f2Sjoerg
153fbe76588Sandvar /* Load the x87 floating-point environment */
1547f1183f2Sjoerg __fldenv(fenv);
1557f1183f2Sjoerg
1567f1183f2Sjoerg /* Same for SSE environment */
1577f1183f2Sjoerg __stmxcsr(&fenv.mxcsr);
1587f1183f2Sjoerg fenv.mxcsr &= ~ex;
1597f1183f2Sjoerg __ldmxcsr(fenv.mxcsr);
1607f1183f2Sjoerg
1617f1183f2Sjoerg /* Success */
1627f1183f2Sjoerg return (0);
1637f1183f2Sjoerg }
1647f1183f2Sjoerg
1657f1183f2Sjoerg /*
1667f1183f2Sjoerg * The fegetexceptflag() function stores an implementation-defined
1677f1183f2Sjoerg * representation of the states of the floating-point status flags indicated by
1687f1183f2Sjoerg * the argument excepts in the object pointed to by the argument flagp.
1697f1183f2Sjoerg */
1707f1183f2Sjoerg int
fegetexceptflag(fexcept_t * flagp,int excepts)1717f1183f2Sjoerg fegetexceptflag(fexcept_t *flagp, int excepts)
1727f1183f2Sjoerg {
1737f1183f2Sjoerg uint32_t mxcsr;
1747f1183f2Sjoerg uint16_t x87_status;
1757f1183f2Sjoerg int ex;
1767f1183f2Sjoerg
1777f1183f2Sjoerg _DIAGASSERT(flagp != NULL);
1787f1183f2Sjoerg _DIAGASSERT((excepts & ~FE_ALL_EXCEPT) == 0);
1797f1183f2Sjoerg
1807f1183f2Sjoerg ex = excepts & FE_ALL_EXCEPT;
1817f1183f2Sjoerg
1827f1183f2Sjoerg /* Store the current x87 status register */
1837f1183f2Sjoerg __fnstsw(&x87_status);
1847f1183f2Sjoerg
1857f1183f2Sjoerg /* Store the MXCSR register */
1867f1183f2Sjoerg __stmxcsr(&mxcsr);
1877f1183f2Sjoerg
1887f1183f2Sjoerg /* Store the results in flagp */
1897f1183f2Sjoerg *flagp = (x87_status | mxcsr) & ex;
1907f1183f2Sjoerg
1917f1183f2Sjoerg /* Success */
1927f1183f2Sjoerg return (0);
1937f1183f2Sjoerg }
1947f1183f2Sjoerg
1957f1183f2Sjoerg /*
1967f1183f2Sjoerg * The feraiseexcept() function raises the supported floating-point exceptions
1977f1183f2Sjoerg * represented by the argument `excepts'.
1987f1183f2Sjoerg *
1997f1183f2Sjoerg * The standard explicitly allows us to execute an instruction that has the
2007f1183f2Sjoerg * exception as a side effect, but we choose to manipulate the status register
2017f1183f2Sjoerg * directly.
2027f1183f2Sjoerg *
2037f1183f2Sjoerg * The validation of input is being deferred to fesetexceptflag().
2047f1183f2Sjoerg */
2057f1183f2Sjoerg int
feraiseexcept(int excepts)2067f1183f2Sjoerg feraiseexcept(int excepts)
2077f1183f2Sjoerg {
2087f1183f2Sjoerg int ex;
2097f1183f2Sjoerg
2107f1183f2Sjoerg _DIAGASSERT((excepts & ~FE_ALL_EXCEPT) == 0);
2117f1183f2Sjoerg
2127f1183f2Sjoerg ex = excepts & FE_ALL_EXCEPT;
213eca2236bSchristos fesetexceptflag((unsigned int *)&ex, ex);
2145cb75bffSriastradh __fwait();
2157f1183f2Sjoerg
2167f1183f2Sjoerg /* Success */
2177f1183f2Sjoerg return (0);
2187f1183f2Sjoerg }
2197f1183f2Sjoerg
2207f1183f2Sjoerg /*
2217f1183f2Sjoerg * This function sets the floating-point status flags indicated by the argument
2227f1183f2Sjoerg * `excepts' to the states stored in the object pointed to by `flagp'. It does
2237f1183f2Sjoerg * NOT raise any floating-point exceptions, but only sets the state of the flags.
2247f1183f2Sjoerg */
2257f1183f2Sjoerg int
fesetexceptflag(const fexcept_t * flagp,int excepts)2267f1183f2Sjoerg fesetexceptflag(const fexcept_t *flagp, int excepts)
2277f1183f2Sjoerg {
2287f1183f2Sjoerg fenv_t fenv;
2297f1183f2Sjoerg int ex;
2307f1183f2Sjoerg
2317f1183f2Sjoerg _DIAGASSERT(flagp != NULL);
2327f1183f2Sjoerg _DIAGASSERT((excepts & ~FE_ALL_EXCEPT) == 0);
2337f1183f2Sjoerg
2347f1183f2Sjoerg ex = excepts & FE_ALL_EXCEPT;
2357f1183f2Sjoerg
2367f1183f2Sjoerg /* Store the current x87 floating-point environment */
2377f1183f2Sjoerg __fnstenv(&fenv);
2387f1183f2Sjoerg
2397f1183f2Sjoerg /* Set the requested status flags */
2407f1183f2Sjoerg fenv.x87.status |= *flagp & ex;
2417f1183f2Sjoerg
242fbe76588Sandvar /* Load the x87 floating-point environment */
2437f1183f2Sjoerg __fldenv(fenv);
2447f1183f2Sjoerg
2457f1183f2Sjoerg /* Same for SSE environment */
2467f1183f2Sjoerg __stmxcsr(&fenv.mxcsr);
2477f1183f2Sjoerg fenv.mxcsr |= *flagp & ex;
2487f1183f2Sjoerg __ldmxcsr(fenv.mxcsr);
2497f1183f2Sjoerg
2507f1183f2Sjoerg /* Success */
2517f1183f2Sjoerg return (0);
2527f1183f2Sjoerg }
2537f1183f2Sjoerg
2547f1183f2Sjoerg /*
2557f1183f2Sjoerg * The fetestexcept() function determines which of a specified subset of the
2567f1183f2Sjoerg * floating-point exception flags are currently set. The `excepts' argument
2577f1183f2Sjoerg * specifies the floating-point status flags to be queried.
2587f1183f2Sjoerg */
2597f1183f2Sjoerg int
fetestexcept(int excepts)2607f1183f2Sjoerg fetestexcept(int excepts)
2617f1183f2Sjoerg {
2627f1183f2Sjoerg uint32_t mxcsr;
2637f1183f2Sjoerg uint16_t status;
2647f1183f2Sjoerg int ex;
2657f1183f2Sjoerg
2667f1183f2Sjoerg _DIAGASSERT((excepts & ~FE_ALL_EXCEPT) == 0);
2677f1183f2Sjoerg
2687f1183f2Sjoerg ex = excepts & FE_ALL_EXCEPT;
2697f1183f2Sjoerg
2707f1183f2Sjoerg __fnstsw(&status);
2717f1183f2Sjoerg __stmxcsr(&mxcsr);
2727f1183f2Sjoerg
273*fa59e253Sriastradh return ((status | mxcsr) & ex);
2747f1183f2Sjoerg }
2757f1183f2Sjoerg
2767f1183f2Sjoerg /*
2777f1183f2Sjoerg * The fegetround() function gets the current rounding direction.
2787f1183f2Sjoerg */
2797f1183f2Sjoerg int
fegetround(void)2807f1183f2Sjoerg fegetround(void)
2817f1183f2Sjoerg {
2827f1183f2Sjoerg uint32_t mxcsr;
2837f1183f2Sjoerg uint16_t control;
2847f1183f2Sjoerg
2857f1183f2Sjoerg /*
2867f1183f2Sjoerg * We check both the x87 floating-point unit _and_ the SSE unit.
2877f1183f2Sjoerg * Normally, those two must agree with respect to each other. If they
2887f1183f2Sjoerg * don't, it's not our fault and the result is non-determinable, in
2897f1183f2Sjoerg * which case POSIX says that a negative value should be returned.
2907f1183f2Sjoerg */
2917f1183f2Sjoerg __fnstcw(&control);
2927f1183f2Sjoerg __stmxcsr(&mxcsr);
2937f1183f2Sjoerg
2947f1183f2Sjoerg if ((control & _X87_ROUNDING_MASK)
2957f1183f2Sjoerg != ((mxcsr & _SSE_ROUNDING_MASK) >> 3)) {
2967f1183f2Sjoerg return (-1);
2977f1183f2Sjoerg }
2987f1183f2Sjoerg
2997f1183f2Sjoerg return (control & _X87_ROUNDING_MASK);
3007f1183f2Sjoerg }
3017f1183f2Sjoerg
3027f1183f2Sjoerg /*
3037f1183f2Sjoerg * The fesetround() function establishes the rounding direction represented by
3047f1183f2Sjoerg * its argument `round'. If the argument is not equal to the value of a rounding
3057f1183f2Sjoerg * direction macro, the rounding direction is not changed.
3067f1183f2Sjoerg */
3077f1183f2Sjoerg int
fesetround(int round)3087f1183f2Sjoerg fesetround(int round)
3097f1183f2Sjoerg {
3107f1183f2Sjoerg uint32_t mxcsr;
3117f1183f2Sjoerg uint16_t control;
3127f1183f2Sjoerg
3137f1183f2Sjoerg /* Check whether requested rounding direction is supported */
3147f1183f2Sjoerg if (round & (~_X87_ROUNDING_MASK))
3157f1183f2Sjoerg return (-1);
3167f1183f2Sjoerg
3177f1183f2Sjoerg /* Store the current x87 control word register */
3187f1183f2Sjoerg __fnstcw(&control);
3197f1183f2Sjoerg
3207f1183f2Sjoerg /*
3217f1183f2Sjoerg * Set the rounding direction
3227f1183f2Sjoerg * Rounding Control is bits 10-11, so shift appropriately
3237f1183f2Sjoerg */
3247f1183f2Sjoerg control &= ~_X87_ROUNDING_MASK;
3257f1183f2Sjoerg control |= round;
3267f1183f2Sjoerg
3277f1183f2Sjoerg /* Load the x87 control word register */
3287f1183f2Sjoerg __fldcw(control);
3297f1183f2Sjoerg
3307f1183f2Sjoerg /*
3317f1183f2Sjoerg * Same for the SSE environment
3327f1183f2Sjoerg * Rounding Control is bits 13-14, so shift appropriately
3337f1183f2Sjoerg */
3347f1183f2Sjoerg __stmxcsr(&mxcsr);
3357f1183f2Sjoerg mxcsr &= ~_SSE_ROUNDING_MASK;
3367f1183f2Sjoerg mxcsr |= (round << _SSE_ROUND_SHIFT);
3377f1183f2Sjoerg __ldmxcsr(mxcsr);
3387f1183f2Sjoerg
3397f1183f2Sjoerg /* Success */
3407f1183f2Sjoerg return (0);
3417f1183f2Sjoerg }
3427f1183f2Sjoerg
3437f1183f2Sjoerg /*
3447f1183f2Sjoerg * The fegetenv() function attempts to store the current floating-point
3457f1183f2Sjoerg * environment in the object pointed to by envp.
3467f1183f2Sjoerg */
3477f1183f2Sjoerg int
fegetenv(fenv_t * envp)3487f1183f2Sjoerg fegetenv(fenv_t *envp)
3497f1183f2Sjoerg {
3507f1183f2Sjoerg _DIAGASSERT(envp != NULL);
3517f1183f2Sjoerg
3527f1183f2Sjoerg /* Store the current x87 floating-point environment */
3537f1183f2Sjoerg __fnstenv(envp);
3547f1183f2Sjoerg
3557f1183f2Sjoerg /* Store the MXCSR register state */
3567f1183f2Sjoerg __stmxcsr(&envp->mxcsr);
3577f1183f2Sjoerg
3587f1183f2Sjoerg /*
3597f1183f2Sjoerg * When an FNSTENV instruction is executed, all pending exceptions are
3607f1183f2Sjoerg * essentially lost (either the x87 FPU status register is cleared or all
3617f1183f2Sjoerg * exceptions are masked).
3627f1183f2Sjoerg *
3637f1183f2Sjoerg * 8.6 X87 FPU EXCEPTION SYNCHRONIZATION -
36460f3bf6aSandvar * Intel(R) 64 and IA-32 Architectures Software Developer's Manual - Vol 1
3657f1183f2Sjoerg *
3667f1183f2Sjoerg */
3677f1183f2Sjoerg __fldcw(envp->x87.control);
3687f1183f2Sjoerg
3697f1183f2Sjoerg /* Success */
3707f1183f2Sjoerg return (0);
3717f1183f2Sjoerg }
3727f1183f2Sjoerg
3737f1183f2Sjoerg /*
3747f1183f2Sjoerg * The feholdexcept() function saves the current floating-point environment
3757f1183f2Sjoerg * in the object pointed to by envp, clears the floating-point status flags, and
3767f1183f2Sjoerg * then installs a non-stop (continue on floating-point exceptions) mode, if
3777f1183f2Sjoerg * available, for all floating-point exceptions.
3787f1183f2Sjoerg */
3797f1183f2Sjoerg int
feholdexcept(fenv_t * envp)3807f1183f2Sjoerg feholdexcept(fenv_t *envp)
3817f1183f2Sjoerg {
3827f1183f2Sjoerg uint32_t mxcsr;
3837f1183f2Sjoerg
3847f1183f2Sjoerg _DIAGASSERT(envp != NULL);
3857f1183f2Sjoerg
3867f1183f2Sjoerg /* Store the current x87 floating-point environment */
3877f1183f2Sjoerg __fnstenv(envp);
3887f1183f2Sjoerg
3897f1183f2Sjoerg /* Clear all exception flags in FPU */
3907f1183f2Sjoerg __fnclex();
3917f1183f2Sjoerg
3927f1183f2Sjoerg /* Store the MXCSR register state */
3937f1183f2Sjoerg __stmxcsr(&envp->mxcsr);
3947f1183f2Sjoerg
3957f1183f2Sjoerg /* Clear exception flags in MXCSR XXX */
3967f1183f2Sjoerg mxcsr = envp->mxcsr;
3977f1183f2Sjoerg mxcsr &= ~FE_ALL_EXCEPT;
3987f1183f2Sjoerg
3997f1183f2Sjoerg /* Mask all exceptions */
4007f1183f2Sjoerg mxcsr |= FE_ALL_EXCEPT << _SSE_EMASK_SHIFT;
4017f1183f2Sjoerg
4027f1183f2Sjoerg __ldmxcsr(mxcsr);
4037f1183f2Sjoerg
4047f1183f2Sjoerg /* Success */
4057f1183f2Sjoerg return (0);
4067f1183f2Sjoerg }
4077f1183f2Sjoerg
4087f1183f2Sjoerg /*
4097f1183f2Sjoerg * The fesetenv() function attempts to establish the floating-point environment
4107f1183f2Sjoerg * represented by the object pointed to by envp. The argument `envp' points
4117f1183f2Sjoerg * to an object set by a call to fegetenv() or feholdexcept(), or equal a
4127f1183f2Sjoerg * floating-point environment macro. The fesetenv() function does not raise
4137f1183f2Sjoerg * floating-point exceptions, but only installs the state of the floating-point
4147f1183f2Sjoerg * status flags represented through its argument.
4157f1183f2Sjoerg */
4167f1183f2Sjoerg int
fesetenv(const fenv_t * envp)4177f1183f2Sjoerg fesetenv(const fenv_t *envp)
4187f1183f2Sjoerg {
4197f1183f2Sjoerg fenv_t fenv;
4207f1183f2Sjoerg
4217f1183f2Sjoerg _DIAGASSERT(envp != NULL);
4227f1183f2Sjoerg
4237f1183f2Sjoerg /* Store the x87 floating-point environment */
4247f1183f2Sjoerg memset(&fenv, 0, sizeof fenv);
4257f1183f2Sjoerg __fnstenv(&fenv);
4267f1183f2Sjoerg
4277f1183f2Sjoerg __fe_dfl_env.x87.control = (fenv.x87.control & 0xffff0000)
4287f1183f2Sjoerg | (__fe_dfl_env.x87.control & 0x0000ffff);
4297f1183f2Sjoerg __fe_dfl_env.x87.status = (fenv.x87.status & 0xffff0000)
4307f1183f2Sjoerg | (__fe_dfl_env.x87.status & 0x0000ffff);
4317f1183f2Sjoerg __fe_dfl_env.x87.tag = (fenv.x87.tag & 0xffff0000)
4327f1183f2Sjoerg | (__fe_dfl_env.x87.tag & 0x0000ffff);
4337f1183f2Sjoerg __fe_dfl_env.x87.others[3] = (fenv.x87.others[3] & 0xffff0000)
4347f1183f2Sjoerg | (__fe_dfl_env.x87.others[3] & 0x0000ffff);
4357f1183f2Sjoerg __fldenv(*envp);
4367f1183f2Sjoerg
4377f1183f2Sjoerg /* Store the MXCSR register */
4387f1183f2Sjoerg __ldmxcsr(envp->mxcsr);
4397f1183f2Sjoerg
4407f1183f2Sjoerg /* Success */
4417f1183f2Sjoerg return (0);
4427f1183f2Sjoerg }
4437f1183f2Sjoerg
4447f1183f2Sjoerg /*
4457f1183f2Sjoerg * The feupdateenv() function saves the currently raised floating-point
4467f1183f2Sjoerg * exceptions in its automatic storage, installs the floating-point environment
4477f1183f2Sjoerg * represented by the object pointed to by `envp', and then raises the saved
4487f1183f2Sjoerg * floating-point exceptions. The argument `envp' shall point to an object set
4497f1183f2Sjoerg * by a call to feholdexcept() or fegetenv(), or equal a floating-point
4507f1183f2Sjoerg * environment macro.
4517f1183f2Sjoerg */
4527f1183f2Sjoerg int
feupdateenv(const fenv_t * envp)4537f1183f2Sjoerg feupdateenv(const fenv_t *envp)
4547f1183f2Sjoerg {
4557f1183f2Sjoerg fenv_t fenv;
4567f1183f2Sjoerg uint32_t mxcsr;
4577f1183f2Sjoerg uint16_t sw;
4587f1183f2Sjoerg
4597f1183f2Sjoerg _DIAGASSERT(envp != NULL);
4607f1183f2Sjoerg
4617f1183f2Sjoerg /* Store the x87 floating-point environment */
4627f1183f2Sjoerg memset(&fenv, 0, sizeof(fenv));
4637f1183f2Sjoerg __fnstenv(&fenv);
4647f1183f2Sjoerg
4657f1183f2Sjoerg __fe_dfl_env.x87.control = (fenv.x87.control & 0xffff0000)
4667f1183f2Sjoerg | (__fe_dfl_env.x87.control & 0x0000ffff);
4677f1183f2Sjoerg __fe_dfl_env.x87.status = (fenv.x87.status & 0xffff0000)
4687f1183f2Sjoerg | (__fe_dfl_env.x87.status & 0x0000ffff);
4697f1183f2Sjoerg __fe_dfl_env.x87.tag = (fenv.x87.tag & 0xffff0000)
4707f1183f2Sjoerg | (__fe_dfl_env.x87.tag & 0x0000ffff);
4717f1183f2Sjoerg __fe_dfl_env.x87.others[3] = (fenv.x87.others[3] & 0xffff0000)
4727f1183f2Sjoerg | (__fe_dfl_env.x87.others[3] & 0x0000ffff);
4737f1183f2Sjoerg
4747f1183f2Sjoerg /* Store the x87 status register */
4757f1183f2Sjoerg __fnstsw(&sw);
4767f1183f2Sjoerg
4777f1183f2Sjoerg /* Store the MXCSR register */
4787f1183f2Sjoerg __stmxcsr(&mxcsr);
4797f1183f2Sjoerg
4807f1183f2Sjoerg /* Install new floating-point environment */
4817f1183f2Sjoerg fesetenv(envp);
4827f1183f2Sjoerg
4837f1183f2Sjoerg /* Raise any previously accumulated exceptions */
4847f1183f2Sjoerg feraiseexcept((sw | mxcsr) & FE_ALL_EXCEPT);
4857f1183f2Sjoerg
4867f1183f2Sjoerg /* Success */
4877f1183f2Sjoerg return (0);
4887f1183f2Sjoerg }
4897f1183f2Sjoerg
4907f1183f2Sjoerg /*
491f9faf20aSandvar * The following functions are extensions to the standard
4927f1183f2Sjoerg */
4937f1183f2Sjoerg int
feenableexcept(int mask)4947f1183f2Sjoerg feenableexcept(int mask)
4957f1183f2Sjoerg {
4967f1183f2Sjoerg uint32_t mxcsr, omask;
4977f1183f2Sjoerg uint16_t control;
4987f1183f2Sjoerg
4997f1183f2Sjoerg _DIAGASSERT((mask & ~FE_ALL_EXCEPT) == 0);
5007f1183f2Sjoerg mask &= FE_ALL_EXCEPT;
5017f1183f2Sjoerg
5027f1183f2Sjoerg __fnstcw(&control);
5037f1183f2Sjoerg __stmxcsr(&mxcsr);
5047f1183f2Sjoerg
5057f1183f2Sjoerg omask = (control | mxcsr >> _SSE_EMASK_SHIFT) & FE_ALL_EXCEPT;
5067f1183f2Sjoerg control &= ~mask;
5077f1183f2Sjoerg __fldcw(control);
5087f1183f2Sjoerg
5097f1183f2Sjoerg mxcsr &= ~(mask << _SSE_EMASK_SHIFT);
5107f1183f2Sjoerg __ldmxcsr(mxcsr);
5117f1183f2Sjoerg
5123a4a1ac2Sriastradh return (FE_ALL_EXCEPT & ~omask);
5137f1183f2Sjoerg
5147f1183f2Sjoerg }
5157f1183f2Sjoerg
5167f1183f2Sjoerg int
fedisableexcept(int mask)5177f1183f2Sjoerg fedisableexcept(int mask)
5187f1183f2Sjoerg {
5197f1183f2Sjoerg uint32_t mxcsr, omask;
5207f1183f2Sjoerg uint16_t control;
5217f1183f2Sjoerg
5227f1183f2Sjoerg _DIAGASSERT((mask & ~FE_ALL_EXCEPT) == 0);
5237f1183f2Sjoerg
5247f1183f2Sjoerg __fnstcw(&control);
5257f1183f2Sjoerg __stmxcsr(&mxcsr);
5267f1183f2Sjoerg
5277f1183f2Sjoerg omask = (control | mxcsr >> _SSE_EMASK_SHIFT) & FE_ALL_EXCEPT;
5287f1183f2Sjoerg control |= mask;
5297f1183f2Sjoerg __fldcw(control);
5307f1183f2Sjoerg
5317f1183f2Sjoerg mxcsr |= mask << _SSE_EMASK_SHIFT;
5327f1183f2Sjoerg __ldmxcsr(mxcsr);
5337f1183f2Sjoerg
5343a4a1ac2Sriastradh return (FE_ALL_EXCEPT & ~omask);
5357f1183f2Sjoerg }
5367f1183f2Sjoerg
5377f1183f2Sjoerg int
fegetexcept(void)5387f1183f2Sjoerg fegetexcept(void)
5397f1183f2Sjoerg {
5407f1183f2Sjoerg uint16_t control;
5417f1183f2Sjoerg
5427f1183f2Sjoerg /*
5437f1183f2Sjoerg * We assume that the masks for the x87 and the SSE unit are
5447f1183f2Sjoerg * the same.
5457f1183f2Sjoerg */
5467f1183f2Sjoerg __fnstcw(&control);
5477f1183f2Sjoerg
5480eddede8Sriastradh return (~control & FE_ALL_EXCEPT);
5497f1183f2Sjoerg }
5507f1183f2Sjoerg
551