From patchwork Fri May 9 16:45:31 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Joseph Myers X-Patchwork-Id: 347475 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 85CD8140079 for ; Sat, 10 May 2014 02:45:46 +1000 (EST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:date:from:to:cc:subject:in-reply-to:message-id :references:mime-version:content-type; q=dns; s=default; b=Jxzrh zZoy1veif9yU7drwtdM09QXghA080KiiowN8ID+jgoiwULjBuXy92/nRzI+vImd7 2feuLcVIUFw5ERMf7mPTibpf123gDbhrK8qRC7WAeoqPGykgFW/6jjGYlalXTCK4 cg6cbkimPLILEFYqBL/wHK5MKbIr0Ss69she10= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:date:from:to:cc:subject:in-reply-to:message-id :references:mime-version:content-type; s=default; bh=nhZOm1eADfM 0gpCmIRqZlrWVPd4=; b=S5GQB96MMWsET5ol2DwMJVfAOmx64/lBEcOOK05xSx3 BYYPz7rJoI8bd2yD9vyq5pCTl1PXr7hIpoC5l2gkFHSODLhr2f9jzY9hWohLJm9/ f0ViKNCEhbMj+d/fzFmLRUS04GW6N12zGAl+3td+cNszdl+bNdZaP1DRBlL6I82U = Received: (qmail 28895 invoked by alias); 9 May 2014 16:45:41 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Delivered-To: mailing list libc-alpha@sourceware.org Received: (qmail 28883 invoked by uid 89); 9 May 2014 16:45:40 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-0.6 required=5.0 tests=AWL, BAYES_50 autolearn=ham version=3.3.2 X-HELO: relay1.mentorg.com Date: Fri, 9 May 2014 16:45:31 +0000 From: "Joseph S. Myers" To: "H.J. Lu" CC: GNU C Library Subject: Re: Include SSE state in i386 fenv_t (bug 16064) In-Reply-To: Message-ID: References: MIME-Version: 1.0 On Fri, 9 May 2014, H.J. Lu wrote: > When loading load x87 fenv_t, we should either not to > change __eip or set it to 0 together with other fields, > similar to other code paths in __fesetenv, to avoid any > potential issues. This patch sets all those fields to 0 unconditionally. 2014-05-09 Joseph Myers [BZ #16064] * sysdeps/i386/fpu/fegetenv.c: Include , and . (__fegetenv): Save SSE state in envp->__eip if supported. * sysdeps/i386/fpu/feholdexcpt.c (feholdexcept): Save SSE state in envp->__eip if supported. * sysdeps/i386/fpu/fesetenv.c: Include , and . (__fesetenv): Always set __eip, __cs_selector, __opcode, __data_offset and __data_selector in environment to 0. Set SSE state if supported. * sysdeps/x86/fpu/Makefile [$(subdir) = math] (tests): Add test-fenv-sse. [$(subdir) = math] (CFLAGS-test-fenv-sse.c): Add -msse2 -mfpmath=sse. * sysdeps/x86/fpu/test-fenv-sse.c: New file. diff --git a/sysdeps/i386/fpu/fegetenv.c b/sysdeps/i386/fpu/fegetenv.c index 8dbdb57..8c45b6b 100644 --- a/sysdeps/i386/fpu/fegetenv.c +++ b/sysdeps/i386/fpu/fegetenv.c @@ -18,6 +18,9 @@ . */ #include +#include +#include +#include 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 d475ca8..dc9d703 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 95b2f0a..2a84657 100644 --- a/sysdeps/i386/fpu/fesetenv.c +++ b/sysdeps/i386/fpu/fesetenv.c @@ -19,6 +19,9 @@ #include #include +#include +#include +#include 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; } diff --git a/sysdeps/x86/fpu/Makefile b/sysdeps/x86/fpu/Makefile index 8054380..9cb7bb2 100644 --- a/sysdeps/x86/fpu/Makefile +++ b/sysdeps/x86/fpu/Makefile @@ -1,3 +1,5 @@ ifeq ($(subdir),math) libm-support += powl_helper +tests += test-fenv-sse +CFLAGS-test-fenv-sse.c += -msse2 -mfpmath=sse endif diff --git a/sysdeps/x86/fpu/test-fenv-sse.c b/sysdeps/x86/fpu/test-fenv-sse.c new file mode 100644 index 0000000..c81eb16 --- /dev/null +++ b/sysdeps/x86/fpu/test-fenv-sse.c @@ -0,0 +1,138 @@ +/* Test floating-point environment includes SSE state (bug 16064). + Copyright (C) 2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include +#include + +static bool +have_sse2 (void) +{ + unsigned int eax, ebx, ecx, edx; + + if (!__get_cpuid (1, &eax, &ebx, &ecx, &edx)) + return false; + + return (edx & bit_SSE2) != 0; +} + +static __attribute__ ((noinline)) int +sse_tests (void) +{ + int ret = 0; + fenv_t base_env; + if (fegetenv (&base_env) != 0) + { + puts ("fegetenv (&base_env) failed"); + return 1; + } + if (fesetround (FE_UPWARD) != 0) + { + puts ("fesetround (FE_UPWARD) failed"); + return 1; + } + if (fesetenv (&base_env) != 0) + { + puts ("fesetenv (&base_env) failed"); + return 1; + } + volatile float a = 1.0f, b = FLT_MIN, c; + c = a + b; + if (c != 1.0f) + { + puts ("fesetenv did not restore rounding mode"); + ret = 1; + } + if (fesetround (FE_DOWNWARD) != 0) + { + puts ("fesetround (FE_DOWNWARD) failed"); + return 1; + } + if (feupdateenv (&base_env) != 0) + { + puts ("feupdateenv (&base_env) failed"); + return 1; + } + volatile float d = -FLT_MIN, e; + e = a + d; + if (e != 1.0f) + { + puts ("feupdateenv did not restore rounding mode"); + ret = 1; + } + if (fesetround (FE_UPWARD) != 0) + { + puts ("fesetround (FE_UPWARD) failed"); + return 1; + } + fenv_t upward_env; + if (feholdexcept (&upward_env) != 0) + { + puts ("feholdexcept (&upward_env) failed"); + return 1; + } + if (fesetround (FE_DOWNWARD) != 0) + { + puts ("fesetround (FE_DOWNWARD) failed"); + return 1; + } + if (fesetenv (&upward_env) != 0) + { + puts ("fesetenv (&upward_env) failed"); + return 1; + } + e = a + d; + if (e != 1.0f) + { + puts ("fesetenv did not restore rounding mode from feholdexcept"); + ret = 1; + } + if (fesetround (FE_UPWARD) != 0) + { + puts ("fesetround (FE_UPWARD) failed"); + return 1; + } + if (fesetenv (FE_DFL_ENV) != 0) + { + puts ("fesetenv (FE_DFL_ENV) failed"); + return 1; + } + c = a + b; + if (c != 1.0f) + { + puts ("fesetenv (FE_DFL_ENV) did not restore rounding mode"); + ret = 1; + } + return ret; +} + +static int +do_test (void) +{ + if (!have_sse2 ()) + { + puts ("CPU does not support SSE2, cannot test"); + return 0; + } + return sse_tests (); +} + +#define TEST_FUNCTION do_test () +#include