1*cddc78eaSriastradh /* $NetBSD: fenv.h,v 1.8 2024/10/30 15:56:11 riastradh Exp $ */ 2ec195e5aSchristos 3ec195e5aSchristos /*- 4ec195e5aSchristos * Copyright (c) 2004-2005 David Schultz <das@FreeBSD.ORG> 5ec195e5aSchristos * All rights reserved. 6ec195e5aSchristos * 7ec195e5aSchristos * Redistribution and use in source and binary forms, with or without 8ec195e5aSchristos * modification, are permitted provided that the following conditions 9ec195e5aSchristos * are met: 10ec195e5aSchristos * 1. Redistributions of source code must retain the above copyright 11ec195e5aSchristos * notice, this list of conditions and the following disclaimer. 12ec195e5aSchristos * 2. Redistributions in binary form must reproduce the above copyright 13ec195e5aSchristos * notice, this list of conditions and the following disclaimer in the 14ec195e5aSchristos * documentation and/or other materials provided with the distribution. 15ec195e5aSchristos * 16ec195e5aSchristos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17ec195e5aSchristos * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18ec195e5aSchristos * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19ec195e5aSchristos * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20ec195e5aSchristos * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21ec195e5aSchristos * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22ec195e5aSchristos * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23ec195e5aSchristos * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24ec195e5aSchristos * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25ec195e5aSchristos * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26ec195e5aSchristos * SUCH DAMAGE. 27ec195e5aSchristos * 28ec195e5aSchristos * $FreeBSD: head/lib/msun/powerpc/fenv.h 226218 2011-10-10 15:43:09Z das $ 29ec195e5aSchristos */ 30ec195e5aSchristos 31ec195e5aSchristos #ifndef _POWERPC_FENV_H_ 32ec195e5aSchristos #define _POWERPC_FENV_H_ 33ec195e5aSchristos 34*cddc78eaSriastradh #include <sys/featuretest.h> 35ec195e5aSchristos #include <sys/stdint.h> 36ec195e5aSchristos 37ec195e5aSchristos /* Exception flags */ 38ec195e5aSchristos #define FE_INEXACT 0x02000000 39ec195e5aSchristos #define FE_DIVBYZERO 0x04000000 40ec195e5aSchristos #define FE_UNDERFLOW 0x08000000 41ec195e5aSchristos #define FE_OVERFLOW 0x10000000 42ec195e5aSchristos #define FE_INVALID 0x20000000 /* all types of invalid FP ops */ 43ec195e5aSchristos 44ec195e5aSchristos /* 45ec195e5aSchristos * The PowerPC architecture has extra invalid flags that indicate the 46ec195e5aSchristos * specific type of invalid operation occurred. These flags may be 47ec195e5aSchristos * tested, set, and cleared---but not masked---separately. All of 48ec195e5aSchristos * these bits are cleared when FE_INVALID is cleared, but only 49ec195e5aSchristos * FE_VXSOFT is set when FE_INVALID is explicitly set in software. 50ec195e5aSchristos */ 51ec195e5aSchristos #define FE_VXCVI 0x00000100 /* invalid integer convert */ 52ec195e5aSchristos #define FE_VXSQRT 0x00000200 /* square root of a negative */ 53ec195e5aSchristos #define FE_VXSOFT 0x00000400 /* software-requested exception */ 54ec195e5aSchristos #define FE_VXVC 0x00080000 /* ordered comparison involving NaN */ 55ec195e5aSchristos #define FE_VXIMZ 0x00100000 /* inf * 0 */ 56ec195e5aSchristos #define FE_VXZDZ 0x00200000 /* 0 / 0 */ 57ec195e5aSchristos #define FE_VXIDI 0x00400000 /* inf / inf */ 58ec195e5aSchristos #define FE_VXISI 0x00800000 /* inf - inf */ 59ec195e5aSchristos #define FE_VXSNAN 0x01000000 /* operation on a signalling NaN */ 60ec195e5aSchristos #define FE_ALL_INVALID (FE_VXCVI | FE_VXSQRT | FE_VXSOFT | FE_VXVC | \ 61ec195e5aSchristos FE_VXIMZ | FE_VXZDZ | FE_VXIDI | FE_VXISI | \ 62ec195e5aSchristos FE_VXSNAN | FE_INVALID) 63ec195e5aSchristos #define FE_ALL_EXCEPT (FE_DIVBYZERO | FE_INEXACT | \ 64ec195e5aSchristos FE_ALL_INVALID | FE_OVERFLOW | FE_UNDERFLOW) 65ec195e5aSchristos 66ec195e5aSchristos /* Rounding modes */ 67ec195e5aSchristos #define FE_TONEAREST 0x0000 68ec195e5aSchristos #define FE_TOWARDZERO 0x0001 69ec195e5aSchristos #define FE_UPWARD 0x0002 70ec195e5aSchristos #define FE_DOWNWARD 0x0003 71ec195e5aSchristos #define _ROUND_MASK (FE_TONEAREST | FE_DOWNWARD | \ 72ec195e5aSchristos FE_UPWARD | FE_TOWARDZERO) 73ec195e5aSchristos 747e30e943Schs #ifndef _SOFT_FLOAT 757e30e943Schs 767e30e943Schs #ifndef __fenv_static 777e30e943Schs #define __fenv_static static 787e30e943Schs #endif 797e30e943Schs 807e30e943Schs typedef uint32_t fenv_t; 817e30e943Schs typedef uint32_t fexcept_t; 827e30e943Schs 83ec195e5aSchristos #ifndef _KERNEL 84ec195e5aSchristos __BEGIN_DECLS 85ec195e5aSchristos 86ec195e5aSchristos /* Default floating-point environment */ 87ec195e5aSchristos extern const fenv_t __fe_dfl_env; 88ec195e5aSchristos #define FE_DFL_ENV (&__fe_dfl_env) 89ec195e5aSchristos 90ec195e5aSchristos /* We need to be able to map status flag positions to mask flag positions */ 91ec195e5aSchristos #define _FPUSW_SHIFT 22 92ec195e5aSchristos #define _ENABLE_MASK ((FE_DIVBYZERO | FE_INEXACT | FE_INVALID | \ 93ec195e5aSchristos FE_OVERFLOW | FE_UNDERFLOW) >> _FPUSW_SHIFT) 94ec195e5aSchristos 95ec195e5aSchristos #ifndef _SOFT_FLOAT 96ec195e5aSchristos #define __mffs(__env) __asm __volatile("mffs %0" : "=f" (*(__env))) 97ec195e5aSchristos #define __mtfsf(__env) __asm __volatile("mtfsf 255,%0" : : "f" (__env)) 981e728605Schs 9987fd18f8Schristos static __inline uint32_t 1001e728605Schs __mfmsr(void) 1011e728605Schs { 1021e728605Schs uint32_t __msr; 1031e728605Schs 1041e728605Schs __asm volatile ("mfmsr %0" : "=r"(__msr)); 1051e728605Schs return __msr; 1061e728605Schs } 1071e728605Schs 10887fd18f8Schristos static __inline void 1091e728605Schs __mtmsr(uint32_t __msr) 1101e728605Schs { 1111e728605Schs 1121e728605Schs __asm volatile ("mtmsr %0" : : "r"(__msr)); 1131e728605Schs } 1141e728605Schs 1151e728605Schs #define __MSR_FE_MASK (0x00000800 | 0x00000100) 1161e728605Schs #define __MSR_FE_DIS (0) 1171e728605Schs #define __MSR_FE_PREC (0x00000800 | 0x00000100) 1181e728605Schs 11987fd18f8Schristos static __inline void 1201e728605Schs __updatemsr(uint32_t __reg) 1211e728605Schs { 1221e728605Schs uint32_t __msr; 1231e728605Schs 1241e728605Schs __msr = __mfmsr() & ~__MSR_FE_MASK; 1251e728605Schs if (__reg != 0) { 1261e728605Schs __msr |= __MSR_FE_PREC; 1271e728605Schs } else { 1281e728605Schs __msr |= __MSR_FE_DIS; 1291e728605Schs } 1301e728605Schs __mtmsr(__msr); 1311e728605Schs } 1321e728605Schs 133ec195e5aSchristos #else 134ec195e5aSchristos #define __mffs(__env) 135ec195e5aSchristos #define __mtfsf(__env) 1361e728605Schs #define __updatemsr(__reg) 137ec195e5aSchristos #endif 138ec195e5aSchristos 139ec195e5aSchristos union __fpscr { 140ec195e5aSchristos double __d; 141ec195e5aSchristos struct { 142ec195e5aSchristos uint32_t __junk; 143ec195e5aSchristos fenv_t __reg; 144ec195e5aSchristos } __bits; 145ec195e5aSchristos }; 146ec195e5aSchristos 14701c63c4fSchristos #if __GNUC_PREREQ__(8, 0) 14801c63c4fSchristos #pragma GCC diagnostic push 14901c63c4fSchristos #pragma GCC diagnostic ignored "-Wshadow" 15001c63c4fSchristos #endif 15101c63c4fSchristos 15287fd18f8Schristos __fenv_static __inline int 153ec195e5aSchristos feclearexcept(int __excepts) 154ec195e5aSchristos { 155ec195e5aSchristos union __fpscr __r; 156ec195e5aSchristos 157ec195e5aSchristos if (__excepts & FE_INVALID) 158ec195e5aSchristos __excepts |= FE_ALL_INVALID; 159ec195e5aSchristos __mffs(&__r.__d); 160ec195e5aSchristos __r.__bits.__reg &= ~__excepts; 161ec195e5aSchristos __mtfsf(__r.__d); 162ec195e5aSchristos return (0); 163ec195e5aSchristos } 164ec195e5aSchristos 16587fd18f8Schristos __fenv_static __inline int 166ec195e5aSchristos fegetexceptflag(fexcept_t *__flagp, int __excepts) 167ec195e5aSchristos { 168ec195e5aSchristos union __fpscr __r; 169ec195e5aSchristos 170ec195e5aSchristos __mffs(&__r.__d); 171ec195e5aSchristos *__flagp = __r.__bits.__reg & __excepts; 172ec195e5aSchristos return (0); 173ec195e5aSchristos } 174ec195e5aSchristos 17587fd18f8Schristos __fenv_static __inline int 176ec195e5aSchristos fesetexceptflag(const fexcept_t *__flagp, int __excepts) 177ec195e5aSchristos { 178ec195e5aSchristos union __fpscr __r; 179ec195e5aSchristos 180ec195e5aSchristos if (__excepts & FE_INVALID) 181fb9bbc71Srin __excepts |= FE_ALL_INVALID; 182ec195e5aSchristos __mffs(&__r.__d); 183ec195e5aSchristos __r.__bits.__reg &= ~__excepts; 184ec195e5aSchristos __r.__bits.__reg |= *__flagp & __excepts; 185ec195e5aSchristos __mtfsf(__r.__d); 186ec195e5aSchristos return (0); 187ec195e5aSchristos } 188ec195e5aSchristos 18987fd18f8Schristos __fenv_static __inline int 190ec195e5aSchristos feraiseexcept(int __excepts) 191ec195e5aSchristos { 192ec195e5aSchristos union __fpscr __r; 193ec195e5aSchristos 194ec195e5aSchristos if (__excepts & FE_INVALID) 195ec195e5aSchristos __excepts |= FE_VXSOFT; 196ec195e5aSchristos __mffs(&__r.__d); 197ec195e5aSchristos __r.__bits.__reg |= __excepts; 198ec195e5aSchristos __mtfsf(__r.__d); 199ec195e5aSchristos return (0); 200ec195e5aSchristos } 201ec195e5aSchristos 20287fd18f8Schristos __fenv_static __inline int 203ec195e5aSchristos fetestexcept(int __excepts) 204ec195e5aSchristos { 205ec195e5aSchristos union __fpscr __r; 206ec195e5aSchristos 207ec195e5aSchristos __mffs(&__r.__d); 208ec195e5aSchristos return (__r.__bits.__reg & __excepts); 209ec195e5aSchristos } 210ec195e5aSchristos 21187fd18f8Schristos __fenv_static __inline int 212ec195e5aSchristos fegetround(void) 213ec195e5aSchristos { 214ec195e5aSchristos union __fpscr __r; 215ec195e5aSchristos 216ec195e5aSchristos __mffs(&__r.__d); 217ec195e5aSchristos return (__r.__bits.__reg & _ROUND_MASK); 218ec195e5aSchristos } 219ec195e5aSchristos 22087fd18f8Schristos __fenv_static __inline int 221ec195e5aSchristos fesetround(int __round) 222ec195e5aSchristos { 223ec195e5aSchristos union __fpscr __r; 224ec195e5aSchristos 225ec195e5aSchristos if (__round & ~_ROUND_MASK) 226ec195e5aSchristos return (-1); 227ec195e5aSchristos __mffs(&__r.__d); 228ec195e5aSchristos __r.__bits.__reg &= ~_ROUND_MASK; 229ec195e5aSchristos __r.__bits.__reg |= __round; 230ec195e5aSchristos __mtfsf(__r.__d); 231ec195e5aSchristos return (0); 232ec195e5aSchristos } 233ec195e5aSchristos 23487fd18f8Schristos __fenv_static __inline int 235ec195e5aSchristos fegetenv(fenv_t *__envp) 236ec195e5aSchristos { 237ec195e5aSchristos union __fpscr __r; 238ec195e5aSchristos 239ec195e5aSchristos __mffs(&__r.__d); 240ec195e5aSchristos *__envp = __r.__bits.__reg; 241ec195e5aSchristos return (0); 242ec195e5aSchristos } 243ec195e5aSchristos 24487fd18f8Schristos __fenv_static __inline int 245ec195e5aSchristos feholdexcept(fenv_t *__envp) 246ec195e5aSchristos { 247ec195e5aSchristos union __fpscr __r; 2481e728605Schs uint32_t msr; 249ec195e5aSchristos 250ec195e5aSchristos __mffs(&__r.__d); 251eabf26b1Sphx *__envp = __r.__bits.__reg; 252ec195e5aSchristos __r.__bits.__reg &= ~(FE_ALL_EXCEPT | _ENABLE_MASK); 253ec195e5aSchristos __mtfsf(__r.__d); 2541e728605Schs __updatemsr(__r.__bits.__reg); 255ec195e5aSchristos return (0); 256ec195e5aSchristos } 257ec195e5aSchristos 25887fd18f8Schristos __fenv_static __inline int 259ec195e5aSchristos fesetenv(const fenv_t *__envp) 260ec195e5aSchristos { 261ec195e5aSchristos union __fpscr __r; 262ec195e5aSchristos 263ec195e5aSchristos __r.__bits.__reg = *__envp; 264ec195e5aSchristos __mtfsf(__r.__d); 2651e728605Schs __updatemsr(__r.__bits.__reg); 266ec195e5aSchristos return (0); 267ec195e5aSchristos } 268ec195e5aSchristos 26987fd18f8Schristos __fenv_static __inline int 270ec195e5aSchristos feupdateenv(const fenv_t *__envp) 271ec195e5aSchristos { 272ec195e5aSchristos union __fpscr __r; 273ec195e5aSchristos 274ec195e5aSchristos __mffs(&__r.__d); 275ec195e5aSchristos __r.__bits.__reg &= FE_ALL_EXCEPT; 276ec195e5aSchristos __r.__bits.__reg |= *__envp; 277ec195e5aSchristos __mtfsf(__r.__d); 2781e728605Schs __updatemsr(__r.__bits.__reg); 279ec195e5aSchristos return (0); 280ec195e5aSchristos } 281ec195e5aSchristos 28201c63c4fSchristos #if __GNUC_PREREQ__(8, 0) 28301c63c4fSchristos #pragma GCC diagnostic pop 28401c63c4fSchristos #endif 28501c63c4fSchristos 286ec195e5aSchristos #if defined(_NETBSD_SOURCE) || defined(_GNU_SOURCE) 287ec195e5aSchristos 28887fd18f8Schristos __fenv_static __inline int 289ec195e5aSchristos feenableexcept(int __mask) 290ec195e5aSchristos { 291ec195e5aSchristos union __fpscr __r; 292ec195e5aSchristos fenv_t __oldmask; 293ec195e5aSchristos 294ec195e5aSchristos __mffs(&__r.__d); 295ec195e5aSchristos __oldmask = __r.__bits.__reg; 296ec195e5aSchristos __r.__bits.__reg |= (__mask & FE_ALL_EXCEPT) >> _FPUSW_SHIFT; 297ec195e5aSchristos __mtfsf(__r.__d); 2981e728605Schs __updatemsr(__r.__bits.__reg); 299ec195e5aSchristos return ((__oldmask & _ENABLE_MASK) << _FPUSW_SHIFT); 300ec195e5aSchristos } 301ec195e5aSchristos 30287fd18f8Schristos __fenv_static __inline int 303ec195e5aSchristos fedisableexcept(int __mask) 304ec195e5aSchristos { 305ec195e5aSchristos union __fpscr __r; 306ec195e5aSchristos fenv_t __oldmask; 307ec195e5aSchristos 308ec195e5aSchristos __mffs(&__r.__d); 309ec195e5aSchristos __oldmask = __r.__bits.__reg; 310ec195e5aSchristos __r.__bits.__reg &= ~((__mask & FE_ALL_EXCEPT) >> _FPUSW_SHIFT); 311ec195e5aSchristos __mtfsf(__r.__d); 3121e728605Schs __updatemsr(__r.__bits.__reg); 313ec195e5aSchristos return ((__oldmask & _ENABLE_MASK) << _FPUSW_SHIFT); 314ec195e5aSchristos } 315ec195e5aSchristos 31687fd18f8Schristos __fenv_static __inline int 317ec195e5aSchristos fegetexcept(void) 318ec195e5aSchristos { 319ec195e5aSchristos union __fpscr __r; 320ec195e5aSchristos 321ec195e5aSchristos __mffs(&__r.__d); 322ec195e5aSchristos return ((__r.__bits.__reg & _ENABLE_MASK) << _FPUSW_SHIFT); 323ec195e5aSchristos } 324ec195e5aSchristos 325ec195e5aSchristos #endif /* _NETBSD_SOURCE || _GNU_SOURCE */ 326ec195e5aSchristos 327ec195e5aSchristos __END_DECLS 3287e30e943Schs 329ec195e5aSchristos #endif 3307e30e943Schs #endif /* _SOFT_FLOAT */ 331ec195e5aSchristos 332ec195e5aSchristos #endif /* !_POWERPC_FENV_H_ */ 333