From f34428eb356a001928e1786d51cbfe216ebeef83 Mon Sep 17 00:00:00 2001 From: Danny Smith Date: Mon, 3 Jul 2006 10:32:58 +0000 Subject: Support SSE float environment in fenv.h functions. * cpu_features.c: New file. * cpu_features.h: New file. * crt1.c: Include "cpu_features.h". (__mingw_CRTStartup): Call cpu_features_init(). * Makefile.in (MING_OBJS): Add cpu_features.c. (SRCDIST_FILES): Add cpu_features.c, cpu_features.h. * include/fenv,h ( fenv_t;): Append __mxcsr field. (__MXCSR_EXCEPT_FLAG_SHIFT): New define. (__MXCSR_EXCEPT_MASK_SHIFT): New define. (__MXCSR_ROUND_FLAG_SHIFT): New define. * mingwex/feclearexcept.c: Include "cpu_features.h". Handle SSE environment. * mingwex/fegetenv.c: Likewise. * mingwex/feholdexcept.c: Likewise. * mingwex/fesetenv.c: Likewise. * mingwex/fesetexceptflag.c: Likewise. * mingwex/fesetround.c: Likewise. * mingwex/fetestexcept.c: Likewise. * mingwex/feupdateenv.c: Likewise. * mingwex/fegetround.c: Add comment. --- winsup/mingw/mingwex/feclearexcept.c | 11 ++++++++++- winsup/mingw/mingwex/fegetenv.c | 6 ++++++ winsup/mingw/mingwex/fegetround.c | 5 +++++ winsup/mingw/mingwex/feholdexcept.c | 14 ++++++++++++++ winsup/mingw/mingwex/fesetenv.c | 18 ++++++++++++++++-- winsup/mingw/mingwex/fesetexceptflag.c | 11 +++++++++++ winsup/mingw/mingwex/fesetround.c | 11 +++++++++++ winsup/mingw/mingwex/fetestexcept.c | 20 ++++++++++++++++---- winsup/mingw/mingwex/feupdateenv.c | 14 ++++++++++---- 9 files changed, 99 insertions(+), 11 deletions(-) (limited to 'winsup/mingw/mingwex') diff --git a/winsup/mingw/mingwex/feclearexcept.c b/winsup/mingw/mingwex/feclearexcept.c index 8c943893b..a68884f41 100644 --- a/winsup/mingw/mingwex/feclearexcept.c +++ b/winsup/mingw/mingwex/feclearexcept.c @@ -1,4 +1,5 @@ #include +#include "cpu_features.h" /* 7.6.2.1 The feclearexcept function clears the supported exceptions @@ -7,9 +8,17 @@ int feclearexcept (int excepts) { fenv_t _env; + excepts &= FE_ALL_EXCEPT; __asm__ volatile ("fnstenv %0;" : "=m" (_env)); /* get the env */ - _env.__status_word &= ~(excepts & FE_ALL_EXCEPT); /* clear the except */ + _env.__status_word &= ~excepts; /* clear the except */ __asm__ volatile ("fldenv %0;" :: "m" (_env)); /*set the env */ + if (__HAS_SSE) + { + unsigned _csr; + __asm__ volatile("stmxcsr %0" : "=m" (_csr)); /* get the register */ + _csr &= ~excepts; /* clear the except */ + __asm__ volatile("ldmxcsr %0" : : "m" (_csr)); /* set the register */ + } return 0; } diff --git a/winsup/mingw/mingwex/fegetenv.c b/winsup/mingw/mingwex/fegetenv.c index 930105673..0c5d591e7 100644 --- a/winsup/mingw/mingwex/fegetenv.c +++ b/winsup/mingw/mingwex/fegetenv.c @@ -1,4 +1,5 @@ #include +#include "cpu_features.h" /* 7.6.4.1 The fegetenv function stores the current floating-point environment @@ -10,5 +11,10 @@ int fegetenv (fenv_t * envp) /* fnstenv sets control word to non-stop for all exceptions, so we need to reload our env to restore the original mask. */ __asm__ ("fldenv %0" : : "m" (*envp)); + + /* And the SSE environment. */ + if (__HAS_SSE) + __asm__ ("stmxcsr %0" : "=m" (envp->__mxcsr)); + return 0; } diff --git a/winsup/mingw/mingwex/fegetround.c b/winsup/mingw/mingwex/fegetround.c index 076b1068c..01d42849f 100644 --- a/winsup/mingw/mingwex/fegetround.c +++ b/winsup/mingw/mingwex/fegetround.c @@ -1,4 +1,5 @@ #include +#include "cpu_features.h" /* 7.6.3.1 The fegetround function returns the value of the rounding direction @@ -9,6 +10,10 @@ fegetround (void) { unsigned short _cw; __asm__ ("fnstcw %0;" : "=m" (_cw)); + + /* If the MXCSR flag is different, there is no way to indicate, so just + report the FPU flag. */ return _cw & (FE_TONEAREST | FE_DOWNWARD | FE_UPWARD | FE_TOWARDZERO); + } diff --git a/winsup/mingw/mingwex/feholdexcept.c b/winsup/mingw/mingwex/feholdexcept.c index 8d4a3f67b..66912d85d 100644 --- a/winsup/mingw/mingwex/feholdexcept.c +++ b/winsup/mingw/mingwex/feholdexcept.c @@ -1,4 +1,5 @@ #include +#include "cpu_features.h" /* 7.6.4.2 The feholdexcept function saves the current floating-point @@ -12,5 +13,18 @@ int feholdexcept (fenv_t * envp) /* fnstenv sets control word to non-stop for all exceptions, so all we need to do is clear the exception flags. */ __asm__ ("fnclex"); + + if (__HAS_SSE) + { + unsigned int _csr; + /* Save the SSE MXCSR register. */ + __asm__ ("stmxcsr %0" : "=m" (envp->__mxcsr)); + /* Clear the exception flags. */ + _csr = envp->__mxcsr & ~FE_ALL_EXCEPT; + /* Set exception mask to non-stop */ + _csr |= (FE_ALL_EXCEPT << __MXCSR_EXCEPT_MASK_SHIFT) /*= 0x1f80 */; + __asm__ volatile ("ldmxcsr %0" : : "m" (_csr)); + } + return 0; } diff --git a/winsup/mingw/mingwex/fesetenv.c b/winsup/mingw/mingwex/fesetenv.c index 3d7b5604a..105a0af10 100644 --- a/winsup/mingw/mingwex/fesetenv.c +++ b/winsup/mingw/mingwex/fesetenv.c @@ -1,5 +1,6 @@ #include #include +#include "cpu_features.h" /* 7.6.4.3 The fesetenv function establishes the floating-point environment @@ -15,6 +16,11 @@ extern void (*_imp___fpreset)( void ) ; int fesetenv (const fenv_t * envp) { + /* Default mxcsr status is to mask all exceptions. All other bits + are zero. */ + + unsigned int _csr = FE_ALL_EXCEPT << __MXCSR_EXCEPT_MASK_SHIFT /*= 0x1f80 */; + if (envp == FE_PC64_ENV) /* * fninit initializes the control register to 0x37f, @@ -37,7 +43,15 @@ int fesetenv (const fenv_t * envp) _fpreset(); else - __asm__ ("fldenv %0;" : : "m" (*envp)); - + { + __asm__ ("fldenv %0;" : : "m" (*envp)); + /* Setting the reserved high order bits of MXCSR causes a segfault */ + _csr = envp ->__mxcsr & 0xffff; + } + + /* Set MXCSR */ + if (__HAS_SSE) + __asm__ volatile ("ldmxcsr %0" : : "m" (_csr)); + return 0; } diff --git a/winsup/mingw/mingwex/fesetexceptflag.c b/winsup/mingw/mingwex/fesetexceptflag.c index 7f4b8e562..876174b69 100644 --- a/winsup/mingw/mingwex/fesetexceptflag.c +++ b/winsup/mingw/mingwex/fesetexceptflag.c @@ -1,4 +1,5 @@ #include +#include "cpu_features.h" /* 7.6.2.4 The fesetexceptflag function sets the complete status for those @@ -18,5 +19,15 @@ int fesetexceptflag (const fexcept_t * flagp, int excepts) _env.__status_word &= ~excepts; _env.__status_word |= (*flagp & excepts); __asm__ volatile ("fldenv %0;" : : "m" (_env)); + + if (__HAS_SSE) + { + unsigned int _csr; + __asm__ __volatile__("stmxcsr %0" : "=m" (_csr)); + _csr &= ~excepts; + _csr |= *flagp & excepts; + __asm__ volatile ("ldmxcsr %0" : : "m" (_csr)); + } + return 0; } diff --git a/winsup/mingw/mingwex/fesetround.c b/winsup/mingw/mingwex/fesetround.c index a8cef86a4..e90dbb4e7 100644 --- a/winsup/mingw/mingwex/fesetround.c +++ b/winsup/mingw/mingwex/fesetround.c @@ -1,4 +1,6 @@ #include +#include "cpu_features.h" + /* 7.6.3.2 The fesetround function establishes the rounding direction represented by its argument round. If the argument is not equal @@ -15,5 +17,14 @@ int fesetround (int mode) _cw &= ~(FE_TONEAREST | FE_DOWNWARD | FE_UPWARD | FE_TOWARDZERO); _cw |= mode; __asm__ volatile ("fldcw %0;" : : "m" (_cw)); + + if (__HAS_SSE) + { + __asm__ volatile ("stmxcsr %0" : "=m" (_cw)); + _cw &= ~ 0x6000; + _cw |= (mode << __MXCSR_ROUND_FLAG_SHIFT); + __asm__ volatile ("ldmxcsr %0" : : "m" (_cw)); + } + return 0; } diff --git a/winsup/mingw/mingwex/fetestexcept.c b/winsup/mingw/mingwex/fetestexcept.c index 6934ed925..062d585eb 100644 --- a/winsup/mingw/mingwex/fetestexcept.c +++ b/winsup/mingw/mingwex/fetestexcept.c @@ -1,4 +1,5 @@ -#include +#include +#include "cpu_features.h" /* 7.6.2.5 The fetestexcept function determines which of a specified subset of the exception flags are currently set. The excepts argument @@ -9,7 +10,18 @@ int fetestexcept (int excepts) { - unsigned short _sw; - __asm__ ("fnstsw %%ax" : "=a" (_sw)); - return _sw & excepts & FE_ALL_EXCEPT; + + unsigned int _res; + __asm__ ("fnstsw %%ax" : "=a" (_res)); + + + /* If SSE supported, return the union of the FPU and SSE flags. */ + if (__HAS_SSE) + { + unsigned int _csr; + __asm__ volatile("stmxcsr %0" : "=m" (_csr)); + _res |= _csr; + } + + return (_res & excepts & FE_ALL_EXCEPT); } diff --git a/winsup/mingw/mingwex/feupdateenv.c b/winsup/mingw/mingwex/feupdateenv.c index f414837f5..e37566b02 100644 --- a/winsup/mingw/mingwex/feupdateenv.c +++ b/winsup/mingw/mingwex/feupdateenv.c @@ -1,4 +1,5 @@ #include +#include "cpu_features.h" /* 7.6.4.4 The feupdateenv function saves the currently raised exceptions in @@ -8,13 +9,18 @@ set by a call to feholdexcept or fegetenv, or equal the macro FE_DFL_ENV or an implementation-defined environment macro. */ -/* FIXME: this works but surely there must be a better way. */ int feupdateenv (const fenv_t * envp) { - unsigned int _fexcept = fetestexcept (FE_ALL_EXCEPT); /*save excepts */ + unsigned int _fexcept; + __asm__ ("fnstsw %%ax" : "=a" (_fexcept)); /*save excepts */ + if (__HAS_SSE) + { + unsigned int _csr; + __asm__ ("stmxcsr %0" : "=m" (_csr)); + _fexcept |= _csr; + } fesetenv (envp); /* install the env */ - feraiseexcept (_fexcept); /* raise the execept */ + feraiseexcept (_fexcept & FE_ALL_EXCEPT); /* raise the execeptions */ return 0; } - -- cgit v1.2.3