xref: /openbsd-src/lib/libm/arch/arm/fenv.c (revision ae3cb403620ab940fbaabb3055fac045a63d56b7)
1 /*	$OpenBSD: fenv.c,v 1.4 2016/09/12 19:47:01 guenther Exp $	*/
2 
3 /*
4  * Copyright (c) 2011 Martynas Venckus <martynas@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <fenv.h>
20 #include <machine/ieeefp.h>
21 
22 extern	fp_except	_softfloat_float_exception_flags;
23 extern	fp_except	_softfloat_float_exception_mask;
24 extern	fp_rnd		_softfloat_float_rounding_mode;
25 extern	void		_softfloat_float_raise(fp_except);
26 
27 /*
28  * The following constant represents the default floating-point environment
29  * (that is, the one installed at program startup) and has type pointer to
30  * const-qualified fenv_t.
31  *
32  * It can be used as an argument to the functions within the <fenv.h> header
33  * that manage the floating-point environment, namely fesetenv() and
34  * feupdateenv().
35  */
36 fenv_t __fe_dfl_env = {
37 	0,
38 	0,
39 	0
40 };
41 
42 /*
43  * The feclearexcept() function clears the supported floating-point exceptions
44  * represented by `excepts'.
45  */
46 int
47 feclearexcept(int excepts)
48 {
49 	excepts &= FE_ALL_EXCEPT;
50 
51 	/* Clear the requested floating-point exceptions */
52 	_softfloat_float_exception_flags &= ~excepts;
53 
54 	return (0);
55 }
56 DEF_STD(feclearexcept);
57 
58 /*
59  * The fegetexceptflag() function stores an implementation-defined
60  * representation of the states of the floating-point status flags indicated by
61  * the argument excepts in the object pointed to by the argument flagp.
62  */
63 int
64 fegetexceptflag(fexcept_t *flagp, int excepts)
65 {
66 	excepts &= FE_ALL_EXCEPT;
67 
68 	/* Store the results in flagp */
69 	*flagp = _softfloat_float_exception_flags & excepts;
70 
71 	return (0);
72 }
73 
74 /*
75  * The feraiseexcept() function raises the supported floating-point exceptions
76  * represented by the argument `excepts'.
77  */
78 int
79 feraiseexcept(int excepts)
80 {
81 	excepts &= FE_ALL_EXCEPT;
82 
83 	fesetexceptflag((fexcept_t *)&excepts, excepts);
84 	_softfloat_float_raise(excepts);
85 
86 	return (0);
87 }
88 DEF_STD(feraiseexcept);
89 
90 /*
91  * This function sets the floating-point status flags indicated by the argument
92  * `excepts' to the states stored in the object pointed to by `flagp'. It does
93  * NOT raise any floating-point exceptions, but only sets the state of the flags.
94  */
95 int
96 fesetexceptflag(const fexcept_t *flagp, int excepts)
97 {
98 	excepts &= FE_ALL_EXCEPT;
99 
100 	/* Set the requested status flags */
101 	_softfloat_float_exception_flags &= ~excepts;
102 	_softfloat_float_exception_flags |= *flagp & excepts;
103 
104 	return (0);
105 }
106 DEF_STD(fesetexceptflag);
107 
108 /*
109  * The fetestexcept() function determines which of a specified subset of the
110  * floating-point exception flags are currently set. The `excepts' argument
111  * specifies the floating-point status flags to be queried.
112  */
113 int
114 fetestexcept(int excepts)
115 {
116 	excepts &= FE_ALL_EXCEPT;
117 
118 	return (_softfloat_float_exception_flags & excepts);
119 }
120 DEF_STD(fetestexcept);
121 
122 /*
123  * The fegetround() function gets the current rounding direction.
124  */
125 int
126 fegetround(void)
127 {
128 	return (_softfloat_float_rounding_mode & _ROUND_MASK);
129 }
130 DEF_STD(fegetround);
131 
132 /*
133  * The fesetround() function establishes the rounding direction represented by
134  * its argument `round'. If the argument is not equal to the value of a rounding
135  * direction macro, the rounding direction is not changed.
136  */
137 int
138 fesetround(int round)
139 {
140 	/* Check whether requested rounding direction is supported */
141 	if (round & ~_ROUND_MASK)
142 		return (-1);
143 
144 	/* Set the rounding direction */
145 	_softfloat_float_rounding_mode &= ~_ROUND_MASK;
146 	_softfloat_float_rounding_mode |= round;
147 
148 	return (0);
149 }
150 DEF_STD(fesetround);
151 
152 /*
153  * The fegetenv() function attempts to store the current floating-point
154  * environment in the object pointed to by envp.
155  */
156 int
157 fegetenv(fenv_t *envp)
158 {
159 	/* Store the current floating-point sticky flags */
160 	envp->__sticky = _softfloat_float_exception_flags;
161 
162 	/* Store the current floating-point masks */
163 	envp->__mask = _softfloat_float_exception_mask;
164 
165 	/* Store the current floating-point control register */
166 	envp->__round = _softfloat_float_rounding_mode;
167 
168 	return (0);
169 }
170 DEF_STD(fegetenv);
171 
172 /*
173  * The feholdexcept() function saves the current floating-point environment
174  * in the object pointed to by envp, clears the floating-point status flags, and
175  * then installs a non-stop (continue on floating-point exceptions) mode, if
176  * available, for all floating-point exceptions.
177  */
178 int
179 feholdexcept(fenv_t *envp)
180 {
181 	/* Store the current floating-point environment */
182 	fegetenv(envp);
183 
184 	/* Clear exception flags */
185 	_softfloat_float_exception_flags &= ~FE_ALL_EXCEPT;
186 
187 	/* Mask all exceptions */
188 	_softfloat_float_exception_mask &= ~FE_ALL_EXCEPT;
189 
190 	return (0);
191 }
192 DEF_STD(feholdexcept);
193 
194 /*
195  * The fesetenv() function attempts to establish the floating-point environment
196  * represented by the object pointed to by envp. The argument `envp' points
197  * to an object set by a call to fegetenv() or feholdexcept(), or equal a
198  * floating-point environment macro. The fesetenv() function does not raise
199  * floating-point exceptions, but only installs the state of the floating-point
200  * status flags represented through its argument.
201  */
202 int
203 fesetenv(const fenv_t *envp)
204 {
205 	/* Load the floating-point sticky flags */
206 	_softfloat_float_exception_flags = envp->__sticky & FE_ALL_EXCEPT;
207 
208 	/* Load the floating-point masks */
209 	_softfloat_float_exception_mask = envp->__mask & FE_ALL_EXCEPT;
210 
211 	/* Load the floating-point rounding mode */
212 	_softfloat_float_rounding_mode = envp->__round & _ROUND_MASK;
213 
214 	return (0);
215 }
216 DEF_STD(fesetenv);
217 
218 /*
219  * The feupdateenv() function saves the currently raised floating-point
220  * exceptions in its automatic storage, installs the floating-point environment
221  * represented by the object pointed to by `envp', and then raises the saved
222  * floating-point exceptions. The argument `envp' shall point to an object set
223  * by a call to feholdexcept() or fegetenv(), or equal a floating-point
224  * environment macro.
225  */
226 int
227 feupdateenv(const fenv_t *envp)
228 {
229 	int excepts = _softfloat_float_exception_flags;
230 
231 	/* Install new floating-point environment */
232 	fesetenv(envp);
233 
234 	/* Raise any previously accumulated exceptions */
235 	feraiseexcept(excepts);
236 
237 	return (0);
238 }
239 DEF_STD(feupdateenv);
240 
241 /*
242  * The following functions are extentions to the standard
243  */
244 int
245 feenableexcept(int mask)
246 {
247 	int omask;
248 
249 	mask &= FE_ALL_EXCEPT;
250 
251 	omask = _softfloat_float_exception_mask & FE_ALL_EXCEPT;
252 	_softfloat_float_exception_mask |= mask;
253 
254 	return (omask);
255 
256 }
257 
258 int
259 fedisableexcept(int mask)
260 {
261 	unsigned int omask;
262 
263 	mask &= FE_ALL_EXCEPT;
264 
265 	omask = _softfloat_float_exception_mask & FE_ALL_EXCEPT;
266 	_softfloat_float_exception_mask &= ~mask;
267 
268 	return (omask);
269 }
270 
271 int
272 fegetexcept(void)
273 {
274 	return (_softfloat_float_exception_mask & FE_ALL_EXCEPT);
275 }
276