1 1.3 andvar /* $NetBSD: fenv.c,v 1.3 2021/09/03 21:54:59 andvar Exp $ */ 2 1.1 nakayama 3 1.1 nakayama /*- 4 1.1 nakayama * Copyright (c) 2004-2005 David Schultz <das (at) FreeBSD.ORG> 5 1.1 nakayama * All rights reserved. 6 1.1 nakayama * 7 1.1 nakayama * Redistribution and use in source and binary forms, with or without 8 1.1 nakayama * modification, are permitted provided that the following conditions 9 1.1 nakayama * are met: 10 1.1 nakayama * 1. Redistributions of source code must retain the above copyright 11 1.1 nakayama * notice, this list of conditions and the following disclaimer. 12 1.1 nakayama * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 nakayama * notice, this list of conditions and the following disclaimer in the 14 1.1 nakayama * documentation and/or other materials provided with the distribution. 15 1.1 nakayama * 16 1.1 nakayama * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 1.1 nakayama * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 1.1 nakayama * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 1.1 nakayama * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 1.1 nakayama * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 1.1 nakayama * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 1.1 nakayama * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 1.1 nakayama * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 1.1 nakayama * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 1.1 nakayama */ 26 1.1 nakayama #include <sys/cdefs.h> 27 1.3 andvar __RCSID("$NetBSD: fenv.c,v 1.3 2021/09/03 21:54:59 andvar Exp $"); 28 1.2 chs 29 1.2 chs #include "namespace.h" 30 1.1 nakayama 31 1.1 nakayama #include <assert.h> 32 1.1 nakayama #include <fenv.h> 33 1.1 nakayama 34 1.2 chs #ifdef __weak_alias 35 1.2 chs __weak_alias(feclearexcept,_feclearexcept) 36 1.2 chs __weak_alias(fedisableexcept,_fedisableexcept) 37 1.2 chs __weak_alias(feenableexcept,_feenableexcept) 38 1.2 chs __weak_alias(fegetenv,_fegetenv) 39 1.2 chs __weak_alias(fegetexcept,_fegetexcept) 40 1.2 chs __weak_alias(fegetexceptflag,_fegetexceptflag) 41 1.2 chs __weak_alias(fegetround,_fegetround) 42 1.2 chs __weak_alias(feholdexcept,_feholdexcept) 43 1.2 chs __weak_alias(feraiseexcept,_feraiseexcept) 44 1.2 chs __weak_alias(fesetenv,_fesetenv) 45 1.2 chs __weak_alias(fesetexceptflag,_fesetexceptflag) 46 1.2 chs __weak_alias(fesetround,_fesetround) 47 1.2 chs __weak_alias(fetestexcept,_fetestexcept) 48 1.2 chs __weak_alias(feupdateenv,_feupdateenv) 49 1.2 chs #endif 50 1.2 chs 51 1.1 nakayama /* Load floating-point state register (32bits) */ 52 1.1 nakayama #define __ldfsr(__r) __asm__ __volatile__ \ 53 1.1 nakayama ("ld %0, %%fsr" : : "m" (__r)) 54 1.1 nakayama 55 1.1 nakayama /* Save floating-point state register (32bits) */ 56 1.1 nakayama #define __stfsr(__r) __asm__ __volatile__ \ 57 1.1 nakayama ("st %%fsr, %0" : "=m" (*(__r))) 58 1.1 nakayama 59 1.1 nakayama /* 60 1.1 nakayama * The feclearexcept() function clears the supported floating-point exceptions 61 1.1 nakayama * represented by `excepts'. 62 1.1 nakayama */ 63 1.1 nakayama int 64 1.1 nakayama feclearexcept(int excepts) 65 1.1 nakayama { 66 1.1 nakayama fexcept_t r; 67 1.1 nakayama int ex; 68 1.1 nakayama 69 1.1 nakayama _DIAGASSERT((excepts & ~FE_ALL_EXCEPT) == 0); 70 1.1 nakayama 71 1.1 nakayama ex = excepts & FE_ALL_EXCEPT; 72 1.1 nakayama 73 1.1 nakayama __stfsr(&r); 74 1.1 nakayama r &= ~ex; 75 1.1 nakayama __ldfsr(r); 76 1.1 nakayama 77 1.1 nakayama /* Success */ 78 1.1 nakayama return 0; 79 1.1 nakayama } 80 1.1 nakayama 81 1.1 nakayama /* 82 1.1 nakayama * The fegetexceptflag() function stores an implementation-defined 83 1.1 nakayama * representation of the states of the floating-point status flags indicated 84 1.1 nakayama * by the argument excepts in the object pointed to by the argument flagp. 85 1.1 nakayama */ 86 1.1 nakayama int 87 1.1 nakayama fegetexceptflag(fexcept_t *flagp, int excepts) 88 1.1 nakayama { 89 1.1 nakayama fexcept_t r; 90 1.1 nakayama int ex; 91 1.1 nakayama 92 1.1 nakayama _DIAGASSERT(flagp != NULL); 93 1.1 nakayama _DIAGASSERT((excepts & ~_FE_ALL_EXCEPT) == 0); 94 1.1 nakayama 95 1.1 nakayama ex = excepts & FE_ALL_EXCEPT; 96 1.1 nakayama 97 1.1 nakayama __stfsr(&r); 98 1.1 nakayama *flagp = r & ex; 99 1.1 nakayama 100 1.1 nakayama /* Success */ 101 1.1 nakayama return 0; 102 1.1 nakayama } 103 1.1 nakayama 104 1.1 nakayama 105 1.1 nakayama /* 106 1.1 nakayama * This function sets the floating-point status flags indicated by the argument 107 1.1 nakayama * `excepts' to the states stored in the object pointed to by `flagp'. It does 108 1.1 nakayama * NOT raise any floating-point exceptions, but only sets the state of the flags. 109 1.1 nakayama */ 110 1.1 nakayama int 111 1.1 nakayama fesetexceptflag(const fexcept_t *flagp, int excepts) 112 1.1 nakayama { 113 1.1 nakayama fexcept_t r; 114 1.1 nakayama int ex; 115 1.1 nakayama 116 1.1 nakayama _DIAGASSERT(flagp != NULL); 117 1.1 nakayama _DIAGASSERT((excepts & ~FE_ALL_EXCEPT) == 0); 118 1.1 nakayama 119 1.1 nakayama ex = excepts & FE_ALL_EXCEPT; 120 1.1 nakayama 121 1.1 nakayama __stfsr(&r); 122 1.1 nakayama r &= ~ex; 123 1.1 nakayama r |= *flagp & ex; 124 1.1 nakayama __ldfsr(r); 125 1.1 nakayama 126 1.1 nakayama /* Success */ 127 1.1 nakayama return 0; 128 1.1 nakayama } 129 1.1 nakayama 130 1.1 nakayama /* 131 1.1 nakayama * The feraiseexcept() function raises the supported floating-point exceptions 132 1.1 nakayama * represented by the argument `excepts'. 133 1.1 nakayama * 134 1.1 nakayama * The order in which these floating-point exceptions are raised is unspecified 135 1.1 nakayama * (by the standard). 136 1.1 nakayama */ 137 1.1 nakayama int 138 1.1 nakayama feraiseexcept(int excepts) 139 1.1 nakayama { 140 1.1 nakayama volatile double d; 141 1.1 nakayama int ex; 142 1.1 nakayama 143 1.1 nakayama _DIAGASSERT((excepts & ~FE_ALL_EXCEPT) == 0); 144 1.1 nakayama 145 1.1 nakayama ex = excepts & FE_ALL_EXCEPT; 146 1.1 nakayama 147 1.1 nakayama /* 148 1.1 nakayama * With a compiler that supports the FENV_ACCESS pragma properly, simple 149 1.1 nakayama * expressions like '0.0 / 0.0' should be sufficient to generate traps. 150 1.1 nakayama * Unfortunately, we need to bring a volatile variable into the equation 151 1.1 nakayama * to prevent incorrect optimizations. 152 1.1 nakayama */ 153 1.1 nakayama if (ex & FE_INVALID) { 154 1.1 nakayama d = 0.0; 155 1.1 nakayama d = 0.0 / d; 156 1.1 nakayama } 157 1.1 nakayama if (ex & FE_DIVBYZERO) { 158 1.1 nakayama d = 0.0; 159 1.1 nakayama d = 1.0 / d; 160 1.1 nakayama } 161 1.1 nakayama if (ex & FE_OVERFLOW) { 162 1.1 nakayama d = 0x1.ffp1023; 163 1.1 nakayama d *= 2.0; 164 1.1 nakayama } 165 1.1 nakayama if (ex & FE_UNDERFLOW) { 166 1.1 nakayama d = 0x1p-1022; 167 1.1 nakayama d /= 0x1p1023; 168 1.1 nakayama } 169 1.1 nakayama if (ex & FE_INEXACT) { 170 1.1 nakayama d = 0x1p-1022; 171 1.1 nakayama d += 1.0; 172 1.1 nakayama } 173 1.1 nakayama 174 1.1 nakayama /* Success */ 175 1.1 nakayama return 0; 176 1.1 nakayama } 177 1.1 nakayama 178 1.1 nakayama /* 179 1.1 nakayama * The fetestexcept() function determines which of a specified subset of the 180 1.1 nakayama * floating-point exception flags are currently set. The `excepts' argument 181 1.1 nakayama * specifies the floating-point status flags to be queried. 182 1.1 nakayama */ 183 1.1 nakayama int 184 1.1 nakayama fetestexcept(int excepts) 185 1.1 nakayama { 186 1.1 nakayama fexcept_t r; 187 1.1 nakayama 188 1.1 nakayama _DIAGASSERT((excepts & ~FE_ALL_EXCEPT) == 0); 189 1.1 nakayama 190 1.1 nakayama __stfsr(&r); 191 1.1 nakayama 192 1.1 nakayama return r & (excepts & FE_ALL_EXCEPT); 193 1.1 nakayama } 194 1.1 nakayama 195 1.1 nakayama /* 196 1.1 nakayama * The fegetround() function gets the current rounding direction. 197 1.1 nakayama */ 198 1.1 nakayama int 199 1.1 nakayama fegetround(void) 200 1.1 nakayama { 201 1.1 nakayama fenv_t r; 202 1.1 nakayama 203 1.1 nakayama __stfsr(&r); 204 1.1 nakayama 205 1.1 nakayama return (r >> _ROUND_SHIFT) & _ROUND_MASK; 206 1.1 nakayama } 207 1.1 nakayama 208 1.1 nakayama /* 209 1.1 nakayama * The fesetround() function establishes the rounding direction represented by 210 1.1 nakayama * its argument `round'. If the argument is not equal to the value of a rounding 211 1.1 nakayama * direction macro, the rounding direction is not changed. 212 1.1 nakayama */ 213 1.1 nakayama int 214 1.1 nakayama fesetround(int round) 215 1.1 nakayama { 216 1.1 nakayama fenv_t r; 217 1.1 nakayama 218 1.1 nakayama _DIAGASSERT((round & ~_ROUND_MASK) == 0); 219 1.1 nakayama if (round & ~_ROUND_MASK) 220 1.1 nakayama return -1; 221 1.1 nakayama 222 1.1 nakayama __stfsr(&r); 223 1.1 nakayama r &= ~(_ROUND_MASK << _ROUND_SHIFT); 224 1.1 nakayama r |= round << _ROUND_SHIFT; 225 1.1 nakayama __ldfsr(r); 226 1.1 nakayama 227 1.1 nakayama /* Success */ 228 1.1 nakayama return 0; 229 1.1 nakayama } 230 1.1 nakayama 231 1.1 nakayama /* 232 1.1 nakayama * The fegetenv() function attempts to store the current floating-point 233 1.1 nakayama * environment in the object pointed to by envp. 234 1.1 nakayama */ 235 1.1 nakayama int 236 1.1 nakayama fegetenv(fenv_t *envp) 237 1.1 nakayama { 238 1.1 nakayama _DIAGASSERT(envp != NULL); 239 1.1 nakayama 240 1.1 nakayama __stfsr(envp); 241 1.1 nakayama 242 1.1 nakayama /* Success */ 243 1.1 nakayama return 0; 244 1.1 nakayama } 245 1.1 nakayama 246 1.1 nakayama 247 1.1 nakayama /* 248 1.1 nakayama * The feholdexcept() function saves the current floating-point environment 249 1.1 nakayama * in the object pointed to by envp, clears the floating-point status flags, and 250 1.1 nakayama * then installs a non-stop (continue on floating-point exceptions) mode, if 251 1.1 nakayama * available, for all floating-point exceptions. 252 1.1 nakayama */ 253 1.1 nakayama int 254 1.1 nakayama feholdexcept(fenv_t *envp) 255 1.1 nakayama { 256 1.1 nakayama fenv_t r; 257 1.1 nakayama 258 1.1 nakayama _DIAGASSERT(envp != NULL); 259 1.1 nakayama 260 1.1 nakayama __stfsr(&r); 261 1.1 nakayama *envp = r; 262 1.1 nakayama r &= ~(FE_ALL_EXCEPT | _ENABLE_MASK); 263 1.1 nakayama __ldfsr(r); 264 1.1 nakayama 265 1.1 nakayama /* Success */ 266 1.1 nakayama return 0; 267 1.1 nakayama } 268 1.1 nakayama 269 1.1 nakayama /* 270 1.1 nakayama * The fesetenv() function attempts to establish the floating-point environment 271 1.1 nakayama * represented by the object pointed to by envp. The argument `envp' points 272 1.1 nakayama * to an object set by a call to fegetenv() or feholdexcept(), or equal a 273 1.1 nakayama * floating-point environment macro. The fesetenv() function does not raise 274 1.1 nakayama * floating-point exceptions, but only installs the state of the floating-point 275 1.1 nakayama * status flags represented through its argument. 276 1.1 nakayama */ 277 1.1 nakayama int 278 1.1 nakayama fesetenv(const fenv_t *envp) 279 1.1 nakayama { 280 1.1 nakayama _DIAGASSERT(envp != NULL); 281 1.1 nakayama 282 1.1 nakayama __ldfsr(*envp); 283 1.1 nakayama 284 1.1 nakayama /* Success */ 285 1.1 nakayama return 0; 286 1.1 nakayama } 287 1.1 nakayama 288 1.1 nakayama 289 1.1 nakayama /* 290 1.1 nakayama * The feupdateenv() function saves the currently raised floating-point 291 1.1 nakayama * exceptions in its automatic storage, installs the floating-point environment 292 1.1 nakayama * represented by the object pointed to by `envp', and then raises the saved 293 1.1 nakayama * floating-point exceptions. The argument `envp' shall point to an object set 294 1.1 nakayama * by a call to feholdexcept() or fegetenv(), or equal a floating-point 295 1.1 nakayama * environment macro. 296 1.1 nakayama */ 297 1.1 nakayama int 298 1.1 nakayama feupdateenv(const fenv_t *envp) 299 1.1 nakayama { 300 1.1 nakayama fexcept_t r; 301 1.1 nakayama 302 1.1 nakayama _DIAGASSERT(envp != NULL); 303 1.1 nakayama 304 1.1 nakayama __stfsr(&r); 305 1.1 nakayama __ldfsr(*envp); 306 1.1 nakayama 307 1.1 nakayama _DIAGASSERT((r & ~FE_ALL_EXCEPT) == 0); 308 1.1 nakayama feraiseexcept(r & FE_ALL_EXCEPT); 309 1.1 nakayama 310 1.1 nakayama /* Success */ 311 1.1 nakayama return 0; 312 1.1 nakayama } 313 1.1 nakayama 314 1.1 nakayama /* 315 1.3 andvar * The following functions are extensions to the standard 316 1.1 nakayama */ 317 1.1 nakayama int 318 1.1 nakayama feenableexcept(int mask) 319 1.1 nakayama { 320 1.1 nakayama fenv_t old_r, new_r; 321 1.1 nakayama 322 1.1 nakayama __stfsr(&old_r); 323 1.1 nakayama new_r = old_r | ((mask & FE_ALL_EXCEPT) << _FPUSW_SHIFT); 324 1.1 nakayama __ldfsr(new_r); 325 1.1 nakayama 326 1.1 nakayama return (old_r >> _FPUSW_SHIFT) & FE_ALL_EXCEPT; 327 1.1 nakayama } 328 1.1 nakayama 329 1.1 nakayama int 330 1.1 nakayama fedisableexcept(int mask) 331 1.1 nakayama { 332 1.1 nakayama fenv_t old_r, new_r; 333 1.1 nakayama 334 1.1 nakayama __stfsr(&old_r); 335 1.1 nakayama new_r = old_r & ~((mask & FE_ALL_EXCEPT) << _FPUSW_SHIFT); 336 1.1 nakayama __ldfsr(new_r); 337 1.1 nakayama 338 1.1 nakayama return (old_r >> _FPUSW_SHIFT) & FE_ALL_EXCEPT; 339 1.1 nakayama } 340 1.1 nakayama 341 1.1 nakayama int 342 1.1 nakayama fegetexcept(void) 343 1.1 nakayama { 344 1.1 nakayama fenv_t r; 345 1.1 nakayama 346 1.1 nakayama __stfsr(&r); 347 1.1 nakayama return (r & _ENABLE_MASK) >> _FPUSW_SHIFT; 348 1.1 nakayama } 349