1 /*- 2 * Copyright (c) 2004-2005 David Schultz <das (at) FreeBSD.ORG> 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: src/lib/msun/ia64/fenv.h,v 1.4 2005/03/16 19:03:45 das Exp $ 27 */ 28 29 #ifndef _FENV_H_ 30 #define _FENV_H_ 31 32 #include <sys/_types.h> 33 34 typedef __uint64_t fenv_t; 35 typedef __uint16_t fexcept_t; 36 37 /* Exception flags */ 38 #define FE_INVALID 0x01 39 #define FE_DENORMAL 0x02 40 #define FE_DIVBYZERO 0x04 41 #define FE_OVERFLOW 0x08 42 #define FE_UNDERFLOW 0x10 43 #define FE_INEXACT 0x20 44 #define FE_ALL_EXCEPT (FE_DIVBYZERO | FE_DENORMAL | FE_INEXACT | \ 45 FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW) 46 47 /* Rounding modes */ 48 #define FE_TONEAREST 0x0000 49 #define FE_DOWNWARD 0x0400 50 #define FE_UPWARD 0x0800 51 #define FE_TOWARDZERO 0x0c00 52 #define _ROUND_MASK (FE_TONEAREST | FE_DOWNWARD | \ 53 FE_UPWARD | FE_TOWARDZERO) 54 55 __BEGIN_DECLS 56 57 /* Default floating-point environment */ 58 extern const fenv_t __fe_dfl_env; 59 #define FE_DFL_ENV (&__fe_dfl_env) 60 61 #define _FPUSW_SHIFT 13 62 63 #define __stfpsr(__r) __asm __volatile("mov %0=ar.fpsr" : "=r" (*(__r))) 64 #define __ldfpsr(__r) __asm __volatile("mov ar.fpsr=%0;;" : : "r" (__r)) 65 66 static __inline int 67 feclearexcept(int __excepts) 68 { 69 fenv_t __fpsr; 70 71 __stfpsr(&__fpsr); 72 __fpsr &= ~((fenv_t)__excepts << _FPUSW_SHIFT); 73 __ldfpsr(__fpsr); 74 return (0); 75 } 76 77 static __inline int 78 fegetexceptflag(fexcept_t *__flagp, int __excepts) 79 { 80 fenv_t __fpsr; 81 82 __stfpsr(&__fpsr); 83 *__flagp = (fexcept_t)(__fpsr >> _FPUSW_SHIFT) & __excepts; 84 return (0); 85 } 86 87 static __inline int 88 fesetexceptflag(const fexcept_t *__flagp, int __excepts) 89 { 90 fenv_t __fpsr; 91 92 __stfpsr(&__fpsr); 93 __fpsr &= ~((fenv_t)__excepts << _FPUSW_SHIFT); 94 __fpsr |= (fenv_t)(__excepts & *__flagp) << _FPUSW_SHIFT; 95 __ldfpsr(__fpsr); 96 return (0); 97 } 98 99 /* 100 * It is worthwhile to use the inline version of this function iff it 101 * is called with arguments that are compile-time constants (due to 102 * dead code elimination). Unfortunately, gcc isn't smart enough to 103 * figure this out automatically, and there's no way to tell it. 104 * We assume that constant arguments will be the common case. 105 */ 106 static __inline int 107 feraiseexcept(int __excepts) 108 { 109 volatile double d; 110 111 /* 112 * With a compiler that supports the FENV_ACCESS pragma 113 * properly, simple expressions like '0.0 / 0.0' should 114 * be sufficient to generate traps. Unfortunately, we 115 * need to bring a volatile variable into the equation 116 * to prevent incorrect optimizations. 117 */ 118 if (__excepts & FE_INVALID) { 119 d = 0.0; 120 d = 0.0 / d; 121 } 122 if (__excepts & FE_DIVBYZERO) { 123 d = 0.0; 124 d = 1.0 / d; 125 } 126 if (__excepts & FE_OVERFLOW) { 127 d = 0x1.ffp1023; 128 d *= 2.0; 129 } 130 if (__excepts & FE_UNDERFLOW) { 131 d = 0x1p-1022; 132 d /= 0x1p1023; 133 } 134 if (__excepts & FE_INEXACT) { 135 d = 0x1p-1022; 136 d += 1.0; 137 } 138 return (0); 139 } 140 141 static __inline int 142 fetestexcept(int __excepts) 143 { 144 fenv_t __fpsr; 145 146 __stfpsr(&__fpsr); 147 return ((__fpsr >> _FPUSW_SHIFT) & __excepts); 148 } 149 150 151 static __inline int 152 fegetround(void) 153 { 154 fenv_t __fpsr; 155 156 __stfpsr(&__fpsr); 157 return (__fpsr & _ROUND_MASK); 158 } 159 160 static __inline int 161 fesetround(int __round) 162 { 163 fenv_t __fpsr; 164 165 if (__round & ~_ROUND_MASK) 166 return (-1); 167 __stfpsr(&__fpsr); 168 __fpsr &= ~_ROUND_MASK; 169 __fpsr |= __round; 170 __ldfpsr(__fpsr); 171 return (0); 172 } 173 174 static __inline int 175 fegetenv(fenv_t *__envp) 176 { 177 178 __stfpsr(__envp); 179 return (0); 180 } 181 182 static __inline int 183 feholdexcept(fenv_t *__envp) 184 { 185 fenv_t __fpsr; 186 187 __stfpsr(&__fpsr); 188 *__envp = __fpsr; 189 __fpsr &= ~((fenv_t)FE_ALL_EXCEPT << _FPUSW_SHIFT); 190 __fpsr |= FE_ALL_EXCEPT; 191 __ldfpsr(__fpsr); 192 return (0); 193 } 194 195 static __inline int 196 fesetenv(const fenv_t *__envp) 197 { 198 199 __ldfpsr(*__envp); 200 return (0); 201 } 202 203 int feupdateenv(const fenv_t *__envp); 204 205 #if __BSD_VISIBLE 206 207 static __inline int 208 feenableexcept(int __mask) 209 { 210 fenv_t __newfpsr, __oldfpsr; 211 212 __stfpsr(&__oldfpsr); 213 __newfpsr = __oldfpsr & ~(__mask & FE_ALL_EXCEPT); 214 __ldfpsr(__newfpsr); 215 return (~__oldfpsr & FE_ALL_EXCEPT); 216 } 217 218 static __inline int 219 fedisableexcept(int __mask) 220 { 221 fenv_t __newfpsr, __oldfpsr; 222 223 __stfpsr(&__oldfpsr); 224 __newfpsr = __oldfpsr | (__mask & FE_ALL_EXCEPT); 225 __ldfpsr(__newfpsr); 226 return (~__oldfpsr & FE_ALL_EXCEPT); 227 } 228 229 static __inline int 230 fegetexcept(void) 231 { 232 fenv_t __fpsr; 233 234 __stfpsr(&__fpsr); 235 return (~__fpsr & FE_ALL_EXCEPT); 236 } 237 238 #endif /* __BSD_VISIBLE */ 239 240 __END_DECLS 241 242 #endif /* !_FENV_H_ */ 243