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/fpu.h> 31 32 #include "fenv.h" 33 34 const fenv_t __fe_dfl_env = { 35 { 0xffff0000 | __INITIAL_FPUCW__, 36 0xffff0000, 37 0xffffffff, 38 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 39 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff } 40 }, 41 __INITIAL_MXCSR__ 42 }; 43 44 const femode_t __fe_dfl_mode = { 45 .__control = __INITIAL_FPUCW__, 46 .__reserved = 0, 47 .__mxcsr = __INITIAL_MXCSR__ 48 }; 49 50 int 51 (feclearexcept)(int excepts) 52 { 53 return (__feclearexcept_int(excepts)); 54 } 55 56 int 57 (fegetexceptflag)(fexcept_t *flagp, int excepts) 58 { 59 return (__fegetexceptflag_int(flagp, excepts)); 60 } 61 62 int 63 fesetexceptflag(const fexcept_t *flagp, int excepts) 64 { 65 fenv_t env; 66 67 __fnstenv(&env.__x87); 68 env.__x87.__status &= ~excepts; 69 env.__x87.__status |= *flagp & excepts; 70 __fldenv(&env.__x87); 71 72 __stmxcsr(&env.__mxcsr); 73 env.__mxcsr &= ~excepts; 74 env.__mxcsr |= *flagp & excepts; 75 __ldmxcsr(&env.__mxcsr); 76 77 return (0); 78 } 79 80 int 81 feraiseexcept(int excepts) 82 { 83 fexcept_t ex = excepts; 84 85 fesetexceptflag(&ex, excepts); 86 __fwait(); 87 return (0); 88 } 89 90 int 91 (fetestexcept)(int excepts) 92 { 93 return (__fetestexcept_int(excepts)); 94 } 95 96 int 97 (fegetround)(void) 98 { 99 return (__fegetround_int()); 100 } 101 102 int 103 (fesetround)(int round) 104 { 105 return (__fesetround_int(round)); 106 } 107 108 int 109 (fegetmode)(femode_t *modep) 110 { 111 return (__fegetmode_int(modep)); 112 } 113 114 int 115 (fesetmode)(const femode_t *modep) 116 { 117 return (__fesetmode_int(modep)); 118 } 119 120 int 121 fegetenv(fenv_t *envp) 122 { 123 124 __fnstenv(&envp->__x87); 125 __stmxcsr(&envp->__mxcsr); 126 /* 127 * fnstenv masks all exceptions, so we need to restore the 128 * control word to avoid this side effect. 129 */ 130 __fldcw(&envp->__x87.__control); 131 return (0); 132 } 133 134 int 135 feholdexcept(fenv_t *envp) 136 { 137 __uint32_t mxcsr; 138 139 __stmxcsr(&mxcsr); 140 __fnstenv(&envp->__x87); 141 __fnclex(); 142 envp->__mxcsr = mxcsr; 143 mxcsr &= ~FE_ALL_EXCEPT; 144 mxcsr |= FE_ALL_EXCEPT << _SSE_EMASK_SHIFT; 145 __ldmxcsr(&mxcsr); 146 return (0); 147 } 148 149 int 150 (fesetenv)(const fenv_t *envp) 151 { 152 return (__fesetenv_int(envp)); 153 } 154 155 int 156 feupdateenv(const fenv_t *envp) 157 { 158 __uint32_t mxcsr; 159 __uint16_t status; 160 161 __fnstsw(&status); 162 __stmxcsr(&mxcsr); 163 fesetenv(envp); 164 feraiseexcept((mxcsr | status) & FE_ALL_EXCEPT); 165 return (0); 166 } 167 168 int 169 __feenableexcept(int mask) 170 { 171 __uint32_t mxcsr, omask; 172 __uint16_t control; 173 174 mask &= FE_ALL_EXCEPT; 175 __fnstcw(&control); 176 __stmxcsr(&mxcsr); 177 omask = ~(control | mxcsr >> _SSE_EMASK_SHIFT) & FE_ALL_EXCEPT; 178 control &= ~mask; 179 __fldcw(&control); 180 mxcsr &= ~(mask << _SSE_EMASK_SHIFT); 181 __ldmxcsr(&mxcsr); 182 return (omask); 183 } 184 185 int 186 __fedisableexcept(int mask) 187 { 188 __uint32_t mxcsr, omask; 189 __uint16_t control; 190 191 mask &= FE_ALL_EXCEPT; 192 __fnstcw(&control); 193 __stmxcsr(&mxcsr); 194 omask = ~(control | mxcsr >> _SSE_EMASK_SHIFT) & FE_ALL_EXCEPT; 195 control |= mask; 196 __fldcw(&control); 197 mxcsr |= mask << _SSE_EMASK_SHIFT; 198 __ldmxcsr(&mxcsr); 199 return (omask); 200 } 201 202 __weak_reference(__feenableexcept, feenableexcept); 203 __weak_reference(__fedisableexcept, fedisableexcept); 204