xref: /openbsd/lib/libm/arch/aarch64/fenv.c (revision 2c53affb)
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