1 /* $OpenBSD: fenv.c,v 1.4 2014/04/18 15:09:52 guenther 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 55 /* 56 * The fegetexceptflag() function stores an implementation-defined 57 * representation of the states of the floating-point status flags indicated by 58 * the argument excepts in the object pointed to by the argument flagp. 59 */ 60 int 61 fegetexceptflag(fexcept_t *flagp, int excepts) 62 { 63 unsigned int fcsr; 64 65 excepts &= FE_ALL_EXCEPT; 66 67 /* Store the current floating-point control and status register */ 68 __asm__ volatile ("cfc1 %0, $31" : "=r" (fcsr)); 69 70 /* Store the results in flagp */ 71 *flagp = fcsr & excepts; 72 73 return (0); 74 } 75 76 /* 77 * The feraiseexcept() function raises the supported floating-point exceptions 78 * represented by the argument `excepts'. 79 */ 80 int 81 feraiseexcept(int excepts) 82 { 83 unsigned int fcsr; 84 85 excepts &= FE_ALL_EXCEPT; 86 87 /* Store the current floating-point control and status register */ 88 __asm__ volatile ("cfc1 %0, $31" : "=r" (fcsr)); 89 90 fcsr |= excepts | (excepts << 10); 91 92 /* Load the floating-point control and status register */ 93 __asm__ volatile ("ctc1 %0, $31" : : "r" (fcsr)); 94 95 return (0); 96 } 97 98 /* 99 * This function sets the floating-point status flags indicated by the argument 100 * `excepts' to the states stored in the object pointed to by `flagp'. It does 101 * NOT raise any floating-point exceptions, but only sets the state of the flags. 102 */ 103 int 104 fesetexceptflag(const fexcept_t *flagp, int excepts) 105 { 106 unsigned int fcsr; 107 108 excepts &= FE_ALL_EXCEPT; 109 110 /* Store the current floating-point control and status register */ 111 __asm__ volatile ("cfc1 %0, $31" : "=r" (fcsr)); 112 113 /* Set the requested status flags */ 114 fcsr &= ~excepts; 115 fcsr |= *flagp & excepts; 116 117 /* Load the floating-point control and status register */ 118 __asm__ volatile ("ctc1 %0, $31" : : "r" (fcsr)); 119 120 return (0); 121 } 122 123 /* 124 * The fetestexcept() function determines which of a specified subset of the 125 * floating-point exception flags are currently set. The `excepts' argument 126 * specifies the floating-point status flags to be queried. 127 */ 128 int 129 fetestexcept(int excepts) 130 { 131 unsigned int fcsr; 132 133 excepts &= FE_ALL_EXCEPT; 134 135 /* Store the current floating-point control and status register */ 136 __asm__ volatile ("cfc1 %0, $31" : "=r" (fcsr)); 137 138 return (fcsr & excepts); 139 } 140 141 /* 142 * The fegetround() function gets the current rounding direction. 143 */ 144 int 145 fegetround(void) 146 { 147 unsigned int fcsr; 148 149 /* Store the current floating-point control and status register */ 150 __asm__ volatile ("cfc1 %0, $31" : "=r" (fcsr)); 151 152 return (fcsr & _ROUND_MASK); 153 } 154 155 /* 156 * The fesetround() function establishes the rounding direction represented by 157 * its argument `round'. If the argument is not equal to the value of a rounding 158 * direction macro, the rounding direction is not changed. 159 */ 160 int 161 fesetround(int round) 162 { 163 unsigned int fcsr; 164 165 /* Check whether requested rounding direction is supported */ 166 if (round & ~_ROUND_MASK) 167 return (-1); 168 169 /* Store the current floating-point control and status register */ 170 __asm__ volatile ("cfc1 %0, $31" : "=r" (fcsr)); 171 172 /* Set the rounding direction */ 173 fcsr &= ~_ROUND_MASK; 174 fcsr |= round; 175 176 /* Load the floating-point control and status register */ 177 __asm__ volatile ("ctc1 %0, $31" : : "r" (fcsr)); 178 179 return (0); 180 } 181 182 /* 183 * The fegetenv() function attempts to store the current floating-point 184 * environment in the object pointed to by envp. 185 */ 186 int 187 fegetenv(fenv_t *envp) 188 { 189 /* Store the current floating-point control and status register */ 190 __asm__ volatile ("cfc1 %0, $31" : "=r" (*envp)); 191 192 return (0); 193 } 194 195 /* 196 * The feholdexcept() function saves the current floating-point environment 197 * in the object pointed to by envp, clears the floating-point status flags, and 198 * then installs a non-stop (continue on floating-point exceptions) mode, if 199 * available, for all floating-point exceptions. 200 */ 201 int 202 feholdexcept(fenv_t *envp) 203 { 204 unsigned int fcsr; 205 206 /* Store the current floating-point control and status register */ 207 __asm__ volatile ("cfc1 %0, $31" : "=r" (*envp)); 208 209 /* Clear exception flags in FCSR */ 210 fcsr = *envp; 211 fcsr &= ~FE_ALL_EXCEPT; 212 213 /* Mask all exceptions */ 214 fcsr &= ~(FE_ALL_EXCEPT << _MASK_SHIFT); 215 __asm__ volatile ("ctc1 %0, $31" : : "r" (fcsr)); 216 217 return (0); 218 } 219 220 /* 221 * The fesetenv() function attempts to establish the floating-point environment 222 * represented by the object pointed to by envp. The argument `envp' points 223 * to an object set by a call to fegetenv() or feholdexcept(), or equal a 224 * floating-point environment macro. The fesetenv() function does not raise 225 * floating-point exceptions, but only installs the state of the floating-point 226 * status flags represented through its argument. 227 */ 228 int 229 fesetenv(const fenv_t *envp) 230 { 231 /* Load the floating-point control and status register */ 232 __asm__ volatile ("ctc1 %0, $31" : : "r" (*envp)); 233 234 return (0); 235 } 236 237 /* 238 * The feupdateenv() function saves the currently raised floating-point 239 * exceptions in its automatic storage, installs the floating-point environment 240 * represented by the object pointed to by `envp', and then raises the saved 241 * floating-point exceptions. The argument `envp' shall point to an object set 242 * by a call to feholdexcept() or fegetenv(), or equal a floating-point 243 * environment macro. 244 */ 245 int 246 feupdateenv(const fenv_t *envp) 247 { 248 unsigned int fcsr; 249 250 /* Store the current floating-point control and status register */ 251 __asm__ volatile ("cfc1 %0, $31" : "=r" (fcsr)); 252 253 /* Install new floating-point environment */ 254 fesetenv(envp); 255 256 /* Raise any previously accumulated exceptions */ 257 feraiseexcept(fcsr); 258 259 return (0); 260 } 261 262 /* 263 * The following functions are extentions to the standard 264 */ 265 int 266 feenableexcept(int mask) 267 { 268 unsigned int fcsr, omask; 269 270 mask &= FE_ALL_EXCEPT; 271 272 /* Store the current floating-point control and status register */ 273 __asm__ volatile ("cfc1 %0, $31" : "=r" (fcsr)); 274 275 omask = (fcsr >> _MASK_SHIFT) & FE_ALL_EXCEPT; 276 fcsr |= mask << _MASK_SHIFT; 277 278 /* Load the floating-point control and status register */ 279 __asm__ volatile ("ctc1 %0, $31" : : "r" (fcsr)); 280 281 return (omask); 282 283 } 284 285 int 286 fedisableexcept(int mask) 287 { 288 unsigned int fcsr, omask; 289 290 mask &= FE_ALL_EXCEPT; 291 292 /* Store the current floating-point control and status register */ 293 __asm__ volatile ("cfc1 %0, $31" : "=r" (fcsr)); 294 295 omask = (fcsr >> _MASK_SHIFT) & FE_ALL_EXCEPT; 296 fcsr &= ~(mask << _MASK_SHIFT); 297 298 /* Load the floating-point control and status register */ 299 __asm__ volatile ("ctc1 %0, $31" : : "r" (fcsr)); 300 301 return (omask); 302 } 303 304 int 305 fegetexcept(void) 306 { 307 unsigned int fcsr; 308 309 /* Store the current floating-point control and status register */ 310 __asm__ volatile ("cfc1 %0, $31" : "=r" (fcsr)); 311 312 return ((fcsr >> _MASK_SHIFT) & FE_ALL_EXCEPT); 313 } 314