1 /* $OpenBSD: fenv.c,v 1.1 2021/04/27 00:31:34 drahn Exp $ */ 2 /*- 3 * Copyright (c) 2004-2005 David Schultz <das@FreeBSD.ORG> 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 * $FreeBSD: head/lib/msun/aarch64/fenv.h 280857 2015-03-30 16:42:08Z emaste $ 28 */ 29 30 #include <fenv.h> 31 #include <machine/ieeefp.h> 32 33 /* We need to be able to map status flag positions to mask flag positions */ 34 #define _FPUSW_SHIFT 8 35 #define _ENABLE_MASK (FE_ALL_EXCEPT << _FPUSW_SHIFT) 36 37 #define __get_fcsr(r) asm volatile("frcsr %0" : "=r" (r)) 38 #define __set_fcsr(r) asm volatile("fscsr %0" : "+r" (r)) 39 #define __get_flags(r) asm volatile("frflags %0" : "=r" (r)) 40 #define __set_flags(r) asm volatile("fsflags %0" : "+r" (r)) 41 #define __get_frm(r) asm volatile("frrm %0" : "=r" (r)) 42 #define __set_frm(r) asm volatile("fsrm %0" : "+r"(r) ) 43 44 /* 45 * The following constant represents the default floating-point environment 46 * (that is, the one installed at program startup) and has type pointer to 47 * const-qualified fenv_t. 48 * 49 * It can be used as an argument to the functions within the <fenv.h> header 50 * that manage the floating-point environment, namely fesetenv() and 51 * feupdateenv(). 52 */ 53 fenv_t __fe_dfl_env = 0; 54 55 /* 56 * The feclearexcept() function clears the supported floating-point exceptions 57 * represented by `excepts'. 58 */ 59 int 60 feclearexcept(int excepts) 61 { 62 fexcept_t r; 63 64 excepts &= FE_ALL_EXCEPT; 65 __get_flags(r); 66 r &= ~excepts; 67 __set_flags(r); 68 return (0); 69 } 70 DEF_STD(feclearexcept); 71 72 /* 73 * The fegetexceptflag() function stores an implementation-defined 74 * representation of the states of the floating-point status flags indicated by 75 * the argument excepts in the object pointed to by the argument flagp. 76 */ 77 int 78 fegetexceptflag(fexcept_t *flagp, int excepts) 79 { 80 fexcept_t r; 81 82 excepts &= FE_ALL_EXCEPT; 83 __get_flags(r); 84 *flagp = r & excepts; 85 return (0); 86 } 87 88 /* 89 * The feraiseexcept() function raises the supported floating-point exceptions 90 * represented by the argument `excepts'. 91 */ 92 int 93 feraiseexcept(int excepts) 94 { 95 fexcept_t r; 96 97 excepts &= FE_ALL_EXCEPT; 98 __get_flags(r); 99 r |= excepts; 100 __set_flags(r); 101 return (0); 102 } 103 DEF_STD(feraiseexcept); 104 105 /* 106 * This function sets the floating-point status flags indicated by the argument 107 * `excepts' to the states stored in the object pointed to by `flagp'. It does 108 * NOT raise any floating-point exceptions, but only sets the state of the flags. 109 */ 110 int 111 fesetexceptflag(const fexcept_t *flagp, int excepts) 112 { 113 fexcept_t r; 114 115 excepts &= FE_ALL_EXCEPT; 116 __get_flags(r); 117 r &= ~excepts; 118 r |= *flagp & excepts; 119 __set_flags(r); 120 return (0); 121 } 122 DEF_STD(fesetexceptflag); 123 124 /* 125 * The fetestexcept() function determines which of a specified subset of the 126 * floating-point exception flags are currently set. The `excepts' argument 127 * specifies the floating-point status flags to be queried. 128 */ 129 int 130 fetestexcept(int excepts) 131 { 132 fexcept_t r; 133 134 excepts &= FE_ALL_EXCEPT; 135 __get_flags(r); 136 return (r & excepts); 137 } 138 DEF_STD(fetestexcept); 139 140 /* 141 * The fegetround() function gets the current rounding direction. 142 */ 143 int 144 fegetround(void) 145 { 146 fenv_t r; 147 148 __get_frm(r); 149 return ((r >> _ROUND_SHIFT) & _ROUND_MASK); 150 } 151 DEF_STD(fegetround); 152 153 /* 154 * The fesetround() function establishes the rounding direction represented by 155 * its argument `round'. If the argument is not equal to the value of a rounding 156 * direction macro, the rounding direction is not changed. 157 */ 158 int 159 fesetround(int round) 160 { 161 fenv_t r; 162 163 if (round & ~_ROUND_MASK) 164 return (-1); 165 __set_frm(round); 166 return (0); 167 } 168 DEF_STD(fesetround); 169 170 /* 171 * The fegetenv() function attempts to store the current floating-point 172 * environment in the object pointed to by envp. 173 */ 174 int 175 fegetenv(fenv_t *envp) 176 { 177 fenv_t r; 178 179 __get_fcsr(r); 180 *envp = r; 181 182 return (0); 183 } 184 DEF_STD(fegetenv); 185 186 /* 187 * The feholdexcept() function saves the current floating-point environment 188 * in the object pointed to by envp, clears the floating-point status flags, and 189 * then installs a non-stop (continue on floating-point exceptions) mode, if 190 * available, for all floating-point exceptions. 191 */ 192 int 193 feholdexcept(fenv_t *envp) 194 { 195 fenv_t r; 196 197 __get_fcsr(r); 198 *envp = r; 199 r &= ~_ROUND_MASK; 200 __set_fcsr(r); 201 202 return (0); 203 } 204 DEF_STD(feholdexcept); 205 206 /* 207 * The fesetenv() function attempts to establish the floating-point environment 208 * represented by the object pointed to by envp. The argument `envp' points 209 * to an object set by a call to fegetenv() or feholdexcept(), or equal a 210 * floating-point environment macro. The fesetenv() function does not raise 211 * floating-point exceptions, but only installs the state of the floating-point 212 * status flags represented through its argument. 213 */ 214 int 215 fesetenv(const fenv_t *envp) 216 { 217 218 fenv_t r; 219 r = *envp; 220 __set_fcsr(r); 221 return (0); 222 } 223 DEF_STD(fesetenv); 224 225 /* 226 * The feupdateenv() function saves the currently raised floating-point 227 * exceptions in its automatic storage, installs the floating-point environment 228 * represented by the object pointed to by `envp', and then raises the saved 229 * floating-point exceptions. The argument `envp' shall point to an object set 230 * by a call to feholdexcept() or fegetenv(), or equal a floating-point 231 * environment macro. 232 */ 233 int 234 feupdateenv(const fenv_t *envp) 235 { 236 fexcept_t r; 237 238 __get_fcsr(r); 239 fesetenv(envp); 240 feraiseexcept(r & FE_ALL_EXCEPT); 241 return (0); 242 } 243 DEF_STD(feupdateenv); 244 245 /* 246 * The following functions are extentions to the standard 247 */ 248 int 249 feenableexcept(int mask) 250 { 251 return -1; 252 } 253 254 int 255 fedisableexcept(int mask) 256 { 257 return 0; 258 } 259 260 int 261 fegetexcept(void) 262 { 263 return 0; 264 } 265