1 /* $OpenBSD: fenv.c,v 1.6 2022/12/27 17:10:07 jmc 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 __mrs_fpcr(r) __asm volatile("mrs %x0, fpcr" : "=r" (r))
38 #define __msr_fpcr(r) __asm volatile("msr fpcr, %x0" : : "r" (r))
39
40 #define __mrs_fpsr(r) __asm volatile("mrs %x0, fpsr" : "=r" (r))
41 #define __msr_fpsr(r) __asm volatile("msr fpsr, %x0" : : "r" (r))
42
43 /*
44 * The following constant represents the default floating-point environment
45 * (that is, the one installed at program startup) and has type pointer to
46 * const-qualified fenv_t.
47 *
48 * It can be used as an argument to the functions within the <fenv.h> header
49 * that manage the floating-point environment, namely fesetenv() and
50 * feupdateenv().
51 */
52 fenv_t __fe_dfl_env = 0;
53
54 /*
55 * The feclearexcept() function clears the supported floating-point exceptions
56 * represented by `excepts'.
57 */
58 int
feclearexcept(int excepts)59 feclearexcept(int excepts)
60 {
61 fexcept_t r;
62
63 excepts &= FE_ALL_EXCEPT;
64 __mrs_fpsr(r);
65 r &= ~excepts;
66 __msr_fpsr(r);
67 return (0);
68 }
69 DEF_STD(feclearexcept);
70
71 /*
72 * The fegetexceptflag() function stores an implementation-defined
73 * representation of the states of the floating-point status flags indicated by
74 * the argument excepts in the object pointed to by the argument flagp.
75 */
76 int
fegetexceptflag(fexcept_t * flagp,int excepts)77 fegetexceptflag(fexcept_t *flagp, int excepts)
78 {
79 fexcept_t r;
80
81 excepts &= FE_ALL_EXCEPT;
82 __mrs_fpsr(r);
83 *flagp = r & excepts;
84 return (0);
85 }
86
87 /*
88 * The feraiseexcept() function raises the supported floating-point exceptions
89 * represented by the argument `excepts'.
90 */
91 int
feraiseexcept(int excepts)92 feraiseexcept(int excepts)
93 {
94 fexcept_t r;
95
96 excepts &= FE_ALL_EXCEPT;
97 __mrs_fpsr(r);
98 r |= excepts;
99 __msr_fpsr(r);
100 return (0);
101 }
102 DEF_STD(feraiseexcept);
103
104 /*
105 * This function sets the floating-point status flags indicated by the argument
106 * `excepts' to the states stored in the object pointed to by `flagp'. It does
107 * NOT raise any floating-point exceptions, but only sets the state of the flags.
108 */
109 int
fesetexceptflag(const fexcept_t * flagp,int excepts)110 fesetexceptflag(const fexcept_t *flagp, int excepts)
111 {
112 fexcept_t r;
113
114 excepts &= FE_ALL_EXCEPT;
115 __mrs_fpsr(r);
116 r &= ~excepts;
117 r |= *flagp & excepts;
118 __msr_fpsr(r);
119 return (0);
120 }
121 DEF_STD(fesetexceptflag);
122
123 /*
124 * The fetestexcept() function determines which of a specified subset of the
125 * floating-point exception flags are currently set. The `excepts' argument
126 * specifies the floating-point status flags to be queried.
127 */
128 int
fetestexcept(int excepts)129 fetestexcept(int excepts)
130 {
131 fexcept_t r;
132
133 excepts &= FE_ALL_EXCEPT;
134 __mrs_fpsr(r);
135 return (r & excepts);
136 }
137 DEF_STD(fetestexcept);
138
139 /*
140 * The fegetround() function gets the current rounding direction.
141 */
142 int
fegetround(void)143 fegetround(void)
144 {
145 fenv_t r;
146
147 __mrs_fpcr(r);
148 return ((r >> _ROUND_SHIFT) & _ROUND_MASK);
149 }
150 DEF_STD(fegetround);
151
152 /*
153 * The fesetround() function establishes the rounding direction represented by
154 * its argument `round'. If the argument is not equal to the value of a rounding
155 * direction macro, the rounding direction is not changed.
156 */
157 int
fesetround(int round)158 fesetround(int round)
159 {
160 fenv_t r;
161
162 if (round & ~_ROUND_MASK)
163 return (-1);
164 __mrs_fpcr(r);
165 r &= ~(_ROUND_MASK << _ROUND_SHIFT);
166 r |= round << _ROUND_SHIFT;
167 __msr_fpcr(r);
168 return (0);
169 }
170 DEF_STD(fesetround);
171
172 /*
173 * The fegetenv() function attempts to store the current floating-point
174 * environment in the object pointed to by envp.
175 */
176 int
fegetenv(fenv_t * envp)177 fegetenv(fenv_t *envp)
178 {
179 fenv_t r;
180
181 __mrs_fpcr(r);
182 *envp = r;
183
184 __mrs_fpsr(r);
185 *envp |= (r << 32);
186
187 return (0);
188 }
189 DEF_STD(fegetenv);
190
191 /*
192 * The feholdexcept() function saves the current floating-point environment
193 * in the object pointed to by envp, clears the floating-point status flags, and
194 * then installs a non-stop (continue on floating-point exceptions) mode, if
195 * available, for all floating-point exceptions.
196 */
197 int
feholdexcept(fenv_t * envp)198 feholdexcept(fenv_t *envp)
199 {
200 fenv_t r;
201
202 __mrs_fpcr(r);
203 *envp = r;
204 r &= ~_ENABLE_MASK;
205 __msr_fpcr(r);
206
207 __mrs_fpsr(r);
208 *envp |= (r << 32);
209 r &= ~FE_ALL_EXCEPT;
210 __msr_fpsr(r);
211 return (0);
212 }
213 DEF_STD(feholdexcept);
214
215 /*
216 * The fesetenv() function attempts to establish the floating-point environment
217 * represented by the object pointed to by envp. The argument `envp' points
218 * to an object set by a call to fegetenv() or feholdexcept(), or equal a
219 * floating-point environment macro. The fesetenv() function does not raise
220 * floating-point exceptions, but only installs the state of the floating-point
221 * status flags represented through its argument.
222 */
223 int
fesetenv(const fenv_t * envp)224 fesetenv(const fenv_t *envp)
225 {
226
227 __msr_fpcr(*envp & 0xffffffff);
228 __msr_fpsr(*envp >> 32);
229 return (0);
230 }
231 DEF_STD(fesetenv);
232
233 /*
234 * The feupdateenv() function saves the currently raised floating-point
235 * exceptions in its automatic storage, installs the floating-point environment
236 * represented by the object pointed to by `envp', and then raises the saved
237 * floating-point exceptions. The argument `envp' shall point to an object set
238 * by a call to feholdexcept() or fegetenv(), or equal a floating-point
239 * environment macro.
240 */
241 int
feupdateenv(const fenv_t * envp)242 feupdateenv(const fenv_t *envp)
243 {
244 fexcept_t r;
245
246 __mrs_fpsr(r);
247 fesetenv(envp);
248 feraiseexcept(r & FE_ALL_EXCEPT);
249 return (0);
250 }
251 DEF_STD(feupdateenv);
252
253 /*
254 * The following functions are extensions to the standard
255 */
256 int
feenableexcept(int mask)257 feenableexcept(int mask)
258 {
259 return -1;
260 }
261
262 int
fedisableexcept(int mask)263 fedisableexcept(int mask)
264 {
265 return 0;
266 }
267
268 int
fegetexcept(void)269 fegetexcept(void)
270 {
271 return 0;
272 }
273