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: src/lib/msun/arm/fenv.h,v 1.6 2011/10/10 15:43:09 das Exp $ 27 */ 28 29 #ifndef _FENV_H_ 30 #define _FENV_H_ 31 32 #include <stdint.h> 33 34 #include "cdefs-compat.h" 35 36 #ifndef __fenv_static 37 #define __fenv_static static 38 #endif 39 40 typedef uint32_t fenv_t; 41 typedef uint32_t fexcept_t; 42 43 /* Exception flags */ 44 #define FE_INVALID 0x0001 45 #define FE_DIVBYZERO 0x0002 46 #define FE_OVERFLOW 0x0004 47 #define FE_UNDERFLOW 0x0008 48 #define FE_INEXACT 0x0010 49 #define FE_ALL_EXCEPT (FE_DIVBYZERO | FE_INEXACT | \ 50 FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW) 51 52 /* Rounding modes */ 53 #define FE_TONEAREST 0x0000 54 #define FE_TOWARDZERO 0x0001 55 #define FE_UPWARD 0x0002 56 #define FE_DOWNWARD 0x0003 57 #define _ROUND_MASK (FE_TONEAREST | FE_DOWNWARD | \ 58 FE_UPWARD | FE_TOWARDZERO) 59 __BEGIN_DECLS 60 61 /* Default floating-point environment */ 62 extern const fenv_t __fe_dfl_env; 63 #define FE_DFL_ENV (&__fe_dfl_env) 64 65 /* We need to be able to map status flag positions to mask flag positions */ 66 #define _FPUSW_SHIFT 16 67 #define _ENABLE_MASK (FE_ALL_EXCEPT << _FPUSW_SHIFT) 68 69 #if defined(__aarch64__) 70 #define __rfs(__fpsr) __asm __volatile("mrs %0,fpsr" : "=r" (*(__fpsr))) 71 #define __wfs(__fpsr) __asm __volatile("msr fpsr,%0" : : "r" (__fpsr)) 72 /* Test for hardware support for ARM floating point operations, explicitly 73 checking for float and double support, see "ARM C Language Extensions", 6.5.1 */ 74 #elif defined(__ARM_FP) && (__ARM_FP & 0x0C) != 0 75 #define __rfs(__fpsr) __asm __volatile("vmrs %0,fpscr" : "=&r" (*(__fpsr))) 76 #define __wfs(__fpsr) __asm __volatile("vmsr fpscr,%0" : : "r" (__fpsr)) 77 #else 78 #define __rfs(__fpsr) (*(__fpsr) = 0) 79 #define __wfs(__fpsr) 80 #endif 81 82 __fenv_static inline int 83 feclearexcept(int __excepts) 84 { 85 fexcept_t __fpsr; 86 87 __rfs(&__fpsr); 88 __fpsr &= ~__excepts; 89 __wfs(__fpsr); 90 return (0); 91 } 92 93 __fenv_static inline int 94 fegetexceptflag(fexcept_t *__flagp, int __excepts) 95 { 96 fexcept_t __fpsr; 97 98 __rfs(&__fpsr); 99 *__flagp = __fpsr & __excepts; 100 return (0); 101 } 102 103 __fenv_static inline int 104 fesetexceptflag(const fexcept_t *__flagp, int __excepts) 105 { 106 fexcept_t __fpsr; 107 108 __rfs(&__fpsr); 109 __fpsr &= ~__excepts; 110 __fpsr |= *__flagp & __excepts; 111 __wfs(__fpsr); 112 return (0); 113 } 114 115 __fenv_static inline int 116 feraiseexcept(int __excepts) 117 { 118 fexcept_t __ex = __excepts; 119 120 fesetexceptflag(&__ex, __excepts); /* XXX */ 121 return (0); 122 } 123 124 __fenv_static inline int 125 fetestexcept(int __excepts) 126 { 127 fexcept_t __fpsr; 128 129 __rfs(&__fpsr); 130 return (__fpsr & __excepts); 131 } 132 133 __fenv_static inline int 134 fegetround(void) 135 { 136 137 /* 138 * Apparently, the rounding mode is specified as part of the 139 * instruction format on ARM, so the dynamic rounding mode is 140 * indeterminate. Some FPUs may differ. 141 */ 142 return (-1); 143 } 144 145 __fenv_static inline int 146 fesetround(int __round) 147 { 148 149 return (-1); 150 } 151 152 __fenv_static inline int 153 fegetenv(fenv_t *__envp) 154 { 155 156 __rfs(__envp); 157 return (0); 158 } 159 160 __fenv_static inline int 161 feholdexcept(fenv_t *__envp) 162 { 163 fenv_t __env; 164 165 __rfs(&__env); 166 *__envp = __env; 167 __env &= ~(FE_ALL_EXCEPT | _ENABLE_MASK); 168 __wfs(__env); 169 return (0); 170 } 171 172 __fenv_static inline int 173 fesetenv(const fenv_t *__envp) 174 { 175 176 __wfs(*__envp); 177 return (0); 178 } 179 180 __fenv_static inline int 181 feupdateenv(const fenv_t *__envp) 182 { 183 fexcept_t __fpsr; 184 185 __rfs(&__fpsr); 186 __wfs(*__envp); 187 feraiseexcept(__fpsr & FE_ALL_EXCEPT); 188 return (0); 189 } 190 191 #if __BSD_VISIBLE 192 193 /* We currently provide no external definitions of the functions below. */ 194 195 static inline int 196 feenableexcept(int __mask) 197 { 198 fenv_t __old_fpsr, __new_fpsr; 199 200 __rfs(&__old_fpsr); 201 __new_fpsr = __old_fpsr | (__mask & FE_ALL_EXCEPT) << _FPUSW_SHIFT; 202 __wfs(__new_fpsr); 203 return ((__old_fpsr >> _FPUSW_SHIFT) & FE_ALL_EXCEPT); 204 } 205 206 static inline int 207 fedisableexcept(int __mask) 208 { 209 fenv_t __old_fpsr, __new_fpsr; 210 211 __rfs(&__old_fpsr); 212 __new_fpsr = __old_fpsr & ~((__mask & FE_ALL_EXCEPT) << _FPUSW_SHIFT); 213 __wfs(__new_fpsr); 214 return ((__old_fpsr >> _FPUSW_SHIFT) & FE_ALL_EXCEPT); 215 } 216 217 static inline int 218 fegetexcept(void) 219 { 220 fenv_t __fpsr; 221 222 __rfs(&__fpsr); 223 return ((__fpsr & _ENABLE_MASK) >> _FPUSW_SHIFT); 224 } 225 226 #endif /* __BSD_VISIBLE */ 227 228 __END_DECLS 229 230 #endif /* !_FENV_H_ */ 231