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