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