1/*- 2 * Copyright (c) 2004-2005 David Schultz <das@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$ 27 */ 28 29#ifndef _FENV_H_ 30#define _FENV_H_ 31 32#include <sys/_types.h> 33 34typedef __uint64_t fenv_t; 35typedef __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 */ 58extern 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 66static __inline int 67feclearexcept(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 77static __inline int 78fegetexceptflag(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 87static __inline int 88fesetexceptflag(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 */ 106static __inline int 107feraiseexcept(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 141static __inline int 142fetestexcept(int __excepts) 143{ 144 fenv_t __fpsr; 145 146 __stfpsr(&__fpsr); 147 return ((__fpsr >> _FPUSW_SHIFT) & __excepts); 148} 149 150 151static __inline int 152fegetround(void) 153{ 154 fenv_t __fpsr; 155 156 __stfpsr(&__fpsr); 157 return (__fpsr & _ROUND_MASK); 158} 159 160static __inline int 161fesetround(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 174static __inline int 175fegetenv(fenv_t *__envp) 176{ 177 178 __stfpsr(__envp); 179 return (0); 180} 181 182static __inline int 183feholdexcept(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 195static __inline int 196fesetenv(const fenv_t *__envp) 197{ 198 199 __ldfpsr(*__envp); 200 return (0); 201} 202 203int feupdateenv(const fenv_t *__envp); 204 205#if __BSD_VISIBLE 206 207static __inline int 208feenableexcept(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 218static __inline int 219fedisableexcept(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 229static __inline int 230fegetexcept(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