1 /*- 2 * Copyright (c) 2016 Dan Horák <dan[at]danny.cz> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $FreeBSD$ 27 */ 28 29 #ifndef _FENV_H_ 30 #define _FENV_H_ 31 32 #include <sys/types.h> 33 34 #ifndef __fenv_static 35 #define __fenv_static static 36 #endif 37 38 typedef __uint32_t fenv_t; 39 typedef __uint32_t fexcept_t; 40 41 /* Exception flags */ 42 #define FE_INEXACT 0x080000 43 #define FE_UNDERFLOW 0x100000 44 #define FE_OVERFLOW 0x200000 45 #define FE_DIVBYZERO 0x400000 46 #define FE_INVALID 0x800000 /* all types of invalid FP ops */ 47 48 #define FE_ALL_EXCEPT (FE_INVALID | FE_DIVBYZERO | FE_INEXACT | FE_OVERFLOW | FE_UNDERFLOW) 49 50 /* Rounding modes */ 51 #define FE_TONEAREST 0x0000 52 #define FE_TOWARDZERO 0x0001 53 #define FE_UPWARD 0x0002 54 #define FE_DOWNWARD 0x0003 55 #define _ROUND_MASK (FE_TONEAREST | FE_DOWNWARD | \ 56 FE_UPWARD | FE_TOWARDZERO) 57 58 __BEGIN_DECLS 59 60 /* Default floating-point environment */ 61 extern const fenv_t __fe_dfl_env; 62 #define FE_DFL_ENV (&__fe_dfl_env) 63 64 /* We need to be able to map status flag positions to mask flag positions */ 65 #define _FPC_EXC_MASK_SHIFT 8 66 #define _ENABLE_MASK ((FE_DIVBYZERO | FE_INEXACT | FE_INVALID | \ 67 FE_OVERFLOW | FE_UNDERFLOW) << _FPC_EXC_MASK_SHIFT) 68 69 /* Macros for accessing the hardware control word. */ 70 #define _FPU_GETCW(cw) __asm__ __volatile__ ("efpc %0,0" : "=d" (cw)) 71 #define _FPU_SETCW(cw) __asm__ __volatile__ ("sfpc %0,0" : : "d" (cw)) 72 73 __fenv_static inline int 74 feclearexcept(int __excepts) 75 { 76 fexcept_t __r; 77 78 if (__excepts & FE_INVALID) 79 __excepts |= FE_ALL_EXCEPT; 80 _FPU_GETCW(__r); 81 __r &= ~__excepts; 82 _FPU_SETCW(__r); 83 return (0); 84 } 85 86 __fenv_static inline int 87 fegetexceptflag(fexcept_t *__flagp, int __excepts) 88 { 89 fexcept_t __r; 90 91 _FPU_GETCW(__r); 92 *__flagp = __r & __excepts; 93 return (0); 94 } 95 96 __fenv_static inline int 97 fesetexceptflag(const fexcept_t *__flagp, int __excepts) 98 { 99 fexcept_t __r; 100 101 if (__excepts & FE_INVALID) 102 __excepts |= FE_ALL_EXCEPT; 103 _FPU_GETCW(__r); 104 __r &= ~__excepts; 105 __r |= *__flagp & __excepts; 106 _FPU_SETCW(__r); 107 return (0); 108 } 109 110 __fenv_static inline int 111 feraiseexcept(int __excepts) 112 { 113 fexcept_t __r; 114 115 _FPU_GETCW(__r); 116 __r |= __excepts; 117 _FPU_SETCW(__r); 118 return (0); 119 } 120 121 __fenv_static inline int 122 fetestexcept(int __excepts) 123 { 124 fexcept_t __r; 125 126 _FPU_GETCW(__r); 127 return (__r & __excepts); 128 } 129 130 __fenv_static inline int 131 fegetround(void) 132 { 133 fexcept_t __r; 134 135 _FPU_GETCW(__r); 136 return (__r & _ROUND_MASK); 137 } 138 139 __fenv_static inline int 140 fesetround(int __round) 141 { 142 fexcept_t __r; 143 144 if (__round & ~_ROUND_MASK) 145 return (-1); 146 147 _FPU_GETCW(__r); 148 __r &= ~_ROUND_MASK; 149 __r |= __round; 150 _FPU_SETCW(__r); 151 return (0); 152 } 153 154 __fenv_static inline int 155 fegetenv(fenv_t *__envp) 156 { 157 _FPU_GETCW(*__envp); 158 return (0); 159 } 160 161 __fenv_static inline int 162 feholdexcept(fenv_t *__envp) 163 { 164 fexcept_t __r; 165 166 _FPU_GETCW(__r); 167 *__envp = __r; 168 __r &= ~(FE_ALL_EXCEPT | _ENABLE_MASK); 169 _FPU_SETCW(__r); 170 return (0); 171 } 172 173 __fenv_static inline int 174 fesetenv(const fenv_t *__envp) 175 { 176 _FPU_SETCW(*__envp); 177 return (0); 178 } 179 180 __fenv_static inline int 181 feupdateenv(const fenv_t *__envp) 182 { 183 fexcept_t __r; 184 185 _FPU_GETCW(__r); 186 __r &= FE_ALL_EXCEPT; 187 __r |= *__envp; 188 _FPU_SETCW(__r); 189 return (0); 190 } 191 192 #if __BSD_VISIBLE 193 194 /* We currently provide no external definitions of the functions below. */ 195 196 static inline int 197 feenableexcept(int __mask) 198 { 199 fenv_t __r; 200 fenv_t __oldmask; 201 202 _FPU_GETCW(__r); 203 __oldmask = __r; 204 __r |= (__mask & FE_ALL_EXCEPT) << _FPC_EXC_MASK_SHIFT; 205 _FPU_SETCW(__r); 206 return ((__oldmask & _ENABLE_MASK) >> _FPC_EXC_MASK_SHIFT); 207 } 208 209 static inline int 210 fedisableexcept(int __mask) 211 { 212 fenv_t __r; 213 fenv_t __oldmask; 214 215 _FPU_GETCW(__r); 216 __oldmask = __r; 217 __r &= ~((__mask & FE_ALL_EXCEPT) << _FPC_EXC_MASK_SHIFT); 218 _FPU_SETCW(__r); 219 return ((__oldmask & _ENABLE_MASK) >> _FPC_EXC_MASK_SHIFT); 220 } 221 222 static inline int 223 fegetexcept(void) 224 { 225 fexcept_t __r; 226 227 _FPU_GETCW(__r); 228 return (__r & (_ENABLE_MASK >> _FPC_EXC_MASK_SHIFT)); 229 } 230 231 #endif /* __BSD_VISIBLE */ 232 233 __END_DECLS 234 235 #endif /* !_FENV_H_ */ 236