1*84d9c625SLionel Sambuc /* $NetBSD: fenv.c,v 1.6 2013/11/11 00:31:51 joerg Exp $ */
22fe8fb19SBen Gras
32fe8fb19SBen Gras /*-
42fe8fb19SBen Gras * Copyright (c) 2004-2005 David Schultz <das@FreeBSD.ORG>
52fe8fb19SBen Gras * All rights reserved.
62fe8fb19SBen Gras *
72fe8fb19SBen Gras * Redistribution and use in source and binary forms, with or without
82fe8fb19SBen Gras * modification, are permitted provided that the following conditions
92fe8fb19SBen Gras * are met:
102fe8fb19SBen Gras * 1. Redistributions of source code must retain the above copyright
112fe8fb19SBen Gras * notice, this list of conditions and the following disclaimer.
122fe8fb19SBen Gras * 2. Redistributions in binary form must reproduce the above copyright
132fe8fb19SBen Gras * notice, this list of conditions and the following disclaimer in the
142fe8fb19SBen Gras * documentation and/or other materials provided with the distribution.
152fe8fb19SBen Gras *
162fe8fb19SBen Gras * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
172fe8fb19SBen Gras * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
182fe8fb19SBen Gras * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
192fe8fb19SBen Gras * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
202fe8fb19SBen Gras * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
212fe8fb19SBen Gras * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
222fe8fb19SBen Gras * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
232fe8fb19SBen Gras * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
242fe8fb19SBen Gras * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
252fe8fb19SBen Gras * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
262fe8fb19SBen Gras * SUCH DAMAGE.
272fe8fb19SBen Gras */
282fe8fb19SBen Gras
292fe8fb19SBen Gras #include <sys/cdefs.h>
30*84d9c625SLionel Sambuc __RCSID("$NetBSD: fenv.c,v 1.6 2013/11/11 00:31:51 joerg Exp $");
312fe8fb19SBen Gras
322fe8fb19SBen Gras #include <sys/param.h>
332fe8fb19SBen Gras #include <sys/sysctl.h>
342fe8fb19SBen Gras #include <assert.h>
352fe8fb19SBen Gras #include <fenv.h>
362fe8fb19SBen Gras #include <stddef.h>
372fe8fb19SBen Gras #include <string.h>
382fe8fb19SBen Gras
392fe8fb19SBen Gras /* Load x87 Control Word */
402fe8fb19SBen Gras #define __fldcw(__cw) __asm__ __volatile__ \
412fe8fb19SBen Gras ("fldcw %0" : : "m" (__cw))
422fe8fb19SBen Gras
432fe8fb19SBen Gras /* No-Wait Store Control Word */
442fe8fb19SBen Gras #define __fnstcw(__cw) __asm__ __volatile__ \
452fe8fb19SBen Gras ("fnstcw %0" : "=m" (*(__cw)))
462fe8fb19SBen Gras
472fe8fb19SBen Gras /* No-Wait Store Status Word */
482fe8fb19SBen Gras #define __fnstsw(__sw) __asm__ __volatile__ \
492fe8fb19SBen Gras ("fnstsw %0" : "=am" (*(__sw)))
502fe8fb19SBen Gras
512fe8fb19SBen Gras /* No-Wait Clear Exception Flags */
522fe8fb19SBen Gras #define __fnclex() __asm__ __volatile__ \
532fe8fb19SBen Gras ("fnclex")
542fe8fb19SBen Gras
552fe8fb19SBen Gras /* Load x87 Environment */
562fe8fb19SBen Gras #define __fldenv(__env) __asm__ __volatile__ \
572fe8fb19SBen Gras ("fldenv %0" : : "m" (__env))
582fe8fb19SBen Gras
592fe8fb19SBen Gras /* No-Wait Store x87 environment */
602fe8fb19SBen Gras #define __fnstenv(__env) __asm__ __volatile__ \
612fe8fb19SBen Gras ("fnstenv %0" : "=m" (*(__env)))
622fe8fb19SBen Gras
632fe8fb19SBen Gras /* Check for and handle pending unmasked x87 pending FPU exceptions */
642fe8fb19SBen Gras #define __fwait(__env) __asm__ __volatile__ \
652fe8fb19SBen Gras ("fwait")
662fe8fb19SBen Gras
672fe8fb19SBen Gras /* Load the MXCSR register */
682fe8fb19SBen Gras #define __ldmxcsr(__mxcsr) __asm__ __volatile__ \
692fe8fb19SBen Gras ("ldmxcsr %0" : : "m" (__mxcsr))
702fe8fb19SBen Gras
712fe8fb19SBen Gras /* Store the MXCSR register state */
722fe8fb19SBen Gras #define __stmxcsr(__mxcsr) __asm__ __volatile__ \
732fe8fb19SBen Gras ("stmxcsr %0" : "=m" (*(__mxcsr)))
742fe8fb19SBen Gras
752fe8fb19SBen Gras /*
762fe8fb19SBen Gras * The following constant represents the default floating-point environment
772fe8fb19SBen Gras * (that is, the one installed at program startup) and has type pointer to
782fe8fb19SBen Gras * const-qualified fenv_t.
792fe8fb19SBen Gras *
802fe8fb19SBen Gras * It can be used as an argument to the functions within the <fenv.h> header
812fe8fb19SBen Gras * that manage the floating-point environment, namely fesetenv() and
822fe8fb19SBen Gras * feupdateenv().
832fe8fb19SBen Gras *
842fe8fb19SBen Gras * x87 fpu registers are 16bit wide. The upper bits, 31-16, are marked as
852fe8fb19SBen Gras * RESERVED. We provide a partial floating-point environment, where we
862fe8fb19SBen Gras * define only the lower bits. The reserved bits are extracted and set by the
872fe8fb19SBen Gras * consumers of FE_DFL_ENV, during runtime.
882fe8fb19SBen Gras */
892fe8fb19SBen Gras fenv_t __fe_dfl_env = {
902fe8fb19SBen Gras {
912fe8fb19SBen Gras __NetBSD_NPXCW__, /* Control word register */
922fe8fb19SBen Gras 0x0, /* Unused */
932fe8fb19SBen Gras 0x0000, /* Status word register */
942fe8fb19SBen Gras 0x0, /* Unused */
952fe8fb19SBen Gras 0x0000ffff, /* Tag word register */
962fe8fb19SBen Gras 0x0, /* Unused */
972fe8fb19SBen Gras {
982fe8fb19SBen Gras 0x0000, 0x0000,
992fe8fb19SBen Gras 0x0000, 0xffff
1002fe8fb19SBen Gras }
1012fe8fb19SBen Gras },
1022fe8fb19SBen Gras __INITIAL_MXCSR__ /* MXCSR register */
1032fe8fb19SBen Gras };
1042fe8fb19SBen Gras
1052fe8fb19SBen Gras /*
1062fe8fb19SBen Gras * Test for SSE support on this processor.
1072fe8fb19SBen Gras *
1082fe8fb19SBen Gras * We need to use ldmxcsr/stmxcsr to get correct results if any part
1092fe8fb19SBen Gras * of the program was compiled to use SSE floating-point, but we can't
1102fe8fb19SBen Gras * use SSE on older processors.
1112fe8fb19SBen Gras *
1122fe8fb19SBen Gras * In order to do so, we need to query the processor capabilities via the CPUID
1132fe8fb19SBen Gras * instruction. We can make it even simpler though, by querying the machdep.sse
1142fe8fb19SBen Gras * sysctl.
1152fe8fb19SBen Gras */
1162fe8fb19SBen Gras static int __HAS_SSE = 0;
1172fe8fb19SBen Gras
118*84d9c625SLionel Sambuc static void __init_libm(void) __attribute__ ((constructor, used));
1192fe8fb19SBen Gras
__init_libm(void)120*84d9c625SLionel Sambuc static void __init_libm(void)
1212fe8fb19SBen Gras {
122*84d9c625SLionel Sambuc #if !defined(__minix)
1232fe8fb19SBen Gras size_t oldlen = sizeof(__HAS_SSE);
1242fe8fb19SBen Gras int rv;
125*84d9c625SLionel Sambuc uint16_t control;
1262fe8fb19SBen Gras
1272fe8fb19SBen Gras rv = sysctlbyname("machdep.sse", &__HAS_SSE, &oldlen, NULL, 0);
1282fe8fb19SBen Gras if (rv == -1)
1292fe8fb19SBen Gras __HAS_SSE = 0;
130*84d9c625SLionel Sambuc #else
131*84d9c625SLionel Sambuc uint16_t control;
132*84d9c625SLionel Sambuc __HAS_SSE = 0;
133*84d9c625SLionel Sambuc #endif /* !defined(__minix) */
134*84d9c625SLionel Sambuc
135*84d9c625SLionel Sambuc __fnstcw(&control);
136*84d9c625SLionel Sambuc __fe_dfl_env.x87.control = control;
1372fe8fb19SBen Gras }
1382fe8fb19SBen Gras
1392fe8fb19SBen Gras /*
1402fe8fb19SBen Gras * The feclearexcept() function clears the supported floating-point exceptions
1412fe8fb19SBen Gras * represented by `excepts'.
1422fe8fb19SBen Gras */
1432fe8fb19SBen Gras int
feclearexcept(int excepts)1442fe8fb19SBen Gras feclearexcept(int excepts)
1452fe8fb19SBen Gras {
1462fe8fb19SBen Gras fenv_t env;
1472fe8fb19SBen Gras uint32_t mxcsr;
1482fe8fb19SBen Gras int ex;
1492fe8fb19SBen Gras
1502fe8fb19SBen Gras _DIAGASSERT((excepts & ~FE_ALL_EXCEPT) == 0);
1512fe8fb19SBen Gras
1522fe8fb19SBen Gras ex = excepts & FE_ALL_EXCEPT;
1532fe8fb19SBen Gras
1542fe8fb19SBen Gras /* It's ~3x faster to call fnclex, than store/load fp env */
1552fe8fb19SBen Gras if (ex == FE_ALL_EXCEPT) {
1562fe8fb19SBen Gras __fnclex();
1572fe8fb19SBen Gras } else {
1582fe8fb19SBen Gras __fnstenv(&env);
1592fe8fb19SBen Gras env.x87.status &= ~ex;
1602fe8fb19SBen Gras __fldenv(env);
1612fe8fb19SBen Gras }
1622fe8fb19SBen Gras
1632fe8fb19SBen Gras if (__HAS_SSE) {
1642fe8fb19SBen Gras __stmxcsr(&mxcsr);
1652fe8fb19SBen Gras mxcsr &= ~ex;
1662fe8fb19SBen Gras __ldmxcsr(mxcsr);
1672fe8fb19SBen Gras }
1682fe8fb19SBen Gras
1692fe8fb19SBen Gras /* Success */
1702fe8fb19SBen Gras return (0);
1712fe8fb19SBen Gras }
1722fe8fb19SBen Gras
1732fe8fb19SBen Gras /*
1742fe8fb19SBen Gras * The fegetexceptflag() function stores an implementation-defined
1752fe8fb19SBen Gras * representation of the states of the floating-point status flags indicated by
1762fe8fb19SBen Gras * the argument excepts in the object pointed to by the argument flagp.
1772fe8fb19SBen Gras */
1782fe8fb19SBen Gras int
fegetexceptflag(fexcept_t * flagp,int excepts)1792fe8fb19SBen Gras fegetexceptflag(fexcept_t *flagp, int excepts)
1802fe8fb19SBen Gras {
1812fe8fb19SBen Gras uint32_t mxcsr;
1822fe8fb19SBen Gras uint16_t status;
1832fe8fb19SBen Gras int ex;
1842fe8fb19SBen Gras
1852fe8fb19SBen Gras _DIAGASSERT(flagp != NULL);
1862fe8fb19SBen Gras _DIAGASSERT((excepts & ~FE_ALL_EXCEPT) == 0);
1872fe8fb19SBen Gras
1882fe8fb19SBen Gras ex = excepts & FE_ALL_EXCEPT;
1892fe8fb19SBen Gras
1902fe8fb19SBen Gras __fnstsw(&status);
1912fe8fb19SBen Gras if (__HAS_SSE)
1922fe8fb19SBen Gras __stmxcsr(&mxcsr);
1932fe8fb19SBen Gras else
1942fe8fb19SBen Gras mxcsr = 0;
1952fe8fb19SBen Gras
1962fe8fb19SBen Gras *flagp = (mxcsr | status) & ex;
1972fe8fb19SBen Gras
1982fe8fb19SBen Gras /* Success */
1992fe8fb19SBen Gras return (0);
2002fe8fb19SBen Gras }
2012fe8fb19SBen Gras
2022fe8fb19SBen Gras /*
2032fe8fb19SBen Gras * The feraiseexcept() function raises the supported floating-point exceptions
2042fe8fb19SBen Gras * represented by the argument `excepts'.
2052fe8fb19SBen Gras *
2062fe8fb19SBen Gras * The standard explicitly allows us to execute an instruction that has the
2072fe8fb19SBen Gras * exception as a side effect, but we choose to manipulate the status register
2082fe8fb19SBen Gras * directly.
2092fe8fb19SBen Gras *
2102fe8fb19SBen Gras * The validation of input is being deferred to fesetexceptflag().
2112fe8fb19SBen Gras */
2122fe8fb19SBen Gras int
feraiseexcept(int excepts)2132fe8fb19SBen Gras feraiseexcept(int excepts)
2142fe8fb19SBen Gras {
2152fe8fb19SBen Gras fexcept_t ex;
2162fe8fb19SBen Gras
2172fe8fb19SBen Gras _DIAGASSERT((excepts & ~FE_ALL_EXCEPT) == 0);
2182fe8fb19SBen Gras
2192fe8fb19SBen Gras ex = excepts & FE_ALL_EXCEPT;
2202fe8fb19SBen Gras fesetexceptflag(&ex, excepts);
2212fe8fb19SBen Gras __fwait();
2222fe8fb19SBen Gras
2232fe8fb19SBen Gras /* Success */
2242fe8fb19SBen Gras return (0);
2252fe8fb19SBen Gras }
2262fe8fb19SBen Gras
2272fe8fb19SBen Gras /*
2282fe8fb19SBen Gras * This function sets the floating-point status flags indicated by the argument
2292fe8fb19SBen Gras * `excepts' to the states stored in the object pointed to by `flagp'. It does
2302fe8fb19SBen Gras * NOT raise any floating-point exceptions, but only sets the state of the flags.
2312fe8fb19SBen Gras */
2322fe8fb19SBen Gras int
fesetexceptflag(const fexcept_t * flagp,int excepts)2332fe8fb19SBen Gras fesetexceptflag(const fexcept_t *flagp, int excepts)
2342fe8fb19SBen Gras {
2352fe8fb19SBen Gras fenv_t env;
2362fe8fb19SBen Gras uint32_t mxcsr;
2372fe8fb19SBen Gras int ex;
2382fe8fb19SBen Gras
2392fe8fb19SBen Gras _DIAGASSERT(flagp != NULL);
2402fe8fb19SBen Gras _DIAGASSERT((excepts & ~FE_ALL_EXCEPT) == 0);
2412fe8fb19SBen Gras
2422fe8fb19SBen Gras ex = excepts & FE_ALL_EXCEPT;
2432fe8fb19SBen Gras
2442fe8fb19SBen Gras __fnstenv(&env);
2452fe8fb19SBen Gras env.x87.status &= ~ex;
2462fe8fb19SBen Gras env.x87.status |= *flagp & ex;
2472fe8fb19SBen Gras __fldenv(env);
2482fe8fb19SBen Gras
2492fe8fb19SBen Gras if (__HAS_SSE) {
2502fe8fb19SBen Gras __stmxcsr(&mxcsr);
2512fe8fb19SBen Gras mxcsr &= ~ex;
2522fe8fb19SBen Gras mxcsr |= *flagp & ex;
2532fe8fb19SBen Gras __ldmxcsr(mxcsr);
2542fe8fb19SBen Gras }
2552fe8fb19SBen Gras
2562fe8fb19SBen Gras /* Success */
2572fe8fb19SBen Gras return (0);
2582fe8fb19SBen Gras }
2592fe8fb19SBen Gras
2602fe8fb19SBen Gras /*
2612fe8fb19SBen Gras * The fetestexcept() function determines which of a specified subset of the
2622fe8fb19SBen Gras * floating-point exception flags are currently set. The `excepts' argument
2632fe8fb19SBen Gras * specifies the floating-point status flags to be queried.
2642fe8fb19SBen Gras */
2652fe8fb19SBen Gras int
fetestexcept(int excepts)2662fe8fb19SBen Gras fetestexcept(int excepts)
2672fe8fb19SBen Gras {
2682fe8fb19SBen Gras uint32_t mxcsr;
2692fe8fb19SBen Gras uint16_t status;
2702fe8fb19SBen Gras int ex;
2712fe8fb19SBen Gras
2722fe8fb19SBen Gras _DIAGASSERT((excepts & ~FE_ALL_EXCEPT) == 0);
2732fe8fb19SBen Gras
2742fe8fb19SBen Gras ex = excepts & FE_ALL_EXCEPT;
2752fe8fb19SBen Gras
2762fe8fb19SBen Gras __fnstsw(&status);
2772fe8fb19SBen Gras if (__HAS_SSE)
2782fe8fb19SBen Gras __stmxcsr(&mxcsr);
2792fe8fb19SBen Gras else
2802fe8fb19SBen Gras mxcsr = 0;
2812fe8fb19SBen Gras
2822fe8fb19SBen Gras return ((status | mxcsr) & ex);
2832fe8fb19SBen Gras }
2842fe8fb19SBen Gras
2852fe8fb19SBen Gras int
fegetround(void)2862fe8fb19SBen Gras fegetround(void)
2872fe8fb19SBen Gras {
2882fe8fb19SBen Gras uint16_t control;
2892fe8fb19SBen Gras
2902fe8fb19SBen Gras /*
2912fe8fb19SBen Gras * We assume that the x87 and the SSE unit agree on the
2922fe8fb19SBen Gras * rounding mode. Reading the control word on the x87 turns
2932fe8fb19SBen Gras * out to be about 5 times faster than reading it on the SSE
2942fe8fb19SBen Gras * unit on an Opteron 244.
2952fe8fb19SBen Gras */
2962fe8fb19SBen Gras __fnstcw(&control);
2972fe8fb19SBen Gras
2982fe8fb19SBen Gras return (control & __X87_ROUND_MASK);
2992fe8fb19SBen Gras }
3002fe8fb19SBen Gras
3012fe8fb19SBen Gras /*
3022fe8fb19SBen Gras * The fesetround() function shall establish the rounding direction represented
3032fe8fb19SBen Gras * by its argument round. If the argument is not equal to the value of a
3042fe8fb19SBen Gras * rounding direction macro, the rounding direction is not changed.
3052fe8fb19SBen Gras */
3062fe8fb19SBen Gras int
fesetround(int round)3072fe8fb19SBen Gras fesetround(int round)
3082fe8fb19SBen Gras {
3092fe8fb19SBen Gras uint32_t mxcsr;
3102fe8fb19SBen Gras uint16_t control;
3112fe8fb19SBen Gras
3122fe8fb19SBen Gras if (round & ~__X87_ROUND_MASK) {
3132fe8fb19SBen Gras /* Failure */
3142fe8fb19SBen Gras return (-1);
3152fe8fb19SBen Gras }
3162fe8fb19SBen Gras
3172fe8fb19SBen Gras __fnstcw(&control);
3182fe8fb19SBen Gras control &= ~__X87_ROUND_MASK;
3192fe8fb19SBen Gras control |= round;
3202fe8fb19SBen Gras __fldcw(control);
3212fe8fb19SBen Gras
3222fe8fb19SBen Gras if (__HAS_SSE) {
3232fe8fb19SBen Gras __stmxcsr(&mxcsr);
3242fe8fb19SBen Gras mxcsr &= ~(__X87_ROUND_MASK << __SSE_ROUND_SHIFT);
3252fe8fb19SBen Gras mxcsr |= round << __SSE_ROUND_SHIFT;
3262fe8fb19SBen Gras __ldmxcsr(mxcsr);
3272fe8fb19SBen Gras }
3282fe8fb19SBen Gras
3292fe8fb19SBen Gras /* Success */
3302fe8fb19SBen Gras return (0);
3312fe8fb19SBen Gras }
3322fe8fb19SBen Gras
3332fe8fb19SBen Gras /*
3342fe8fb19SBen Gras * The fegetenv() function attempts to store the current floating-point
3352fe8fb19SBen Gras * environment in the object pointed to by envp.
3362fe8fb19SBen Gras */
3372fe8fb19SBen Gras int
fegetenv(fenv_t * envp)3382fe8fb19SBen Gras fegetenv(fenv_t *envp)
3392fe8fb19SBen Gras {
3402fe8fb19SBen Gras uint32_t mxcsr;
3412fe8fb19SBen Gras
3422fe8fb19SBen Gras _DIAGASSERT(flagp != NULL);
3432fe8fb19SBen Gras
3442fe8fb19SBen Gras /*
3452fe8fb19SBen Gras * fnstenv masks all exceptions, so we need to restore the old control
3462fe8fb19SBen Gras * word to avoid this side effect.
3472fe8fb19SBen Gras */
3482fe8fb19SBen Gras __fnstenv(envp);
3492fe8fb19SBen Gras __fldcw(envp->x87.control);
3502fe8fb19SBen Gras if (__HAS_SSE) {
3512fe8fb19SBen Gras __stmxcsr(&mxcsr);
3522fe8fb19SBen Gras envp->mxcsr = mxcsr;
3532fe8fb19SBen Gras }
3542fe8fb19SBen Gras
3552fe8fb19SBen Gras /* Success */
3562fe8fb19SBen Gras return (0);
3572fe8fb19SBen Gras }
3582fe8fb19SBen Gras
3592fe8fb19SBen Gras /*
3602fe8fb19SBen Gras * The feholdexcept() function saves the current floating-point environment in
3612fe8fb19SBen Gras * the object pointed to by envp, clears the floating-point status flags, and
3622fe8fb19SBen Gras * then installs a non-stop (continue on floating-point exceptions) mode, if
3632fe8fb19SBen Gras * available, for all floating-point exceptions.
3642fe8fb19SBen Gras */
3652fe8fb19SBen Gras int
feholdexcept(fenv_t * envp)3662fe8fb19SBen Gras feholdexcept(fenv_t *envp)
3672fe8fb19SBen Gras {
3682fe8fb19SBen Gras uint32_t mxcsr;
3692fe8fb19SBen Gras
3702fe8fb19SBen Gras _DIAGASSERT(envp != NULL);
3712fe8fb19SBen Gras
3722fe8fb19SBen Gras __fnstenv(envp);
3732fe8fb19SBen Gras __fnclex();
3742fe8fb19SBen Gras if (__HAS_SSE) {
3752fe8fb19SBen Gras __stmxcsr(&mxcsr);
3762fe8fb19SBen Gras envp->mxcsr = mxcsr;
3772fe8fb19SBen Gras mxcsr &= ~FE_ALL_EXCEPT;
3782fe8fb19SBen Gras mxcsr |= FE_ALL_EXCEPT << __SSE_EMASK_SHIFT;
3792fe8fb19SBen Gras __ldmxcsr(mxcsr);
3802fe8fb19SBen Gras }
3812fe8fb19SBen Gras
3822fe8fb19SBen Gras /* Success */
3832fe8fb19SBen Gras return (0);
3842fe8fb19SBen Gras }
3852fe8fb19SBen Gras
3862fe8fb19SBen Gras /*
3872fe8fb19SBen Gras * The fesetenv() function attempts to establish the floating-point environment
3882fe8fb19SBen Gras * represented by the object pointed to by envp. The argument `envp' points
3892fe8fb19SBen Gras * to an object set by a call to fegetenv() or feholdexcept(), or equal a
3902fe8fb19SBen Gras * floating-point environment macro. The fesetenv() function does not raise
3912fe8fb19SBen Gras * floating-point exceptions, but only installs the state of the floating-point
3922fe8fb19SBen Gras * status flags represented through its argument.
3932fe8fb19SBen Gras */
3942fe8fb19SBen Gras int
fesetenv(const fenv_t * envp)3952fe8fb19SBen Gras fesetenv(const fenv_t *envp)
3962fe8fb19SBen Gras {
3972fe8fb19SBen Gras fenv_t env;
3982fe8fb19SBen Gras
3992fe8fb19SBen Gras _DIAGASSERT(envp != NULL);
4002fe8fb19SBen Gras
4012fe8fb19SBen Gras /* Store the x87 floating-point environment */
4022fe8fb19SBen Gras memset(&env, 0, sizeof(env));
4032fe8fb19SBen Gras __fnstenv(&env);
4042fe8fb19SBen Gras
4052fe8fb19SBen Gras __fe_dfl_env.x87.unused1 = env.x87.unused1;
4062fe8fb19SBen Gras __fe_dfl_env.x87.unused2 = env.x87.unused2;
4072fe8fb19SBen Gras __fe_dfl_env.x87.unused3 = env.x87.unused3;
4082fe8fb19SBen Gras memcpy(__fe_dfl_env.x87.others,
4092fe8fb19SBen Gras env.x87.others,
4102fe8fb19SBen Gras sizeof(__fe_dfl_env.x87.others) / sizeof(uint32_t));
4112fe8fb19SBen Gras
4122fe8fb19SBen Gras __fldenv(envp->x87);
4132fe8fb19SBen Gras if (__HAS_SSE)
4142fe8fb19SBen Gras __ldmxcsr(envp->mxcsr);
4152fe8fb19SBen Gras
4162fe8fb19SBen Gras /* Success */
4172fe8fb19SBen Gras return (0);
4182fe8fb19SBen Gras }
4192fe8fb19SBen Gras
4202fe8fb19SBen Gras /*
4212fe8fb19SBen Gras * The feupdateenv() function saves the currently raised floating-point
4222fe8fb19SBen Gras * exceptions in its automatic storage, installs the floating-point environment
4232fe8fb19SBen Gras * represented by the object pointed to by `envp', and then raises the saved
4242fe8fb19SBen Gras * floating-point exceptions. The argument `envp' shall point to an object set
4252fe8fb19SBen Gras * by a call to feholdexcept() or fegetenv(), or equal a floating-point
4262fe8fb19SBen Gras * environment macro.
4272fe8fb19SBen Gras */
4282fe8fb19SBen Gras int
feupdateenv(const fenv_t * envp)4292fe8fb19SBen Gras feupdateenv(const fenv_t *envp)
4302fe8fb19SBen Gras {
4312fe8fb19SBen Gras fenv_t env;
4322fe8fb19SBen Gras uint32_t mxcsr;
4332fe8fb19SBen Gras uint16_t status;
4342fe8fb19SBen Gras
4352fe8fb19SBen Gras _DIAGASSERT(envp != NULL);
4362fe8fb19SBen Gras
4372fe8fb19SBen Gras /* Store the x87 floating-point environment */
4382fe8fb19SBen Gras memset(&env, 0, sizeof(env));
4392fe8fb19SBen Gras __fnstenv(&env);
4402fe8fb19SBen Gras
4412fe8fb19SBen Gras __fe_dfl_env.x87.unused1 = env.x87.unused1;
4422fe8fb19SBen Gras __fe_dfl_env.x87.unused2 = env.x87.unused2;
4432fe8fb19SBen Gras __fe_dfl_env.x87.unused3 = env.x87.unused3;
4442fe8fb19SBen Gras memcpy(__fe_dfl_env.x87.others,
4452fe8fb19SBen Gras env.x87.others,
4462fe8fb19SBen Gras sizeof(__fe_dfl_env.x87.others) / sizeof(uint32_t));
4472fe8fb19SBen Gras
4482fe8fb19SBen Gras __fnstsw(&status);
4492fe8fb19SBen Gras if (__HAS_SSE)
4502fe8fb19SBen Gras __stmxcsr(&mxcsr);
4512fe8fb19SBen Gras else
4522fe8fb19SBen Gras mxcsr = 0;
4532fe8fb19SBen Gras fesetenv(envp);
4542fe8fb19SBen Gras feraiseexcept((mxcsr | status) & FE_ALL_EXCEPT);
4552fe8fb19SBen Gras
4562fe8fb19SBen Gras /* Success */
4572fe8fb19SBen Gras return (0);
4582fe8fb19SBen Gras }
4592fe8fb19SBen Gras
4602fe8fb19SBen Gras /*
4612fe8fb19SBen Gras * The following functions are extentions to the standard
4622fe8fb19SBen Gras */
4632fe8fb19SBen Gras int
feenableexcept(int mask)4642fe8fb19SBen Gras feenableexcept(int mask)
4652fe8fb19SBen Gras {
4662fe8fb19SBen Gras uint32_t mxcsr, omask;
4672fe8fb19SBen Gras uint16_t control;
4682fe8fb19SBen Gras
4692fe8fb19SBen Gras mask &= FE_ALL_EXCEPT;
4702fe8fb19SBen Gras __fnstcw(&control);
4712fe8fb19SBen Gras if (__HAS_SSE)
4722fe8fb19SBen Gras __stmxcsr(&mxcsr);
4732fe8fb19SBen Gras else
4742fe8fb19SBen Gras mxcsr = 0;
4752fe8fb19SBen Gras
4762fe8fb19SBen Gras omask = (control | mxcsr >> __SSE_EMASK_SHIFT) & FE_ALL_EXCEPT;
4772fe8fb19SBen Gras control &= ~mask;
4782fe8fb19SBen Gras __fldcw(control);
4792fe8fb19SBen Gras if (__HAS_SSE) {
4802fe8fb19SBen Gras mxcsr &= ~(mask << __SSE_EMASK_SHIFT);
4812fe8fb19SBen Gras __ldmxcsr(mxcsr);
4822fe8fb19SBen Gras }
4832fe8fb19SBen Gras
484*84d9c625SLionel Sambuc return (FE_ALL_EXCEPT & ~omask);
4852fe8fb19SBen Gras }
4862fe8fb19SBen Gras
4872fe8fb19SBen Gras int
fedisableexcept(int mask)4882fe8fb19SBen Gras fedisableexcept(int mask)
4892fe8fb19SBen Gras {
4902fe8fb19SBen Gras uint32_t mxcsr, omask;
4912fe8fb19SBen Gras uint16_t control;
4922fe8fb19SBen Gras
4932fe8fb19SBen Gras mask &= FE_ALL_EXCEPT;
4942fe8fb19SBen Gras __fnstcw(&control);
4952fe8fb19SBen Gras if (__HAS_SSE)
4962fe8fb19SBen Gras __stmxcsr(&mxcsr);
4972fe8fb19SBen Gras else
4982fe8fb19SBen Gras mxcsr = 0;
4992fe8fb19SBen Gras
5002fe8fb19SBen Gras omask = (control | mxcsr >> __SSE_EMASK_SHIFT) & FE_ALL_EXCEPT;
5012fe8fb19SBen Gras control |= mask;
5022fe8fb19SBen Gras __fldcw(control);
5032fe8fb19SBen Gras if (__HAS_SSE) {
5042fe8fb19SBen Gras mxcsr |= mask << __SSE_EMASK_SHIFT;
5052fe8fb19SBen Gras __ldmxcsr(mxcsr);
5062fe8fb19SBen Gras }
5072fe8fb19SBen Gras
508*84d9c625SLionel Sambuc return (FE_ALL_EXCEPT & ~omask);
5092fe8fb19SBen Gras }
5102fe8fb19SBen Gras
5112fe8fb19SBen Gras int
fegetexcept(void)5122fe8fb19SBen Gras fegetexcept(void)
5132fe8fb19SBen Gras {
5142fe8fb19SBen Gras uint16_t control;
5152fe8fb19SBen Gras
5162fe8fb19SBen Gras /*
5172fe8fb19SBen Gras * We assume that the masks for the x87 and the SSE unit are
5182fe8fb19SBen Gras * the same.
5192fe8fb19SBen Gras */
5202fe8fb19SBen Gras __fnstcw(&control);
5212fe8fb19SBen Gras
522*84d9c625SLionel Sambuc return (~control & FE_ALL_EXCEPT);
5232fe8fb19SBen Gras }
524