10b71a226SDavid Schultz /*- 29233b45aSDavid Schultz * Copyright (c) 2004-2005 David Schultz <das@FreeBSD.ORG> 30b71a226SDavid Schultz * All rights reserved. 40b71a226SDavid Schultz * 50b71a226SDavid Schultz * Redistribution and use in source and binary forms, with or without 60b71a226SDavid Schultz * modification, are permitted provided that the following conditions 70b71a226SDavid Schultz * are met: 80b71a226SDavid Schultz * 1. Redistributions of source code must retain the above copyright 90b71a226SDavid Schultz * notice, this list of conditions and the following disclaimer. 100b71a226SDavid Schultz * 2. Redistributions in binary form must reproduce the above copyright 110b71a226SDavid Schultz * notice, this list of conditions and the following disclaimer in the 120b71a226SDavid Schultz * documentation and/or other materials provided with the distribution. 130b71a226SDavid Schultz * 140b71a226SDavid Schultz * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 150b71a226SDavid Schultz * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 160b71a226SDavid Schultz * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 170b71a226SDavid Schultz * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 180b71a226SDavid Schultz * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 190b71a226SDavid Schultz * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 200b71a226SDavid Schultz * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 210b71a226SDavid Schultz * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 220b71a226SDavid Schultz * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 230b71a226SDavid Schultz * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 240b71a226SDavid Schultz * SUCH DAMAGE. 250b71a226SDavid Schultz * 260b71a226SDavid Schultz * $FreeBSD$ 270b71a226SDavid Schultz */ 280b71a226SDavid Schultz 299233b45aSDavid Schultz #include <sys/cdefs.h> 300b71a226SDavid Schultz #include <sys/types.h> 310b71a226SDavid Schultz #include <machine/npx.h> 329233b45aSDavid Schultz #include "fenv.h" 330b71a226SDavid Schultz 340b71a226SDavid Schultz const fenv_t __fe_dfl_env = { 359233b45aSDavid Schultz __INITIAL_NPXCW__, 369233b45aSDavid Schultz 0x0000, 379233b45aSDavid Schultz 0x0000, 389233b45aSDavid Schultz 0x1f80, 390b71a226SDavid Schultz 0xffffffff, 400b71a226SDavid Schultz { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 410b71a226SDavid Schultz 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff } 420b71a226SDavid Schultz }; 439233b45aSDavid Schultz 449233b45aSDavid Schultz enum __sse_support __has_sse = 459233b45aSDavid Schultz #ifdef __SSE__ 469233b45aSDavid Schultz __SSE_YES; 479233b45aSDavid Schultz #else 489233b45aSDavid Schultz __SSE_UNK; 499233b45aSDavid Schultz #endif 509233b45aSDavid Schultz 519233b45aSDavid Schultz #define getfl(x) __asm __volatile("pushfl\n\tpopl %0" : "=mr" (*(x))) 529233b45aSDavid Schultz #define setfl(x) __asm __volatile("pushl %0\n\tpopfl" : : "g" (x)) 539233b45aSDavid Schultz #define cpuid_dx(x) __asm __volatile("pushl %%ebx\n\tmovl $1, %%eax\n\t" \ 549233b45aSDavid Schultz "cpuid\n\tpopl %%ebx" \ 559233b45aSDavid Schultz : "=d" (*(x)) : : "eax", "ecx") 569233b45aSDavid Schultz 579233b45aSDavid Schultz /* 589233b45aSDavid Schultz * Test for SSE support on this processor. We need to do this because 599233b45aSDavid Schultz * we need to use ldmxcsr/stmxcsr to get correct results if any part 609233b45aSDavid Schultz * of the program was compiled to use SSE floating-point, but we can't 619233b45aSDavid Schultz * use SSE on older processors. 629233b45aSDavid Schultz */ 639233b45aSDavid Schultz int 649233b45aSDavid Schultz __test_sse(void) 659233b45aSDavid Schultz { 669233b45aSDavid Schultz int flag, nflag; 679233b45aSDavid Schultz int dx_features; 689233b45aSDavid Schultz 699233b45aSDavid Schultz /* Am I a 486? */ 709233b45aSDavid Schultz getfl(&flag); 719233b45aSDavid Schultz nflag = flag ^ 0x200000; 729233b45aSDavid Schultz setfl(nflag); 739233b45aSDavid Schultz getfl(&nflag); 749233b45aSDavid Schultz if (flag != nflag) { 759233b45aSDavid Schultz /* Not a 486, so CPUID should work. */ 769233b45aSDavid Schultz cpuid_dx(&dx_features); 779233b45aSDavid Schultz if (dx_features & 0x2000000) { 789233b45aSDavid Schultz __has_sse = __SSE_YES; 799233b45aSDavid Schultz return (1); 809233b45aSDavid Schultz } 819233b45aSDavid Schultz } 829233b45aSDavid Schultz __has_sse = __SSE_NO; 839233b45aSDavid Schultz return (0); 849233b45aSDavid Schultz } 859233b45aSDavid Schultz 869233b45aSDavid Schultz int 879233b45aSDavid Schultz fesetexceptflag(const fexcept_t *flagp, int excepts) 889233b45aSDavid Schultz { 899233b45aSDavid Schultz fenv_t env; 909233b45aSDavid Schultz int mxcsr; 919233b45aSDavid Schultz 929233b45aSDavid Schultz __fnstenv(&env); 939233b45aSDavid Schultz env.__status &= ~excepts; 949233b45aSDavid Schultz env.__status |= *flagp & excepts; 959233b45aSDavid Schultz __fldenv(env); 969233b45aSDavid Schultz 979233b45aSDavid Schultz if (__HAS_SSE()) { 989233b45aSDavid Schultz __stmxcsr(&mxcsr); 999233b45aSDavid Schultz mxcsr &= ~excepts; 1009233b45aSDavid Schultz mxcsr |= *flagp & excepts; 1019233b45aSDavid Schultz __ldmxcsr(mxcsr); 1029233b45aSDavid Schultz } 1039233b45aSDavid Schultz 1049233b45aSDavid Schultz return (0); 1059233b45aSDavid Schultz } 1069233b45aSDavid Schultz 1079233b45aSDavid Schultz int 1089233b45aSDavid Schultz feraiseexcept(int excepts) 1099233b45aSDavid Schultz { 1109233b45aSDavid Schultz fexcept_t ex = excepts; 1119233b45aSDavid Schultz 1129233b45aSDavid Schultz fesetexceptflag(&ex, excepts); 1139233b45aSDavid Schultz __fwait(); 1149233b45aSDavid Schultz return (0); 1159233b45aSDavid Schultz } 1169233b45aSDavid Schultz 1179233b45aSDavid Schultz int 1189233b45aSDavid Schultz fegetenv(fenv_t *envp) 1199233b45aSDavid Schultz { 1209233b45aSDavid Schultz int control, mxcsr; 1219233b45aSDavid Schultz 1229233b45aSDavid Schultz /* 1239233b45aSDavid Schultz * fnstenv masks all exceptions, so we need to save and 1249233b45aSDavid Schultz * restore the control word to avoid this side effect. 1259233b45aSDavid Schultz */ 1269233b45aSDavid Schultz __fnstcw(&control); 1279233b45aSDavid Schultz __fnstenv(envp); 1289233b45aSDavid Schultz if (__HAS_SSE()) { 1299233b45aSDavid Schultz __stmxcsr(&mxcsr); 1309233b45aSDavid Schultz __set_mxcsr(*envp, mxcsr); 1319233b45aSDavid Schultz } 1329233b45aSDavid Schultz __fldcw(control); 1339233b45aSDavid Schultz return (0); 1349233b45aSDavid Schultz } 1359233b45aSDavid Schultz 1369233b45aSDavid Schultz int 1379233b45aSDavid Schultz feholdexcept(fenv_t *envp) 1389233b45aSDavid Schultz { 1399233b45aSDavid Schultz int mxcsr; 1409233b45aSDavid Schultz 1419233b45aSDavid Schultz __fnstenv(envp); 1429233b45aSDavid Schultz __fnclex(); 1439233b45aSDavid Schultz if (__HAS_SSE()) { 1449233b45aSDavid Schultz __stmxcsr(&mxcsr); 1459233b45aSDavid Schultz __set_mxcsr(*envp, mxcsr); 1469233b45aSDavid Schultz mxcsr &= ~FE_ALL_EXCEPT; 1479233b45aSDavid Schultz mxcsr |= FE_ALL_EXCEPT << _SSE_EMASK_SHIFT; 1489233b45aSDavid Schultz __ldmxcsr(mxcsr); 1499233b45aSDavid Schultz } 1509233b45aSDavid Schultz return (0); 1519233b45aSDavid Schultz } 1529233b45aSDavid Schultz 1539233b45aSDavid Schultz int 1549233b45aSDavid Schultz feupdateenv(const fenv_t *envp) 1559233b45aSDavid Schultz { 1569233b45aSDavid Schultz int mxcsr, status; 1579233b45aSDavid Schultz 1589233b45aSDavid Schultz __fnstsw(&status); 1599233b45aSDavid Schultz if (__HAS_SSE()) 1609233b45aSDavid Schultz __stmxcsr(&mxcsr); 1619233b45aSDavid Schultz else 1629233b45aSDavid Schultz mxcsr = 0; 1639233b45aSDavid Schultz fesetenv(envp); 1649233b45aSDavid Schultz feraiseexcept((mxcsr | status) & FE_ALL_EXCEPT); 1659233b45aSDavid Schultz return (0); 1669233b45aSDavid Schultz } 1679233b45aSDavid Schultz 1689233b45aSDavid Schultz int 1699233b45aSDavid Schultz __feenableexcept(int mask) 1709233b45aSDavid Schultz { 1719233b45aSDavid Schultz int mxcsr, control, omask; 1729233b45aSDavid Schultz 1739233b45aSDavid Schultz mask &= FE_ALL_EXCEPT; 1749233b45aSDavid Schultz __fnstcw(&control); 1759233b45aSDavid Schultz if (__HAS_SSE()) 1769233b45aSDavid Schultz __stmxcsr(&mxcsr); 1779233b45aSDavid Schultz else 1789233b45aSDavid Schultz mxcsr = 0; 1799233b45aSDavid Schultz omask = (control | mxcsr >> _SSE_EMASK_SHIFT) & FE_ALL_EXCEPT; 1809233b45aSDavid Schultz control &= ~mask; 1819233b45aSDavid Schultz __fldcw(control); 1829233b45aSDavid Schultz if (__HAS_SSE()) { 1839233b45aSDavid Schultz mxcsr &= ~(mask << _SSE_EMASK_SHIFT); 1849233b45aSDavid Schultz __ldmxcsr(mxcsr); 1859233b45aSDavid Schultz } 1869233b45aSDavid Schultz return (~omask); 1879233b45aSDavid Schultz } 1889233b45aSDavid Schultz 1899233b45aSDavid Schultz int 1909233b45aSDavid Schultz __fedisableexcept(int mask) 1919233b45aSDavid Schultz { 1929233b45aSDavid Schultz int mxcsr, control, omask; 1939233b45aSDavid Schultz 1949233b45aSDavid Schultz mask &= FE_ALL_EXCEPT; 1959233b45aSDavid Schultz __fnstcw(&control); 1969233b45aSDavid Schultz if (__HAS_SSE()) 1979233b45aSDavid Schultz __stmxcsr(&mxcsr); 1989233b45aSDavid Schultz else 1999233b45aSDavid Schultz mxcsr = 0; 2009233b45aSDavid Schultz omask = (control | mxcsr >> _SSE_EMASK_SHIFT) & FE_ALL_EXCEPT; 2019233b45aSDavid Schultz control |= mask; 2029233b45aSDavid Schultz __fldcw(control); 2039233b45aSDavid Schultz if (__HAS_SSE()) { 2049233b45aSDavid Schultz mxcsr |= mask << _SSE_EMASK_SHIFT; 2059233b45aSDavid Schultz __ldmxcsr(mxcsr); 2069233b45aSDavid Schultz } 2079233b45aSDavid Schultz return (~omask); 2089233b45aSDavid Schultz } 2099233b45aSDavid Schultz 2109233b45aSDavid Schultz __weak_reference(__feenableexcept, feenableexcept); 2119233b45aSDavid Schultz __weak_reference(__fedisableexcept, fedisableexcept); 212