diff options
Diffstat (limited to 'sysdeps/i386')
-rw-r--r-- | sysdeps/i386/fpu/fegetenv.c | 6 | ||||
-rw-r--r-- | sysdeps/i386/fpu/feholdexcpt.c | 4 | ||||
-rw-r--r-- | sysdeps/i386/fpu/fesetenv.c | 50 |
3 files changed, 43 insertions, 17 deletions
diff --git a/sysdeps/i386/fpu/fegetenv.c b/sysdeps/i386/fpu/fegetenv.c index 8dbdb5787a..8c45b6b8cb 100644 --- a/sysdeps/i386/fpu/fegetenv.c +++ b/sysdeps/i386/fpu/fegetenv.c @@ -18,6 +18,9 @@ <http://www.gnu.org/licenses/>. */ #include <fenv.h> +#include <unistd.h> +#include <ldsodefs.h> +#include <dl-procinfo.h> int __fegetenv (fenv_t *envp) @@ -28,6 +31,9 @@ __fegetenv (fenv_t *envp) would block all exceptions. */ __asm__ ("fldenv %0" : : "m" (*envp)); + if ((GLRO(dl_hwcap) & HWCAP_I386_XMM) != 0) + __asm__ ("stmxcsr %0" : "=m" (envp->__eip)); + /* Success. */ return 0; } diff --git a/sysdeps/i386/fpu/feholdexcpt.c b/sysdeps/i386/fpu/feholdexcpt.c index d475ca850c..dc9d7031ca 100644 --- a/sysdeps/i386/fpu/feholdexcpt.c +++ b/sysdeps/i386/fpu/feholdexcpt.c @@ -35,10 +35,10 @@ feholdexcept (fenv_t *envp) unsigned int xwork; /* Get the current control word. */ - __asm__ ("stmxcsr %0" : "=m" (*&xwork)); + __asm__ ("stmxcsr %0" : "=m" (envp->__eip)); /* Set all exceptions to non-stop and clear them. */ - xwork = (xwork | 0x1f80) & ~0x3f; + xwork = (envp->__eip | 0x1f80) & ~0x3f; __asm__ ("ldmxcsr %0" : : "m" (*&xwork)); } diff --git a/sysdeps/i386/fpu/fesetenv.c b/sysdeps/i386/fpu/fesetenv.c index 95b2f0a1ab..2a84657030 100644 --- a/sysdeps/i386/fpu/fesetenv.c +++ b/sysdeps/i386/fpu/fesetenv.c @@ -19,6 +19,9 @@ #include <fenv.h> #include <assert.h> +#include <unistd.h> +#include <ldsodefs.h> +#include <dl-procinfo.h> int @@ -40,21 +43,11 @@ __fesetenv (const fenv_t *envp) temp.__control_word |= FE_ALL_EXCEPT; temp.__control_word &= ~FE_TOWARDZERO; temp.__status_word &= ~FE_ALL_EXCEPT; - temp.__eip = 0; - temp.__cs_selector = 0; - temp.__opcode = 0; - temp.__data_offset = 0; - temp.__data_selector = 0; } else if (envp == FE_NOMASK_ENV) { temp.__control_word &= ~(FE_ALL_EXCEPT | FE_TOWARDZERO); temp.__status_word &= ~FE_ALL_EXCEPT; - temp.__eip = 0; - temp.__cs_selector = 0; - temp.__opcode = 0; - temp.__data_offset = 0; - temp.__data_selector = 0; } else { @@ -63,15 +56,42 @@ __fesetenv (const fenv_t *envp) & (FE_ALL_EXCEPT | FE_TOWARDZERO)); temp.__status_word &= ~FE_ALL_EXCEPT; temp.__status_word |= envp->__status_word & FE_ALL_EXCEPT; - temp.__eip = envp->__eip; - temp.__cs_selector = envp->__cs_selector; - temp.__opcode = envp->__opcode; - temp.__data_offset = envp->__data_offset; - temp.__data_selector = envp->__data_selector; } + temp.__eip = 0; + temp.__cs_selector = 0; + temp.__opcode = 0; + temp.__data_offset = 0; + temp.__data_selector = 0; __asm__ ("fldenv %0" : : "m" (temp)); + if ((GLRO(dl_hwcap) & HWCAP_I386_XMM) != 0) + { + unsigned int mxcsr; + __asm__ ("stmxcsr %0" : "=m" (mxcsr)); + + if (envp == FE_DFL_ENV) + { + /* Set mask for SSE MXCSR. */ + mxcsr |= (FE_ALL_EXCEPT << 7); + /* Set rounding to FE_TONEAREST. */ + mxcsr &= ~0x6000; + mxcsr |= (FE_TONEAREST << 3); + } + else if (envp == FE_NOMASK_ENV) + { + /* Do not mask exceptions. */ + mxcsr &= ~(FE_ALL_EXCEPT << 7); + /* Set rounding to FE_TONEAREST. */ + mxcsr &= ~0x6000; + mxcsr |= (FE_TONEAREST << 3); + } + else + mxcsr = envp->__eip; + + __asm__ ("ldmxcsr %0" : : "m" (mxcsr)); + } + /* Success. */ return 0; } |