1 /* $OpenBSD: fenv.c,v 1.6 2022/12/27 17:10:07 jmc Exp $ */ 2 3 /* 4 * Copyright (c) 2011 Martynas Venckus <martynas@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <fenv.h> 20 21 /* 22 * The following constant represents the default floating-point environment 23 * (that is, the one installed at program startup) and has type pointer to 24 * const-qualified fenv_t. 25 * 26 * It can be used as an argument to the functions within the <fenv.h> header 27 * that manage the floating-point environment, namely fesetenv() and 28 * feupdateenv(). 29 */ 30 fenv_t __fe_dfl_env = 0; 31 32 /* 33 * The feclearexcept() function clears the supported floating-point exceptions 34 * represented by `excepts'. 35 */ 36 int 37 feclearexcept(int excepts) 38 { 39 unsigned int fcsr; 40 41 excepts &= FE_ALL_EXCEPT; 42 43 /* Store the current floating-point control and status register */ 44 __asm__ volatile ("cfc1 %0, $31" : "=r" (fcsr)); 45 46 /* Clear the requested floating-point exceptions */ 47 fcsr &= ~excepts; 48 49 /* Load the floating-point control and status register */ 50 __asm__ volatile ("ctc1 %0, $31" : : "r" (fcsr)); 51 52 return (0); 53 } 54 DEF_STD(feclearexcept); 55 56 /* 57 * The fegetexceptflag() function stores an implementation-defined 58 * representation of the states of the floating-point status flags indicated by 59 * the argument excepts in the object pointed to by the argument flagp. 60 */ 61 int 62 fegetexceptflag(fexcept_t *flagp, int excepts) 63 { 64 unsigned int fcsr; 65 66 excepts &= FE_ALL_EXCEPT; 67 68 /* Store the current floating-point control and status register */ 69 __asm__ volatile ("cfc1 %0, $31" : "=r" (fcsr)); 70 71 /* Store the results in flagp */ 72 *flagp = fcsr & excepts; 73 74 return (0); 75 } 76 77 /* 78 * The feraiseexcept() function raises the supported floating-point exceptions 79 * represented by the argument `excepts'. 80 */ 81 int 82 feraiseexcept(int excepts) 83 { 84 unsigned int fcsr; 85 86 excepts &= FE_ALL_EXCEPT; 87 88 /* Store the current floating-point control and status register */ 89 __asm__ volatile ("cfc1 %0, $31" : "=r" (fcsr)); 90 91 fcsr |= excepts | (excepts << 10); 92 93 /* Load the floating-point control and status register */ 94 __asm__ volatile ("ctc1 %0, $31" : : "r" (fcsr)); 95 96 return (0); 97 } 98 DEF_STD(feraiseexcept); 99 100 /* 101 * This function sets the floating-point status flags indicated by the argument 102 * `excepts' to the states stored in the object pointed to by `flagp'. It does 103 * NOT raise any floating-point exceptions, but only sets the state of the flags. 104 */ 105 int 106 fesetexceptflag(const fexcept_t *flagp, int excepts) 107 { 108 unsigned int fcsr; 109 110 excepts &= FE_ALL_EXCEPT; 111 112 /* Store the current floating-point control and status register */ 113 __asm__ volatile ("cfc1 %0, $31" : "=r" (fcsr)); 114 115 /* Set the requested status flags */ 116 fcsr &= ~excepts; 117 fcsr |= *flagp & excepts; 118 119 /* Load the floating-point control and status register */ 120 __asm__ volatile ("ctc1 %0, $31" : : "r" (fcsr)); 121 122 return (0); 123 } 124 DEF_STD(fesetexceptflag); 125 126 /* 127 * The fetestexcept() function determines which of a specified subset of the 128 * floating-point exception flags are currently set. The `excepts' argument 129 * specifies the floating-point status flags to be queried. 130 */ 131 int 132 fetestexcept(int excepts) 133 { 134 unsigned int fcsr; 135 136 excepts &= FE_ALL_EXCEPT; 137 138 /* Store the current floating-point control and status register */ 139 __asm__ volatile ("cfc1 %0, $31" : "=r" (fcsr)); 140 141 return (fcsr & excepts); 142 } 143 DEF_STD(fetestexcept); 144 145 /* 146 * The fegetround() function gets the current rounding direction. 147 */ 148 int 149 fegetround(void) 150 { 151 unsigned int fcsr; 152 153 /* Store the current floating-point control and status register */ 154 __asm__ volatile ("cfc1 %0, $31" : "=r" (fcsr)); 155 156 return (fcsr & _ROUND_MASK); 157 } 158 DEF_STD(fegetround); 159 160 /* 161 * The fesetround() function establishes the rounding direction represented by 162 * its argument `round'. If the argument is not equal to the value of a rounding 163 * direction macro, the rounding direction is not changed. 164 */ 165 int 166 fesetround(int round) 167 { 168 unsigned int fcsr; 169 170 /* Check whether requested rounding direction is supported */ 171 if (round & ~_ROUND_MASK) 172 return (-1); 173 174 /* Store the current floating-point control and status register */ 175 __asm__ volatile ("cfc1 %0, $31" : "=r" (fcsr)); 176 177 /* Set the rounding direction */ 178 fcsr &= ~_ROUND_MASK; 179 fcsr |= round; 180 181 /* Load the floating-point control and status register */ 182 __asm__ volatile ("ctc1 %0, $31" : : "r" (fcsr)); 183 184 return (0); 185 } 186 DEF_STD(fesetround); 187 188 /* 189 * The fegetenv() function attempts to store the current floating-point 190 * environment in the object pointed to by envp. 191 */ 192 int 193 fegetenv(fenv_t *envp) 194 { 195 /* Store the current floating-point control and status register */ 196 __asm__ volatile ("cfc1 %0, $31" : "=r" (*envp)); 197 198 return (0); 199 } 200 DEF_STD(fegetenv); 201 202 /* 203 * The feholdexcept() function saves the current floating-point environment 204 * in the object pointed to by envp, clears the floating-point status flags, and 205 * then installs a non-stop (continue on floating-point exceptions) mode, if 206 * available, for all floating-point exceptions. 207 */ 208 int 209 feholdexcept(fenv_t *envp) 210 { 211 unsigned int fcsr; 212 213 /* Store the current floating-point control and status register */ 214 __asm__ volatile ("cfc1 %0, $31" : "=r" (*envp)); 215 216 /* Clear exception flags in FCSR */ 217 fcsr = *envp; 218 fcsr &= ~FE_ALL_EXCEPT; 219 220 /* Mask all exceptions */ 221 fcsr &= ~(FE_ALL_EXCEPT << _MASK_SHIFT); 222 __asm__ volatile ("ctc1 %0, $31" : : "r" (fcsr)); 223 224 return (0); 225 } 226 DEF_STD(feholdexcept); 227 228 /* 229 * The fesetenv() function attempts to establish the floating-point environment 230 * represented by the object pointed to by envp. The argument `envp' points 231 * to an object set by a call to fegetenv() or feholdexcept(), or equal a 232 * floating-point environment macro. The fesetenv() function does not raise 233 * floating-point exceptions, but only installs the state of the floating-point 234 * status flags represented through its argument. 235 */ 236 int 237 fesetenv(const fenv_t *envp) 238 { 239 /* Load the floating-point control and status register */ 240 __asm__ volatile ("ctc1 %0, $31" : : "r" (*envp)); 241 242 return (0); 243 } 244 DEF_STD(fesetenv); 245 246 /* 247 * The feupdateenv() function saves the currently raised floating-point 248 * exceptions in its automatic storage, installs the floating-point environment 249 * represented by the object pointed to by `envp', and then raises the saved 250 * floating-point exceptions. The argument `envp' shall point to an object set 251 * by a call to feholdexcept() or fegetenv(), or equal a floating-point 252 * environment macro. 253 */ 254 int 255 feupdateenv(const fenv_t *envp) 256 { 257 unsigned int fcsr; 258 259 /* Store the current floating-point control and status register */ 260 __asm__ volatile ("cfc1 %0, $31" : "=r" (fcsr)); 261 262 /* Install new floating-point environment */ 263 fesetenv(envp); 264 265 /* Raise any previously accumulated exceptions */ 266 feraiseexcept(fcsr); 267 268 return (0); 269 } 270 DEF_STD(feupdateenv); 271 272 /* 273 * The following functions are extensions to the standard 274 */ 275 int 276 feenableexcept(int mask) 277 { 278 unsigned int fcsr, omask; 279 280 mask &= FE_ALL_EXCEPT; 281 282 /* Store the current floating-point control and status register */ 283 __asm__ volatile ("cfc1 %0, $31" : "=r" (fcsr)); 284 285 omask = (fcsr >> _MASK_SHIFT) & FE_ALL_EXCEPT; 286 fcsr |= mask << _MASK_SHIFT; 287 288 /* Load the floating-point control and status register */ 289 __asm__ volatile ("ctc1 %0, $31" : : "r" (fcsr)); 290 291 return (omask); 292 293 } 294 295 int 296 fedisableexcept(int mask) 297 { 298 unsigned int fcsr, omask; 299 300 mask &= FE_ALL_EXCEPT; 301 302 /* Store the current floating-point control and status register */ 303 __asm__ volatile ("cfc1 %0, $31" : "=r" (fcsr)); 304 305 omask = (fcsr >> _MASK_SHIFT) & FE_ALL_EXCEPT; 306 fcsr &= ~(mask << _MASK_SHIFT); 307 308 /* Load the floating-point control and status register */ 309 __asm__ volatile ("ctc1 %0, $31" : : "r" (fcsr)); 310 311 return (omask); 312 } 313 314 int 315 fegetexcept(void) 316 { 317 unsigned int fcsr; 318 319 /* Store the current floating-point control and status register */ 320 __asm__ volatile ("cfc1 %0, $31" : "=r" (fcsr)); 321 322 return ((fcsr >> _MASK_SHIFT) & FE_ALL_EXCEPT); 323 } 324