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