xref: /freebsd/lib/msun/arm/fenv.c (revision 7899f917b1c0ea178f1d2be0cfb452086d079d23)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2004 David Schultz <das@FreeBSD.ORG>
5  * Copyright (c) 2013 Andrew Turner <andrew@FreeBSD.ORG>
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 
30 #define	__fenv_static
31 #include "fenv.h"
32 
33 #include <machine/acle-compat.h>
34 
35 /* When SOFTFP_ABI is defined we are using the softfp ABI. */
36 #if defined(__VFP_FP__) && !defined(__ARM_PCS_VFP)
37 #define SOFTFP_ABI
38 #endif
39 
40 
41 #ifndef FENV_MANGLE
42 /*
43  * Hopefully the system ID byte is immutable, so it's valid to use
44  * this as a default environment.
45  */
46 const fenv_t __fe_dfl_env = 0;
47 #endif
48 
49 
50 /* If this is a non-mangled softfp version special processing is required */
51 #if defined(FENV_MANGLE) || !defined(SOFTFP_ABI)
52 
53 /*
54  * The following macros map between the softfloat emulator's flags and
55  * the hardware's FPSR.  The hardware this file was written for doesn't
56  * have rounding control bits, so we stick those in the system ID byte.
57  */
58 #ifndef __ARM_PCS_VFP
59 #define	__set_env(env, flags, mask, rnd) env = ((flags)			\
60 						| (mask)<<_FPUSW_SHIFT	\
61 						| (rnd) << 24)
62 #define	__env_flags(env)		((env) & FE_ALL_EXCEPT)
63 #define	__env_mask(env)			(((env) >> _FPUSW_SHIFT)	\
64 						& FE_ALL_EXCEPT)
65 #define	__env_round(env)		(((env) >> 24) & _ROUND_MASK)
66 #include "fenv-softfloat.h"
67 #endif
68 
69 #ifdef __GNUC_GNU_INLINE__
70 #error "This file must be compiled with C99 'inline' semantics"
71 #endif
72 
73 extern inline int feclearexcept(int __excepts);
74 extern inline int fegetexceptflag(fexcept_t *__flagp, int __excepts);
75 extern inline int fesetexceptflag(const fexcept_t *__flagp, int __excepts);
76 extern inline int feraiseexcept(int __excepts);
77 extern inline int fetestexcept(int __excepts);
78 extern inline int fegetround(void);
79 extern inline int fesetround(int __round);
80 extern inline int fegetenv(fenv_t *__envp);
81 extern inline int feholdexcept(fenv_t *__envp);
82 extern inline int fesetenv(const fenv_t *__envp);
83 extern inline int feupdateenv(const fenv_t *__envp);
84 extern inline int feenableexcept(int __mask);
85 extern inline int fedisableexcept(int __mask);
86 extern inline int fegetexcept(void);
87 
88 #else /* !FENV_MANGLE && SOFTFP_ABI */
89 /* Set by libc when the VFP unit is enabled */
90 extern int _libc_arm_fpu_present;
91 
92 int __softfp_feclearexcept(int __excepts);
93 int __softfp_fegetexceptflag(fexcept_t *__flagp, int __excepts);
94 int __softfp_fesetexceptflag(const fexcept_t *__flagp, int __excepts);
95 int __softfp_feraiseexcept(int __excepts);
96 int __softfp_fetestexcept(int __excepts);
97 int __softfp_fegetround(void);
98 int __softfp_fesetround(int __round);
99 int __softfp_fegetenv(fenv_t *__envp);
100 int __softfp_feholdexcept(fenv_t *__envp);
101 int __softfp_fesetenv(const fenv_t *__envp);
102 int __softfp_feupdateenv(const fenv_t *__envp);
103 int __softfp_feenableexcept(int __mask);
104 int __softfp_fedisableexcept(int __mask);
105 int __softfp_fegetexcept(void);
106 
107 int __vfp_feclearexcept(int __excepts);
108 int __vfp_fegetexceptflag(fexcept_t *__flagp, int __excepts);
109 int __vfp_fesetexceptflag(const fexcept_t *__flagp, int __excepts);
110 int __vfp_feraiseexcept(int __excepts);
111 int __vfp_fetestexcept(int __excepts);
112 int __vfp_fegetround(void);
113 int __vfp_fesetround(int __round);
114 int __vfp_fegetenv(fenv_t *__envp);
115 int __vfp_feholdexcept(fenv_t *__envp);
116 int __vfp_fesetenv(const fenv_t *__envp);
117 int __vfp_feupdateenv(const fenv_t *__envp);
118 int __vfp_feenableexcept(int __mask);
119 int __vfp_fedisableexcept(int __mask);
120 int __vfp_fegetexcept(void);
121 
122 static int
123 __softfp_round_to_vfp(int round)
124 {
125 
126 	switch (round) {
127 	case FE_TONEAREST:
128 	default:
129 		return VFP_FE_TONEAREST;
130 	case FE_TOWARDZERO:
131 		return VFP_FE_TOWARDZERO;
132 	case FE_UPWARD:
133 		return VFP_FE_UPWARD;
134 	case FE_DOWNWARD:
135 		return VFP_FE_DOWNWARD;
136 	}
137 }
138 
139 static int
140 __softfp_round_from_vfp(int round)
141 {
142 
143 	switch (round) {
144 	case VFP_FE_TONEAREST:
145 	default:
146 		return FE_TONEAREST;
147 	case VFP_FE_TOWARDZERO:
148 		return FE_TOWARDZERO;
149 	case VFP_FE_UPWARD:
150 		return FE_UPWARD;
151 	case VFP_FE_DOWNWARD:
152 		return FE_DOWNWARD;
153 	}
154 }
155 
156 int feclearexcept(int __excepts)
157 {
158 
159 	if (_libc_arm_fpu_present)
160 		__vfp_feclearexcept(__excepts);
161 	__softfp_feclearexcept(__excepts);
162 
163 	return (0);
164 }
165 
166 int fegetexceptflag(fexcept_t *__flagp, int __excepts)
167 {
168 	fexcept_t __vfp_flagp;
169 
170 	__vfp_flagp = 0;
171 	if (_libc_arm_fpu_present)
172 		__vfp_fegetexceptflag(&__vfp_flagp, __excepts);
173 	__softfp_fegetexceptflag(__flagp, __excepts);
174 
175 	*__flagp |= __vfp_flagp;
176 
177 	return (0);
178 }
179 
180 int fesetexceptflag(const fexcept_t *__flagp, int __excepts)
181 {
182 
183 	if (_libc_arm_fpu_present)
184 		__vfp_fesetexceptflag(__flagp, __excepts);
185 	__softfp_fesetexceptflag(__flagp, __excepts);
186 
187 	return (0);
188 }
189 
190 int feraiseexcept(int __excepts)
191 {
192 
193 	if (_libc_arm_fpu_present)
194 		__vfp_feraiseexcept(__excepts);
195 	__softfp_feraiseexcept(__excepts);
196 
197 	return (0);
198 }
199 
200 int fetestexcept(int __excepts)
201 {
202 	int __got_excepts;
203 
204 	__got_excepts = 0;
205 	if (_libc_arm_fpu_present)
206 		__got_excepts = __vfp_fetestexcept(__excepts);
207 	__got_excepts |= __softfp_fetestexcept(__excepts);
208 
209 	return (__got_excepts);
210 }
211 
212 int fegetround(void)
213 {
214 
215 	if (_libc_arm_fpu_present)
216 		return __softfp_round_from_vfp(__vfp_fegetround());
217 	return __softfp_fegetround();
218 }
219 
220 int fesetround(int __round)
221 {
222 
223 	if (_libc_arm_fpu_present)
224 		__vfp_fesetround(__softfp_round_to_vfp(__round));
225 	__softfp_fesetround(__round);
226 
227 	return (0);
228 }
229 
230 int fegetenv(fenv_t *__envp)
231 {
232 	fenv_t __vfp_envp;
233 
234 	__vfp_envp = 0;
235 	if (_libc_arm_fpu_present)
236 		__vfp_fegetenv(&__vfp_envp);
237 	__softfp_fegetenv(__envp);
238 	*__envp |= __vfp_envp;
239 
240 	return (0);
241 }
242 
243 int feholdexcept(fenv_t *__envp)
244 {
245 	fenv_t __vfp_envp;
246 
247 	__vfp_envp = 0;
248 	if (_libc_arm_fpu_present)
249 		__vfp_feholdexcept(&__vfp_envp);
250 	__softfp_feholdexcept(__envp);
251 	*__envp |= __vfp_envp;
252 
253 	return (0);
254 }
255 
256 int fesetenv(const fenv_t *__envp)
257 {
258 
259 	if (_libc_arm_fpu_present)
260 		__vfp_fesetenv(__envp);
261 	__softfp_fesetenv(__envp);
262 
263 	return (0);
264 }
265 
266 int feupdateenv(const fenv_t *__envp)
267 {
268 
269 	if (_libc_arm_fpu_present)
270 		__vfp_feupdateenv(__envp);
271 	__softfp_feupdateenv(__envp);
272 
273 	return (0);
274 }
275 
276 int feenableexcept(int __mask)
277 {
278 	int __unmasked;
279 
280 	__unmasked = 0;
281 	if (_libc_arm_fpu_present)
282 		__unmasked = __vfp_feenableexcept(__mask);
283 	__unmasked |= __softfp_feenableexcept(__mask);
284 
285 	return (__unmasked);
286 }
287 
288 int fedisableexcept(int __mask)
289 {
290 	int __unmasked;
291 
292 	__unmasked = 0;
293 	if (_libc_arm_fpu_present)
294 		__unmasked = __vfp_fedisableexcept(__mask);
295 	__unmasked |= __softfp_fedisableexcept(__mask);
296 
297 	return (__unmasked);
298 }
299 
300 int fegetexcept(void)
301 {
302 	int __unmasked;
303 
304 	__unmasked = 0;
305 	if (_libc_arm_fpu_present)
306 		__unmasked = __vfp_fegetexcept();
307 	__unmasked |= __softfp_fegetexcept();
308 
309 	return (__unmasked);
310 }
311 
312 #endif
313 
314