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