fenv.c revision 1.3
1/* $OpenBSD: fenv.c,v 1.3 2012/12/05 23:20:02 deraadt 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#include <machine/ieeefp.h> 21 22extern fp_except _softfloat_float_exception_flags; 23extern fp_except _softfloat_float_exception_mask; 24extern fp_rnd _softfloat_float_rounding_mode; 25extern void _softfloat_float_raise(fp_except); 26 27/* 28 * The following constant represents the default floating-point environment 29 * (that is, the one installed at program startup) and has type pointer to 30 * const-qualified fenv_t. 31 * 32 * It can be used as an argument to the functions within the <fenv.h> header 33 * that manage the floating-point environment, namely fesetenv() and 34 * feupdateenv(). 35 */ 36fenv_t __fe_dfl_env = { 37 0, 38 0, 39 0 40}; 41 42/* 43 * The feclearexcept() function clears the supported floating-point exceptions 44 * represented by `excepts'. 45 */ 46int 47feclearexcept(int excepts) 48{ 49 excepts &= FE_ALL_EXCEPT; 50 51 /* Clear the requested floating-point exceptions */ 52 _softfloat_float_exception_flags &= ~excepts; 53 54 return (0); 55} 56 57/* 58 * The fegetexceptflag() function stores an implementation-defined 59 * representation of the states of the floating-point status flags indicated by 60 * the argument excepts in the object pointed to by the argument flagp. 61 */ 62int 63fegetexceptflag(fexcept_t *flagp, int excepts) 64{ 65 excepts &= FE_ALL_EXCEPT; 66 67 /* Store the results in flagp */ 68 *flagp = _softfloat_float_exception_flags & excepts; 69 70 return (0); 71} 72 73/* 74 * The feraiseexcept() function raises the supported floating-point exceptions 75 * represented by the argument `excepts'. 76 */ 77int 78feraiseexcept(int excepts) 79{ 80 excepts &= FE_ALL_EXCEPT; 81 82 fesetexceptflag((fexcept_t *)&excepts, excepts); 83 _softfloat_float_raise(excepts); 84 85 return (0); 86} 87 88/* 89 * This function sets the floating-point status flags indicated by the argument 90 * `excepts' to the states stored in the object pointed to by `flagp'. It does 91 * NOT raise any floating-point exceptions, but only sets the state of the flags. 92 */ 93int 94fesetexceptflag(const fexcept_t *flagp, int excepts) 95{ 96 excepts &= FE_ALL_EXCEPT; 97 98 /* Set the requested status flags */ 99 _softfloat_float_exception_flags &= ~excepts; 100 _softfloat_float_exception_flags |= *flagp & excepts; 101 102 return (0); 103} 104 105/* 106 * The fetestexcept() function determines which of a specified subset of the 107 * floating-point exception flags are currently set. The `excepts' argument 108 * specifies the floating-point status flags to be queried. 109 */ 110int 111fetestexcept(int excepts) 112{ 113 excepts &= FE_ALL_EXCEPT; 114 115 return (_softfloat_float_exception_flags & excepts); 116} 117 118/* 119 * The fegetround() function gets the current rounding direction. 120 */ 121int 122fegetround(void) 123{ 124 return (_softfloat_float_rounding_mode & _ROUND_MASK); 125} 126 127/* 128 * The fesetround() function establishes the rounding direction represented by 129 * its argument `round'. If the argument is not equal to the value of a rounding 130 * direction macro, the rounding direction is not changed. 131 */ 132int 133fesetround(int round) 134{ 135 /* Check whether requested rounding direction is supported */ 136 if (round & ~_ROUND_MASK) 137 return (-1); 138 139 /* Set the rounding direction */ 140 _softfloat_float_rounding_mode &= ~_ROUND_MASK; 141 _softfloat_float_rounding_mode |= round; 142 143 return (0); 144} 145 146/* 147 * The fegetenv() function attempts to store the current floating-point 148 * environment in the object pointed to by envp. 149 */ 150int 151fegetenv(fenv_t *envp) 152{ 153 /* Store the current floating-point sticky flags */ 154 envp->__sticky = _softfloat_float_exception_flags; 155 156 /* Store the current floating-point masks */ 157 envp->__mask = _softfloat_float_exception_mask; 158 159 /* Store the current floating-point control register */ 160 envp->__round = _softfloat_float_rounding_mode; 161 162 return (0); 163} 164 165/* 166 * The feholdexcept() function saves the current floating-point environment 167 * in the object pointed to by envp, clears the floating-point status flags, and 168 * then installs a non-stop (continue on floating-point exceptions) mode, if 169 * available, for all floating-point exceptions. 170 */ 171int 172feholdexcept(fenv_t *envp) 173{ 174 /* Store the current floating-point environment */ 175 fegetenv(envp); 176 177 /* Clear exception flags */ 178 _softfloat_float_exception_flags &= ~FE_ALL_EXCEPT; 179 180 /* Mask all exceptions */ 181 _softfloat_float_exception_mask &= ~FE_ALL_EXCEPT; 182 183 return (0); 184} 185 186/* 187 * The fesetenv() function attempts to establish the floating-point environment 188 * represented by the object pointed to by envp. The argument `envp' points 189 * to an object set by a call to fegetenv() or feholdexcept(), or equal a 190 * floating-point environment macro. The fesetenv() function does not raise 191 * floating-point exceptions, but only installs the state of the floating-point 192 * status flags represented through its argument. 193 */ 194int 195fesetenv(const fenv_t *envp) 196{ 197 /* Load the floating-point sticky flags */ 198 _softfloat_float_exception_flags = envp->__sticky & FE_ALL_EXCEPT; 199 200 /* Load the floating-point masks */ 201 _softfloat_float_exception_mask = envp->__mask & FE_ALL_EXCEPT; 202 203 /* Load the floating-point rounding mode */ 204 _softfloat_float_rounding_mode = envp->__round & _ROUND_MASK; 205 206 return (0); 207} 208 209/* 210 * The feupdateenv() function saves the currently raised floating-point 211 * exceptions in its automatic storage, installs the floating-point environment 212 * represented by the object pointed to by `envp', and then raises the saved 213 * floating-point exceptions. The argument `envp' shall point to an object set 214 * by a call to feholdexcept() or fegetenv(), or equal a floating-point 215 * environment macro. 216 */ 217int 218feupdateenv(const fenv_t *envp) 219{ 220 int excepts = _softfloat_float_exception_flags; 221 222 /* Install new floating-point environment */ 223 fesetenv(envp); 224 225 /* Raise any previously accumulated exceptions */ 226 feraiseexcept(excepts); 227 228 return (0); 229} 230 231/* 232 * The following functions are extentions to the standard 233 */ 234int 235feenableexcept(int mask) 236{ 237 int omask; 238 239 mask &= FE_ALL_EXCEPT; 240 241 omask = _softfloat_float_exception_mask & FE_ALL_EXCEPT; 242 _softfloat_float_exception_mask |= mask; 243 244 return (omask); 245 246} 247 248int 249fedisableexcept(int mask) 250{ 251 unsigned int omask; 252 253 mask &= FE_ALL_EXCEPT; 254 255 omask = _softfloat_float_exception_mask & FE_ALL_EXCEPT; 256 _softfloat_float_exception_mask &= ~mask; 257 258 return (omask); 259} 260 261int 262fegetexcept(void) 263{ 264 return (_softfloat_float_exception_mask & FE_ALL_EXCEPT); 265} 266