xref: /freebsd/lib/msun/arm/fenv.c (revision 5bf5ca772c6de2d53344a78cf461447cc322ccea)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
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  * $FreeBSD$
30  */
31 
32 #define	__fenv_static
33 #include "fenv.h"
34 
35 #include <machine/acle-compat.h>
36 
37 #if __ARM_ARCH >= 6
38 #define FENV_ARMv6
39 #endif
40 
41 /* When SOFTFP_ABI is defined we are using the softfp ABI. */
42 #if defined(__VFP_FP__) && !defined(__ARM_PCS_VFP)
43 #define SOFTFP_ABI
44 #endif
45 
46 
47 #ifndef FENV_MANGLE
48 /*
49  * Hopefully the system ID byte is immutable, so it's valid to use
50  * this as a default environment.
51  */
52 const fenv_t __fe_dfl_env = 0;
53 #endif
54 
55 
56 /* If this is a non-mangled softfp version special processing is required */
57 #if defined(FENV_MANGLE) || !defined(SOFTFP_ABI) || !defined(FENV_ARMv6)
58 
59 /*
60  * The following macros map between the softfloat emulator's flags and
61  * the hardware's FPSR.  The hardware this file was written for doesn't
62  * have rounding control bits, so we stick those in the system ID byte.
63  */
64 #ifndef __ARM_PCS_VFP
65 #define	__set_env(env, flags, mask, rnd) env = ((flags)			\
66 						| (mask)<<_FPUSW_SHIFT	\
67 						| (rnd) << 24)
68 #define	__env_flags(env)		((env) & FE_ALL_EXCEPT)
69 #define	__env_mask(env)			(((env) >> _FPUSW_SHIFT)	\
70 						& FE_ALL_EXCEPT)
71 #define	__env_round(env)		(((env) >> 24) & _ROUND_MASK)
72 #include "fenv-softfloat.h"
73 #endif
74 
75 #ifdef __GNUC_GNU_INLINE__
76 #error "This file must be compiled with C99 'inline' semantics"
77 #endif
78 
79 extern inline int feclearexcept(int __excepts);
80 extern inline int fegetexceptflag(fexcept_t *__flagp, int __excepts);
81 extern inline int fesetexceptflag(const fexcept_t *__flagp, int __excepts);
82 extern inline int feraiseexcept(int __excepts);
83 extern inline int fetestexcept(int __excepts);
84 extern inline int fegetround(void);
85 extern inline int fesetround(int __round);
86 extern inline int fegetenv(fenv_t *__envp);
87 extern inline int feholdexcept(fenv_t *__envp);
88 extern inline int fesetenv(const fenv_t *__envp);
89 extern inline int feupdateenv(const fenv_t *__envp);
90 extern inline int feenableexcept(int __mask);
91 extern inline int fedisableexcept(int __mask);
92 extern inline int fegetexcept(void);
93 
94 #else /* !FENV_MANGLE && SOFTFP_ABI */
95 /* Set by libc when the VFP unit is enabled */
96 extern int _libc_arm_fpu_present;
97 
98 int __softfp_feclearexcept(int __excepts);
99 int __softfp_fegetexceptflag(fexcept_t *__flagp, int __excepts);
100 int __softfp_fesetexceptflag(const fexcept_t *__flagp, int __excepts);
101 int __softfp_feraiseexcept(int __excepts);
102 int __softfp_fetestexcept(int __excepts);
103 int __softfp_fegetround(void);
104 int __softfp_fesetround(int __round);
105 int __softfp_fegetenv(fenv_t *__envp);
106 int __softfp_feholdexcept(fenv_t *__envp);
107 int __softfp_fesetenv(const fenv_t *__envp);
108 int __softfp_feupdateenv(const fenv_t *__envp);
109 int __softfp_feenableexcept(int __mask);
110 int __softfp_fedisableexcept(int __mask);
111 int __softfp_fegetexcept(void);
112 
113 int __vfp_feclearexcept(int __excepts);
114 int __vfp_fegetexceptflag(fexcept_t *__flagp, int __excepts);
115 int __vfp_fesetexceptflag(const fexcept_t *__flagp, int __excepts);
116 int __vfp_feraiseexcept(int __excepts);
117 int __vfp_fetestexcept(int __excepts);
118 int __vfp_fegetround(void);
119 int __vfp_fesetround(int __round);
120 int __vfp_fegetenv(fenv_t *__envp);
121 int __vfp_feholdexcept(fenv_t *__envp);
122 int __vfp_fesetenv(const fenv_t *__envp);
123 int __vfp_feupdateenv(const fenv_t *__envp);
124 int __vfp_feenableexcept(int __mask);
125 int __vfp_fedisableexcept(int __mask);
126 int __vfp_fegetexcept(void);
127 
128 static int
129 __softfp_round_to_vfp(int round)
130 {
131 
132 	switch (round) {
133 	case FE_TONEAREST:
134 	default:
135 		return VFP_FE_TONEAREST;
136 	case FE_TOWARDZERO:
137 		return VFP_FE_TOWARDZERO;
138 	case FE_UPWARD:
139 		return VFP_FE_UPWARD;
140 	case FE_DOWNWARD:
141 		return VFP_FE_DOWNWARD;
142 	}
143 }
144 
145 static int
146 __softfp_round_from_vfp(int round)
147 {
148 
149 	switch (round) {
150 	case VFP_FE_TONEAREST:
151 	default:
152 		return FE_TONEAREST;
153 	case VFP_FE_TOWARDZERO:
154 		return FE_TOWARDZERO;
155 	case VFP_FE_UPWARD:
156 		return FE_UPWARD;
157 	case VFP_FE_DOWNWARD:
158 		return FE_DOWNWARD;
159 	}
160 }
161 
162 int feclearexcept(int __excepts)
163 {
164 
165 	if (_libc_arm_fpu_present)
166 		__vfp_feclearexcept(__excepts);
167 	__softfp_feclearexcept(__excepts);
168 
169 	return (0);
170 }
171 
172 int fegetexceptflag(fexcept_t *__flagp, int __excepts)
173 {
174 	fexcept_t __vfp_flagp;
175 
176 	__vfp_flagp = 0;
177 	if (_libc_arm_fpu_present)
178 		__vfp_fegetexceptflag(&__vfp_flagp, __excepts);
179 	__softfp_fegetexceptflag(__flagp, __excepts);
180 
181 	*__flagp |= __vfp_flagp;
182 
183 	return (0);
184 }
185 
186 int fesetexceptflag(const fexcept_t *__flagp, int __excepts)
187 {
188 
189 	if (_libc_arm_fpu_present)
190 		__vfp_fesetexceptflag(__flagp, __excepts);
191 	__softfp_fesetexceptflag(__flagp, __excepts);
192 
193 	return (0);
194 }
195 
196 int feraiseexcept(int __excepts)
197 {
198 
199 	if (_libc_arm_fpu_present)
200 		__vfp_feraiseexcept(__excepts);
201 	__softfp_feraiseexcept(__excepts);
202 
203 	return (0);
204 }
205 
206 int fetestexcept(int __excepts)
207 {
208 	int __got_excepts;
209 
210 	__got_excepts = 0;
211 	if (_libc_arm_fpu_present)
212 		__got_excepts = __vfp_fetestexcept(__excepts);
213 	__got_excepts |= __softfp_fetestexcept(__excepts);
214 
215 	return (__got_excepts);
216 }
217 
218 int fegetround(void)
219 {
220 
221 	if (_libc_arm_fpu_present)
222 		return __softfp_round_from_vfp(__vfp_fegetround());
223 	return __softfp_fegetround();
224 }
225 
226 int fesetround(int __round)
227 {
228 
229 	if (_libc_arm_fpu_present)
230 		__vfp_fesetround(__softfp_round_to_vfp(__round));
231 	__softfp_fesetround(__round);
232 
233 	return (0);
234 }
235 
236 int fegetenv(fenv_t *__envp)
237 {
238 	fenv_t __vfp_envp;
239 
240 	__vfp_envp = 0;
241 	if (_libc_arm_fpu_present)
242 		__vfp_fegetenv(&__vfp_envp);
243 	__softfp_fegetenv(__envp);
244 	*__envp |= __vfp_envp;
245 
246 	return (0);
247 }
248 
249 int feholdexcept(fenv_t *__envp)
250 {
251 	fenv_t __vfp_envp;
252 
253 	__vfp_envp = 0;
254 	if (_libc_arm_fpu_present)
255 		__vfp_feholdexcept(&__vfp_envp);
256 	__softfp_feholdexcept(__envp);
257 	*__envp |= __vfp_envp;
258 
259 	return (0);
260 }
261 
262 int fesetenv(const fenv_t *__envp)
263 {
264 
265 	if (_libc_arm_fpu_present)
266 		__vfp_fesetenv(__envp);
267 	__softfp_fesetenv(__envp);
268 
269 	return (0);
270 }
271 
272 int feupdateenv(const fenv_t *__envp)
273 {
274 
275 	if (_libc_arm_fpu_present)
276 		__vfp_feupdateenv(__envp);
277 	__softfp_feupdateenv(__envp);
278 
279 	return (0);
280 }
281 
282 int feenableexcept(int __mask)
283 {
284 	int __unmasked;
285 
286 	__unmasked = 0;
287 	if (_libc_arm_fpu_present)
288 		__unmasked = __vfp_feenableexcept(__mask);
289 	__unmasked |= __softfp_feenableexcept(__mask);
290 
291 	return (__unmasked);
292 }
293 
294 int fedisableexcept(int __mask)
295 {
296 	int __unmasked;
297 
298 	__unmasked = 0;
299 	if (_libc_arm_fpu_present)
300 		__unmasked = __vfp_fedisableexcept(__mask);
301 	__unmasked |= __softfp_fedisableexcept(__mask);
302 
303 	return (__unmasked);
304 }
305 
306 int fegetexcept(void)
307 {
308 	int __unmasked;
309 
310 	__unmasked = 0;
311 	if (_libc_arm_fpu_present)
312 		__unmasked = __vfp_fegetexcept();
313 	__unmasked |= __softfp_fegetexcept();
314 
315 	return (__unmasked);
316 }
317 
318 #endif
319 
320