1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2004-2005 David Schultz <das@FreeBSD.ORG> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/types.h> 30 #include <machine/npx.h> 31 32 #include "fenv.h" 33 34 const fenv_t __fe_dfl_env = { 35 __INITIAL_NPXCW__, 36 0x0000, 37 0x0000, 38 0x1f80, 39 0xffffffff, 40 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 41 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff } 42 }; 43 44 const femode_t __fe_dfl_mode = { 45 .__control = __INITIAL_NPXCW__, 46 .__reserved = 0, 47 .__mxcsr = __INITIAL_MXCSR__ 48 }; 49 50 enum __sse_support __has_sse = 51 #ifdef __SSE__ 52 __SSE_YES; 53 #else 54 __SSE_UNK; 55 #endif 56 57 #define getfl(x) __asm __volatile("pushfl\n\tpopl %0" : "=mr" (*(x))) 58 #define setfl(x) __asm __volatile("pushl %0\n\tpopfl" : : "g" (x)) 59 #define cpuid_dx(x) __asm __volatile("pushl %%ebx\n\tmovl $1, %%eax\n\t" \ 60 "cpuid\n\tpopl %%ebx" \ 61 : "=d" (*(x)) : : "eax", "ecx") 62 63 /* 64 * Test for SSE support on this processor. We need to do this because 65 * we need to use ldmxcsr/stmxcsr to get correct results if any part 66 * of the program was compiled to use SSE floating-point, but we can't 67 * use SSE on older processors. 68 */ 69 int 70 __test_sse(void) 71 { 72 int flag, nflag; 73 int dx_features; 74 75 /* Am I a 486? */ 76 getfl(&flag); 77 nflag = flag ^ 0x200000; 78 setfl(nflag); 79 getfl(&nflag); 80 if (flag != nflag) { 81 /* Not a 486, so CPUID should work. */ 82 cpuid_dx(&dx_features); 83 if (dx_features & 0x2000000) { 84 __has_sse = __SSE_YES; 85 return (1); 86 } 87 } 88 __has_sse = __SSE_NO; 89 return (0); 90 } 91 92 int 93 (feclearexcept)(int excepts) 94 { 95 return (__feclearexcept_int(excepts)); 96 } 97 98 int 99 (fegetexceptflag)(fexcept_t *flagp, int excepts) 100 { 101 return (__fegetexceptflag_int(flagp, excepts)); 102 } 103 104 int 105 fesetexceptflag(const fexcept_t *flagp, int excepts) 106 { 107 fenv_t env; 108 __uint32_t mxcsr; 109 110 __fnstenv(&env); 111 env.__status &= ~excepts; 112 env.__status |= *flagp & excepts; 113 __fldenv(&env); 114 115 if (__HAS_SSE()) { 116 __stmxcsr(&mxcsr); 117 mxcsr &= ~excepts; 118 mxcsr |= *flagp & excepts; 119 __ldmxcsr(&mxcsr); 120 } 121 122 return (0); 123 } 124 125 int 126 feraiseexcept(int excepts) 127 { 128 fexcept_t ex = excepts; 129 130 fesetexceptflag(&ex, excepts); 131 __fwait(); 132 return (0); 133 } 134 135 int 136 (fetestexcept)(int excepts) 137 { 138 return (__fetestexcept_int(excepts)); 139 } 140 141 int 142 (fegetround)(void) 143 { 144 return (__fegetround_int()); 145 } 146 147 int 148 (fesetround)(int round) 149 { 150 return (__fesetround_int(round)); 151 } 152 153 int 154 (fegetmode)(femode_t *modep) 155 { 156 return (__fegetmode_int(modep)); 157 } 158 159 int 160 (fesetmode)(const femode_t *modep) 161 { 162 return (__fesetmode_int(modep)); 163 } 164 165 int 166 fegetenv(fenv_t *envp) 167 { 168 __uint32_t mxcsr; 169 170 __fnstenv(envp); 171 /* 172 * fnstenv masks all exceptions, so we need to restore 173 * the old control word to avoid this side effect. 174 */ 175 __fldcw(&envp->__control); 176 if (__HAS_SSE()) { 177 __stmxcsr(&mxcsr); 178 __set_mxcsr(*envp, mxcsr); 179 } 180 return (0); 181 } 182 183 int 184 feholdexcept(fenv_t *envp) 185 { 186 __uint32_t mxcsr; 187 188 __fnstenv(envp); 189 __fnclex(); 190 if (__HAS_SSE()) { 191 __stmxcsr(&mxcsr); 192 __set_mxcsr(*envp, mxcsr); 193 mxcsr &= ~FE_ALL_EXCEPT; 194 mxcsr |= FE_ALL_EXCEPT << _SSE_EMASK_SHIFT; 195 __ldmxcsr(&mxcsr); 196 } 197 return (0); 198 } 199 200 int 201 (fesetenv)(const fenv_t *envp) 202 { 203 return (__fesetenv_int(envp)); 204 } 205 206 int 207 feupdateenv(const fenv_t *envp) 208 { 209 __uint32_t mxcsr; 210 __uint16_t status; 211 212 __fnstsw(&status); 213 if (__HAS_SSE()) 214 __stmxcsr(&mxcsr); 215 else 216 mxcsr = 0; 217 fesetenv(envp); 218 feraiseexcept((mxcsr | status) & FE_ALL_EXCEPT); 219 return (0); 220 } 221 222 int 223 __feenableexcept(int mask) 224 { 225 __uint32_t mxcsr, omask; 226 __uint16_t control; 227 228 mask &= FE_ALL_EXCEPT; 229 __fnstcw(&control); 230 if (__HAS_SSE()) 231 __stmxcsr(&mxcsr); 232 else 233 mxcsr = 0; 234 omask = ~(control | mxcsr >> _SSE_EMASK_SHIFT) & FE_ALL_EXCEPT; 235 control &= ~mask; 236 __fldcw(&control); 237 if (__HAS_SSE()) { 238 mxcsr &= ~(mask << _SSE_EMASK_SHIFT); 239 __ldmxcsr(&mxcsr); 240 } 241 return (omask); 242 } 243 244 int 245 __fedisableexcept(int mask) 246 { 247 __uint32_t mxcsr, omask; 248 __uint16_t control; 249 250 mask &= FE_ALL_EXCEPT; 251 __fnstcw(&control); 252 if (__HAS_SSE()) 253 __stmxcsr(&mxcsr); 254 else 255 mxcsr = 0; 256 omask = ~(control | mxcsr >> _SSE_EMASK_SHIFT) & FE_ALL_EXCEPT; 257 control |= mask; 258 __fldcw(&control); 259 if (__HAS_SSE()) { 260 mxcsr |= mask << _SSE_EMASK_SHIFT; 261 __ldmxcsr(&mxcsr); 262 } 263 return (omask); 264 } 265 266 __weak_reference(__feenableexcept, feenableexcept); 267 __weak_reference(__fedisableexcept, fedisableexcept); 268