diff options
Diffstat (limited to 'lib/libm/arch/i387/fenv.c')
-rw-r--r-- | lib/libm/arch/i387/fenv.c | 381 |
1 files changed, 160 insertions, 221 deletions
diff --git a/lib/libm/arch/i387/fenv.c b/lib/libm/arch/i387/fenv.c index 639a4d5c633..9f79a807e8b 100644 --- a/lib/libm/arch/i387/fenv.c +++ b/lib/libm/arch/i387/fenv.c @@ -1,5 +1,5 @@ -/* $OpenBSD: fenv.c,v 1.1 2011/04/24 00:35:22 martynas Exp $ */ -/* $NetBSD: fenv.c,v 1.3 2010/08/01 06:34:38 taca Exp $ */ +/* $OpenBSD: fenv.c,v 1.2 2011/04/28 17:34:23 martynas Exp $ */ +/* $NetBSD: fenv.c,v 1.3 2010/08/01 06:34:38 taca Exp $ */ /*- * Copyright (c) 2004-2005 David Schultz <das@FreeBSD.ORG> @@ -28,52 +28,12 @@ */ #include <sys/cdefs.h> - +#include <machine/cpu.h> +#include <machine/npx.h> #include <sys/param.h> #include <sys/sysctl.h> -#include <machine/cpu.h> -#include <assert.h> -#include <fenv.h> -#include <stddef.h> -#include <string.h> - -#define _DIAGASSERT(x) ((void) 0) /* XXX */ - -/* Load x87 Control Word */ -#define __fldcw(__cw) __asm__ __volatile__ \ - ("fldcw %0" : : "m" (__cw)) - -/* No-Wait Store Control Word */ -#define __fnstcw(__cw) __asm__ __volatile__ \ - ("fnstcw %0" : "=m" (*(__cw))) - -/* No-Wait Store Status Word */ -#define __fnstsw(__sw) __asm__ __volatile__ \ - ("fnstsw %0" : "=am" (*(__sw))) - -/* No-Wait Clear Exception Flags */ -#define __fnclex() __asm__ __volatile__ \ - ("fnclex") - -/* Load x87 Environment */ -#define __fldenv(__env) __asm__ __volatile__ \ - ("fldenv %0" : : "m" (__env)) - -/* No-Wait Store x87 environment */ -#define __fnstenv(__env) __asm__ __volatile__ \ - ("fnstenv %0" : "=m" (*(__env))) -/* Check for and handle pending unmasked x87 pending FPU exceptions */ -#define __fwait(__env) __asm__ __volatile__ \ - ("fwait") - -/* Load the MXCSR register */ -#define __ldmxcsr(__mxcsr) __asm__ __volatile__ \ - ("ldmxcsr %0" : : "m" (__mxcsr)) - -/* Store the MXCSR register state */ -#define __stmxcsr(__mxcsr) __asm__ __volatile__ \ - ("stmxcsr %0" : "=m" (*(__mxcsr))) +#include <fenv.h> /* * The following constant represents the default floating-point environment @@ -85,21 +45,18 @@ * feupdateenv(). * * x87 fpu registers are 16bit wide. The upper bits, 31-16, are marked as - * RESERVED. We provide a partial floating-point environment, where we - * define only the lower bits. The reserved bits are extracted and set by the - * consumers of FE_DFL_ENV, during runtime. + * RESERVED. */ fenv_t __fe_dfl_env = { { - __INITIAL_NPXCW__, /* Control word register */ - 0x0, /* Unused */ - 0x0000, /* Status word register */ - 0x0, /* Unused */ - 0x0000ffff, /* Tag word register */ - 0x0, /* Unused */ + 0xffff0000 | __INITIAL_NPXCW__, /* Control word register */ + 0xffff0000, /* Status word register */ + 0xffffffff, /* Tag word register */ { - 0x0000, 0x0000, - 0x0000, 0xffff + 0x00000000, + 0x00000000, + 0x00000000, + 0xffff0000 } }, __INITIAL_MXCSR__ /* MXCSR register */ @@ -138,30 +95,27 @@ static void __test_sse(void) int feclearexcept(int excepts) { - fenv_t env; - uint32_t mxcsr; - int ex; + fenv_t fenv; + unsigned int mxcsr; - _DIAGASSERT((excepts & ~FE_ALL_EXCEPT) == 0); + excepts &= FE_ALL_EXCEPT; - ex = excepts & FE_ALL_EXCEPT; + /* Store the current x87 floating-point environment */ + __asm__ __volatile__ ("fnstenv %0" : "=m" (fenv)); - /* It's ~3x faster to call fnclex, than store/load fp env */ - if (ex == FE_ALL_EXCEPT) { - __fnclex(); - } else { - __fnstenv(&env); - env.x87.status &= ~ex; - __fldenv(env); - } + /* Clear the requested floating-point exceptions */ + fenv.__x87.__status &= ~excepts; + + /* Load the x87 floating-point environent */ + __asm__ __volatile__ ("fldenv %0" : : "m" (fenv)); + /* Same for SSE environment */ if (__HAS_SSE) { - __stmxcsr(&mxcsr); - mxcsr &= ~ex; - __ldmxcsr(mxcsr); + __asm__ __volatile__ ("stmxcsr %0" : "=m" (mxcsr)); + mxcsr &= ~excepts; + __asm__ __volatile__ ("ldmxcsr %0" : : "m" (mxcsr)); } - /* Success */ return (0); } @@ -173,24 +127,21 @@ feclearexcept(int excepts) int fegetexceptflag(fexcept_t *flagp, int excepts) { - uint32_t mxcsr; - uint16_t status; - int ex; + unsigned short status; + unsigned int mxcsr = 0; - _DIAGASSERT(flagp != NULL); - _DIAGASSERT((excepts & ~FE_ALL_EXCEPT) == 0); + excepts &= FE_ALL_EXCEPT; - ex = excepts & FE_ALL_EXCEPT; + /* Store the current x87 status register */ + __asm__ __volatile__ ("fnstsw %0" : "=am" (status)); - __fnstsw(&status); + /* Store the MXCSR register */ if (__HAS_SSE) - __stmxcsr(&mxcsr); - else - mxcsr = 0; + __asm__ __volatile__ ("stmxcsr %0" : "=m" (mxcsr)); - *flagp = (mxcsr | status) & ex; + /* Store the results in flagp */ + *flagp = (status | mxcsr) & excepts; - /* Success */ return (0); } @@ -207,15 +158,11 @@ fegetexceptflag(fexcept_t *flagp, int excepts) int feraiseexcept(int excepts) { - fexcept_t ex; + excepts &= FE_ALL_EXCEPT; - _DIAGASSERT((excepts & ~FE_ALL_EXCEPT) == 0); + fesetexceptflag((fexcept_t *)&excepts, excepts); + __asm__ __volatile__ ("fwait"); - ex = excepts & FE_ALL_EXCEPT; - fesetexceptflag(&ex, excepts); - __fwait(); - - /* Success */ return (0); } @@ -227,28 +174,29 @@ feraiseexcept(int excepts) int fesetexceptflag(const fexcept_t *flagp, int excepts) { - fenv_t env; - uint32_t mxcsr; - int ex; + fenv_t fenv; + unsigned int mxcsr; + + excepts &= FE_ALL_EXCEPT; - _DIAGASSERT(flagp != NULL); - _DIAGASSERT((excepts & ~FE_ALL_EXCEPT) == 0); + /* Store the current x87 floating-point environment */ + __asm__ __volatile__ ("fnstenv %0" : "=m" (fenv)); - ex = excepts & FE_ALL_EXCEPT; + /* Set the requested status flags */ + fenv.__x87.__status &= ~excepts; + fenv.__x87.__status |= *flagp & excepts; - __fnstenv(&env); - env.x87.status &= ~ex; - env.x87.status |= *flagp & ex; - __fldenv(env); + /* Load the x87 floating-point environent */ + __asm__ __volatile__ ("fldenv %0" : : "m" (fenv)); + /* Same for SSE environment */ if (__HAS_SSE) { - __stmxcsr(&mxcsr); - mxcsr &= ~ex; - mxcsr |= *flagp & ex; - __ldmxcsr(mxcsr); + __asm__ __volatile__ ("stmxcsr %0" : "=m" (mxcsr)); + mxcsr &= ~excepts; + mxcsr |= *flagp & excepts; + __asm__ __volatile__ ("ldmxcsr %0" : : "m" (mxcsr)); } - /* Success */ return (0); } @@ -260,27 +208,28 @@ fesetexceptflag(const fexcept_t *flagp, int excepts) int fetestexcept(int excepts) { - uint32_t mxcsr; - uint16_t status; - int ex; + unsigned short status; + unsigned int mxcsr = 0; - _DIAGASSERT((excepts & ~FE_ALL_EXCEPT) == 0); + excepts &= FE_ALL_EXCEPT; - ex = excepts & FE_ALL_EXCEPT; + /* Store the current x87 status register */ + __asm__ __volatile__ ("fnstsw %0" : "=am" (status)); - __fnstsw(&status); + /* Store the MXCSR register state */ if (__HAS_SSE) - __stmxcsr(&mxcsr); - else - mxcsr = 0; + __asm__ __volatile__ ("stmxcsr %0" : "=m" (mxcsr)); - return ((status | mxcsr) & ex); + return ((status | mxcsr) & excepts); } +/* + * The fegetround() function gets the current rounding direction. + */ int fegetround(void) { - uint16_t control; + unsigned short control; /* * We assume that the x87 and the SSE unit agree on the @@ -288,40 +237,44 @@ fegetround(void) * out to be about 5 times faster than reading it on the SSE * unit on an Opteron 244. */ - __fnstcw(&control); + __asm__ __volatile__ ("fnstcw %0" : "=m" (control)); - return (control & __X87_ROUND_MASK); + return (control & _X87_ROUND_MASK); } /* - * The fesetround() function shall establish the rounding direction represented - * by its argument round. If the argument is not equal to the value of a - * rounding direction macro, the rounding direction is not changed. + * The fesetround() function establishes the rounding direction represented by + * its argument `round'. If the argument is not equal to the value of a rounding + * direction macro, the rounding direction is not changed. */ int fesetround(int round) { - uint32_t mxcsr; - uint16_t control; + unsigned short control; + unsigned int mxcsr; - if (round & ~__X87_ROUND_MASK) { - /* Failure */ + /* Check whether requested rounding direction is supported */ + if (round & ~_X87_ROUND_MASK) return (-1); - } - __fnstcw(&control); - control &= ~__X87_ROUND_MASK; + /* Store the current x87 control word register */ + __asm__ __volatile__ ("fnstcw %0" : "=m" (control)); + + /* Set the rounding direction */ + control &= ~_X87_ROUND_MASK; control |= round; - __fldcw(control); + /* Load the x87 control word register */ + __asm__ __volatile__ ("fldcw %0" : : "m" (control)); + + /* Same for the SSE environment */ if (__HAS_SSE) { - __stmxcsr(&mxcsr); - mxcsr &= ~(__X87_ROUND_MASK << __SSE_ROUND_SHIFT); - mxcsr |= round << __SSE_ROUND_SHIFT; - __ldmxcsr(mxcsr); + __asm__ __volatile__ ("stmxcsr %0" : "=m" (mxcsr)); + mxcsr &= ~(_X87_ROUND_MASK << _SSE_ROUND_SHIFT); + mxcsr |= round << _SSE_ROUND_SHIFT; + __asm__ __volatile__ ("ldmxcsr %0" : : "m" (mxcsr)); } - /* Success */ return (0); } @@ -332,49 +285,58 @@ fesetround(int round) int fegetenv(fenv_t *envp) { - uint32_t mxcsr; + /* Store the current x87 floating-point environment */ + __asm__ __volatile__ ("fnstenv %0" : "=m" (*envp)); - _DIAGASSERT(flagp != NULL); + /* Store the MXCSR register state */ + if (__HAS_SSE) + __asm__ __volatile__ ("stmxcsr %0" : "=m" (envp->__mxcsr)); /* - * fnstenv masks all exceptions, so we need to restore the old control - * word to avoid this side effect. + * When an FNSTENV instruction is executed, all pending exceptions are + * essentially lost (either the x87 FPU status register is cleared or + * all exceptions are masked). + * + * 8.6 X87 FPU EXCEPTION SYNCHRONIZATION - + * Intel(R) 64 and IA-32 Architectures Softare Developer's Manual - Vol1 */ - __fnstenv(envp); - __fldcw(envp->x87.control); - if (__HAS_SSE) { - __stmxcsr(&mxcsr); - envp->mxcsr = mxcsr; - } + __asm__ __volatile__ ("fldcw %0" : : "m" (envp->__x87.__control)); - /* Success */ return (0); } /* - * The feholdexcept() function saves the current floating-point environment in - * the object pointed to by envp, clears the floating-point status flags, and + * The feholdexcept() function saves the current floating-point environment + * in the object pointed to by envp, clears the floating-point status flags, and * then installs a non-stop (continue on floating-point exceptions) mode, if * available, for all floating-point exceptions. */ int feholdexcept(fenv_t *envp) { - uint32_t mxcsr; + unsigned int mxcsr; - _DIAGASSERT(envp != NULL); + /* Store the current x87 floating-point environment */ + __asm__ __volatile__ ("fnstenv %0" : "=m" (*envp)); + + /* Clear all exception flags in FPU */ + __asm__ __volatile__ ("fnclex"); - __fnstenv(envp); - __fnclex(); if (__HAS_SSE) { - __stmxcsr(&mxcsr); - envp->mxcsr = mxcsr; + /* Store the MXCSR register state */ + __asm__ __volatile__ ("stmxcsr %0" : "=m" (envp->__mxcsr)); + + /* Clear exception flags in MXCSR */ + mxcsr = envp->__mxcsr; mxcsr &= ~FE_ALL_EXCEPT; - mxcsr |= FE_ALL_EXCEPT << __SSE_EMASK_SHIFT; - __ldmxcsr(mxcsr); + + /* Mask all exceptions */ + mxcsr |= FE_ALL_EXCEPT << _SSE_MASK_SHIFT; + + /* Store the MXCSR register */ + __asm__ __volatile__ ("ldmxcsr %0" : : "m" (mxcsr)); } - /* Success */ return (0); } @@ -389,26 +351,13 @@ feholdexcept(fenv_t *envp) int fesetenv(const fenv_t *envp) { - fenv_t env; - - _DIAGASSERT(envp != NULL); + /* Load the x87 floating-point environent */ + __asm__ __volatile__ ("fldenv %0" : : "m" (*envp)); - /* Store the x87 floating-point environment */ - memset(&env, 0, sizeof(env)); - __fnstenv(&env); - - __fe_dfl_env.x87.unused1 = env.x87.unused1; - __fe_dfl_env.x87.unused2 = env.x87.unused2; - __fe_dfl_env.x87.unused3 = env.x87.unused3; - memcpy(__fe_dfl_env.x87.others, - env.x87.others, - sizeof(__fe_dfl_env.x87.others) / sizeof(uint32_t)); - - __fldenv(envp->x87); + /* Store the MXCSR register */ if (__HAS_SSE) - __ldmxcsr(envp->mxcsr); + __asm__ __volatile__ ("ldmxcsr %0" : : "m" (envp->__mxcsr)); - /* Success */ return (0); } @@ -423,32 +372,22 @@ fesetenv(const fenv_t *envp) int feupdateenv(const fenv_t *envp) { - fenv_t env; - uint32_t mxcsr; - uint16_t status; - - _DIAGASSERT(envp != NULL); + unsigned short status; + unsigned int mxcsr = 0; - /* Store the x87 floating-point environment */ - memset(&env, 0, sizeof(env)); - __fnstenv(&env); + /* Store the x87 status register */ + __asm__ __volatile__ ("fnstsw %0" : "=am" (status)); - __fe_dfl_env.x87.unused1 = env.x87.unused1; - __fe_dfl_env.x87.unused2 = env.x87.unused2; - __fe_dfl_env.x87.unused3 = env.x87.unused3; - memcpy(__fe_dfl_env.x87.others, - env.x87.others, - sizeof(__fe_dfl_env.x87.others) / sizeof(uint32_t)); - - __fnstsw(&status); + /* Store the MXCSR register */ if (__HAS_SSE) - __stmxcsr(&mxcsr); - else - mxcsr = 0; + __asm__ __volatile__ ("stmxcsr %0" : "=m" (mxcsr)); + + /* Install new floating-point environment */ fesetenv(envp); - feraiseexcept((mxcsr | status) & FE_ALL_EXCEPT); - /* Success */ + /* Raise any previously accumulated exceptions */ + feraiseexcept(status | mxcsr); + return (0); } @@ -458,61 +397,61 @@ feupdateenv(const fenv_t *envp) int feenableexcept(int mask) { - uint32_t mxcsr, omask; - uint16_t control; + unsigned int mxcsr = 0, omask; + unsigned short control; mask &= FE_ALL_EXCEPT; - __fnstcw(&control); + + __asm__ __volatile__ ("fnstcw %0" : "=m" (control)); if (__HAS_SSE) - __stmxcsr(&mxcsr); - else - mxcsr = 0; + __asm__ __volatile__ ("stmxcsr %0" : "=m" (mxcsr)); - omask = (control | mxcsr >> __SSE_EMASK_SHIFT) & FE_ALL_EXCEPT; + omask = ~(control | (mxcsr >> _SSE_MASK_SHIFT)) & FE_ALL_EXCEPT; control &= ~mask; - __fldcw(control); + __asm__ __volatile__ ("fldcw %0" : : "m" (control)); + if (__HAS_SSE) { - mxcsr &= ~(mask << __SSE_EMASK_SHIFT); - __ldmxcsr(mxcsr); + mxcsr &= ~(mask << _SSE_MASK_SHIFT); + __asm__ __volatile__ ("ldmxcsr %0" : : "m" (mxcsr)); } - return (~omask); + return (omask); } int fedisableexcept(int mask) { - uint32_t mxcsr, omask; - uint16_t control; + unsigned int mxcsr = 0, omask; + unsigned short control; mask &= FE_ALL_EXCEPT; - __fnstcw(&control); + + __asm__ __volatile__ ("fnstcw %0" : "=m" (control)); if (__HAS_SSE) - __stmxcsr(&mxcsr); - else - mxcsr = 0; + __asm__ __volatile__ ("stmxcsr %0" : "=m" (mxcsr)); - omask = (control | mxcsr >> __SSE_EMASK_SHIFT) & FE_ALL_EXCEPT; + omask = ~(control | (mxcsr >> _SSE_MASK_SHIFT)) & FE_ALL_EXCEPT; control |= mask; - __fldcw(control); + __asm__ __volatile__ ("fldcw %0" : : "m" (control)); + if (__HAS_SSE) { - mxcsr |= mask << __SSE_EMASK_SHIFT; - __ldmxcsr(mxcsr); + mxcsr |= mask << _SSE_MASK_SHIFT; + __asm__ __volatile__ ("ldmxcsr %0" : : "m" (mxcsr)); } - return (~omask); + return (omask); } int fegetexcept(void) { - uint16_t control; + unsigned short control; /* * We assume that the masks for the x87 and the SSE unit are * the same. */ - __fnstcw(&control); + __asm__ __volatile__ ("fnstcw %0" : "=m" (control)); - return (control & FE_ALL_EXCEPT); + return (~control & FE_ALL_EXCEPT); } |