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 #elif defined(ARM_HARD_FLOAT) 73 #define __rfs(__fpsr) __asm __volatile("rfs %0" : "=r" (*(__fpsr))) 74 #define __wfs(__fpsr) __asm __volatile("wfs %0" : : "r" (__fpsr)) 75 #else 76 #define __rfs(__fpsr) 77 #define __wfs(__fpsr) 78 #endif 79 80 __fenv_static inline int 81 feclearexcept(int __excepts) 82 { 83 fexcept_t __fpsr; 84 85 __rfs(&__fpsr); 86 __fpsr &= ~__excepts; 87 __wfs(__fpsr); 88 return (0); 89 } 90 91 __fenv_static inline int 92 fegetexceptflag(fexcept_t *__flagp, int __excepts) 93 { 94 fexcept_t __fpsr; 95 96 __rfs(&__fpsr); 97 *__flagp = __fpsr & __excepts; 98 return (0); 99 } 100 101 __fenv_static inline int 102 fesetexceptflag(const fexcept_t *__flagp, int __excepts) 103 { 104 fexcept_t __fpsr; 105 106 __rfs(&__fpsr); 107 __fpsr &= ~__excepts; 108 __fpsr |= *__flagp & __excepts; 109 __wfs(__fpsr); 110 return (0); 111 } 112 113 __fenv_static inline int 114 feraiseexcept(int __excepts) 115 { 116 fexcept_t __ex = __excepts; 117 118 fesetexceptflag(&__ex, __excepts); /* XXX */ 119 return (0); 120 } 121 122 __fenv_static inline int 123 fetestexcept(int __excepts) 124 { 125 fexcept_t __fpsr; 126 127 __rfs(&__fpsr); 128 return (__fpsr & __excepts); 129 } 130 131 __fenv_static inline int 132 fegetround(void) 133 { 134 135 /* 136 * Apparently, the rounding mode is specified as part of the 137 * instruction format on ARM, so the dynamic rounding mode is 138 * indeterminate. Some FPUs may differ. 139 */ 140 return (-1); 141 } 142 143 __fenv_static inline int 144 fesetround(int __round) 145 { 146 147 return (-1); 148 } 149 150 __fenv_static inline int 151 fegetenv(fenv_t *__envp) 152 { 153 154 __rfs(__envp); 155 return (0); 156 } 157 158 __fenv_static inline int 159 feholdexcept(fenv_t *__envp) 160 { 161 fenv_t __env; 162 163 __rfs(&__env); 164 *__envp = __env; 165 __env &= ~(FE_ALL_EXCEPT | _ENABLE_MASK); 166 __wfs(__env); 167 return (0); 168 } 169 170 __fenv_static inline int 171 fesetenv(const fenv_t *__envp) 172 { 173 174 __wfs(*__envp); 175 return (0); 176 } 177 178 __fenv_static inline int 179 feupdateenv(const fenv_t *__envp) 180 { 181 fexcept_t __fpsr; 182 183 __rfs(&__fpsr); 184 __wfs(*__envp); 185 feraiseexcept(__fpsr & FE_ALL_EXCEPT); 186 return (0); 187 } 188 189 #if __BSD_VISIBLE 190 191 /* We currently provide no external definitions of the functions below. */ 192 193 static inline int 194 feenableexcept(int __mask) 195 { 196 fenv_t __old_fpsr, __new_fpsr; 197 198 __rfs(&__old_fpsr); 199 __new_fpsr = __old_fpsr | (__mask & FE_ALL_EXCEPT) << _FPUSW_SHIFT; 200 __wfs(__new_fpsr); 201 return ((__old_fpsr >> _FPUSW_SHIFT) & FE_ALL_EXCEPT); 202 } 203 204 static inline int 205 fedisableexcept(int __mask) 206 { 207 fenv_t __old_fpsr, __new_fpsr; 208 209 __rfs(&__old_fpsr); 210 __new_fpsr = __old_fpsr & ~((__mask & FE_ALL_EXCEPT) << _FPUSW_SHIFT); 211 __wfs(__new_fpsr); 212 return ((__old_fpsr >> _FPUSW_SHIFT) & FE_ALL_EXCEPT); 213 } 214 215 static inline int 216 fegetexcept(void) 217 { 218 fenv_t __fpsr; 219 220 __rfs(&__fpsr); 221 return ((__fpsr & _ENABLE_MASK) >> _FPUSW_SHIFT); 222 } 223 224 #endif /* __BSD_VISIBLE */ 225 226 __END_DECLS 227 228 #endif /* !_FENV_H_ */ 229