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