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