this repo has no description
1/*
2 * fenv.c
3 * cLibm
4 *
5 * Created by Ian Ollmann on 7/15/07.
6 * Copyright 2007 Apple Inc. All rights reserved.
7 *
8 * A partial implementation for Intel is provided here for testing purposes.
9 * You'll need to provide a full implementation for your platform of choice.
10 *
11 */
12
13#if defined(ARMLIBM_FENV_SUPPORT)
14
15#include "fenv.h"
16#include <stdint.h>
17#include "required_arithmetic.h"
18
19#define FE_ALL_RND ( FE_TONEAREST | FE_TOWARDZERO | FE_UPWARD | FE_DOWNWARD )
20
21#if defined( __GNUC__ )
22 #define ALWAYS_INLINE __attribute__ ((__always_inline__))
23#else
24 #define ALWAYS_INLINE
25#endif
26
27#ifndef __arm__
28 #error This file is for use on ARM + VFP and later
29#endif
30
31
32#define GET_FPSCR() ({ uint32_t _fpscr; __asm__ __volatile__( "fmrx %0, fpscr" : "=r" (_fpscr) ); /* return */ _fpscr; })
33#define SET_FPSCR(_fpscr) __asm__ __volatile__( "fmxr fpscr, %0" : : "r" (_fpscr) )
34
35
36const fenv_t _FE_DFL_ENV = {{{ 0, 0, 0, 0 }}};
37// Worker functions for making sure that much of the work is done in a uniform way
38
39// For each bit set in excepts, change the floating point state to match the correspinding bit in *flagp
40static inline int _fesetexceptflag_private(const fexcept_t *flagp, int excepts ) ALWAYS_INLINE;
41static inline int _fesetexceptflag_private(const fexcept_t *flagp, int excepts )
42{
43 uint32_t fpscr = GET_FPSCR();
44
45 excepts &= FE_ALL_EXCEPT | 0x8000;
46
47 fpscr &= ~excepts;
48 fpscr |= *flagp & excepts;
49
50 SET_FPSCR( fpscr );
51
52 return 0;
53}
54
55// For each bit set in excepts, copy the corresponding bit from the floating point state into *flagp
56// All other bits shall be set to zero
57static inline int _fegetexceptflag_private(fexcept_t *flagp, int excepts);
58static inline int _fegetexceptflag_private(fexcept_t *flagp, int excepts)
59{
60 uint32_t fpscr = GET_FPSCR();
61
62 *flagp = fpscr & excepts;
63
64 return 0;
65}
66
67
68
69/*******************************************************************************
70* The function "feclearexcept" clears the supported floating point *
71* exceptions represented by its argument. *
72*******************************************************************************/
73
74int feclearexcept(int excepts)
75{
76 fexcept_t zero = 0;
77 return _fesetexceptflag_private( &zero, excepts );
78}
79
80
81
82/*******************************************************************************
83* The function "feraiseexcept" raises the supported floating-point *
84* exceptions represented by its argument. The order in which these *
85* floating-point exceptions are raised is unspecified. *
86*******************************************************************************/
87
88int feraiseexcept(int excepts)
89{
90 int inexact_set = 0;
91
92 if( excepts & FE_OVERFLOW )
93 {
94 required_add_float( 0x1.0p127f, 0x1.0p127f );
95 inexact_set = 1;
96 }
97 if( excepts & FE_UNDERFLOW )
98 {
99 required_multiply_float( 0x1.0p-126f, 0x1.0p-126f );
100 inexact_set = 1;
101 }
102 if( excepts & FE_INVALID )
103 required_add_float( __builtin_inff(), -__builtin_inff() );
104 if( excepts & FE_DIVBYZERO )
105 required_divide_float( 1.0f, 0.0f );
106 if( 0 != (excepts & FE_INEXACT) && 0 == inexact_set )
107 required_add_float( 0x1.0p127f, 1.0f );
108
109 return 0;
110}
111
112
113
114
115
116
117/*******************************************************************************
118* The function "fetestexcept" determines which of the specified subset of *
119* the floating-point exception flags are currently set. The excepts *
120* argument specifies the floating-point status flags to be queried. This *
121* function returns the value of the bitwise OR of the floating-point *
122* exception macros corresponding to the currently set floating-point *
123* exceptions included in excepts. *
124* *
125*******************************************************************************/
126
127int fetestexcept(int excepts )
128{
129 fexcept_t t = 0;
130
131 _fegetexceptflag_private( &t, excepts);
132
133 return t;
134}
135
136
137/*******************************************************************************
138* The following functions provide control of rounding direction modes. *
139*******************************************************************************/
140
141/*******************************************************************************
142* The function "fegetround" returns the value of the rounding direction *
143* macro which represents the current rounding direction, or a negative *
144* if there is no such rounding direction macro or the current rounding *
145* direction is not determinable. *
146*******************************************************************************/
147
148int fegetround(void)
149{
150 int32_t fpscr = GET_FPSCR();
151
152 return fpscr & FE_ALL_RND;
153}
154
155
156/*******************************************************************************
157* The function "fesetround" establishes the rounding direction represented *
158* by its argument "round". If the argument is not equal to the value of a *
159* rounding direction macro, the rounding direction is not changed. It *
160* returns zero if and only if the argument is equal to a rounding *
161* direction macro. *
162*******************************************************************************/
163
164int fesetround(int round )
165{
166 if( (round & FE_ALL_RND) != round )
167 return round;
168
169 int32_t fpscr = GET_FPSCR();
170
171 fpscr &= ~FE_ALL_RND;
172 fpscr |= round & FE_ALL_RND;
173
174 SET_FPSCR( fpscr );
175
176 return 0;
177}
178
179
180/*******************************************************************************
181* The following functions manage the floating-point environment, exception *
182* flags and dynamic modes, as one entity. *
183*******************************************************************************/
184
185/*******************************************************************************
186* The fegetenv function stores the current floating-point enviornment in *
187* the object pointed to by envp. *
188*******************************************************************************/
189int fegetenv(fenv_t *envp)
190{
191 envp->__fpscr = GET_FPSCR();
192 envp->__reserved0 = 0;
193 envp->__reserved1 = 0;
194 envp->__reserved2 = 0;
195
196 return 0;
197}
198
199/*******************************************************************************
200* The feholdexcept function saves the current floating-point environment in *
201* the object pointed to by envp, clears the floating-point status flags, *
202* and then installs a non-stop (continue on floating-point exceptions) *
203* mode, if available, for all floating-point exceptions. The feholdexcept *
204* function returns zero if and only if non-stop floating-point exceptions *
205* handling was successfully installed. *
206*******************************************************************************/
207int feholdexcept(fenv_t *envp)
208{
209 uint32_t fpscr = GET_FPSCR();
210
211 envp->__fpscr = fpscr;
212 envp->__reserved0 = 0;
213 envp->__reserved1 = 0;
214 envp->__reserved2 = 0;
215
216 fpscr &= ~( FE_ALL_EXCEPT | (FE_ALL_EXCEPT << 8) );
217
218 SET_FPSCR( fpscr );
219
220 return 0;
221}
222
223
224/*******************************************************************************
225* The fesetnv function establishes the floating-point environment *
226* represented by the object pointed to by envp. The argument envp shall *
227* point to an object set by a call to fegetenv or feholdexcept, or equal to *
228* a floating-point environment macro -- we define only *FE_DFL_ENV and *
229* FE_DISABLE_SSE_DENORMS_ENV -- to be C99 standard compliant and portable *
230* to other architectures. Note that fesetnv merely installs the state of *
231* the floating-point status flags represented through its argument, and *
232* does not raise these floating-point exceptions. *
233* *
234*******************************************************************************/
235int fesetenv(const fenv_t *envp)
236{
237 SET_FPSCR( envp->__fpscr );
238
239 return 0;
240}
241
242
243
244/*******************************************************************************
245* The feupdateenv function saves the currently raised floating-point *
246* exceptions in its automatic storage, installs the floating-point *
247* environment represented by the object pointed to by envp, and then raises *
248* the saved floating-point exceptions. The argument envp shall point to an *
249* object set by a call to feholdexcept or fegetenv or equal a *
250* floating-point environment macro. *
251* *
252*******************************************************************************/
253int feupdateenv(const fenv_t *envp)
254{
255 uint32_t oldenv = GET_FPSCR();
256
257 SET_FPSCR( envp->__fpscr );
258
259 int inexact_set = 0;
260
261 if( oldenv & FE_OVERFLOW )
262 {
263 required_add_float( 0x1.0p127f, 0x1.0p127f );
264 inexact_set = 1;
265 }
266 if( oldenv & FE_UNDERFLOW )
267 {
268 required_multiply_float( 0x1.0p-126f, 0x1.0p-126f );
269 inexact_set = 1;
270 }
271 if( oldenv & FE_INVALID )
272 required_add_float( __builtin_inff(), -__builtin_inff() );
273 if( oldenv & FE_DIVBYZERO )
274 required_divide_float( 1.0f, 0.0f );
275 if( 0 != (oldenv & FE_INEXACT) && 0 == inexact_set )
276 required_add_float( 0x1.0p127f, 1.0f );
277
278 return 0;
279}
280
281
282/*******************************************************************************
283* The function "fegetexceptflag" stores a implementation-defined *
284* representation of the states of the floating-point status flags indicated *
285* by its integer argument excepts in the object pointed to by the argument, *
286* flagp. *
287*******************************************************************************/
288
289int fegetexceptflag(fexcept_t *flagp, int excepts)
290{
291 return _fegetexceptflag_private( flagp, excepts );
292}
293
294/*******************************************************************************
295* The function "fesetexceptflag" sets or clears the floating point status *
296* flags indicated by the argument excepts to the states stored in the *
297* object pointed to by flagp. The value of the *flagp shall have been set *
298* by a previous call to fegetexceptflag whose second argument represented *
299* at least those floating-point exceptions represented by the argument *
300* excepts. This function does not raise floating-point exceptions; it just *
301* sets the state of the flags. *
302*******************************************************************************/
303
304int fesetexceptflag(const fexcept_t *flagp, int excepts )
305{
306 return _fesetexceptflag_private( flagp, excepts );
307}
308
309#endif
310
311