xref: /openbsd-src/lib/libm/arch/arm/fenv.c (revision d6f349c8942d3775c387f56cb45c019e2a8520df)
1 /*	$OpenBSD: fenv.c,v 1.2 2011/04/28 17:34:23 martynas 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 <sys/cdefs.h>
20 #include <machine/ieeefp.h>
21 
22 #include <fenv.h>
23 
24 extern	fp_except	_softfloat_float_exception_flags;
25 extern	fp_except	_softfloat_float_exception_mask;
26 extern	fp_rnd		_softfloat_float_rounding_mode;
27 extern	void		_softfloat_float_raise(fp_except);
28 
29 /*
30  * The following constant represents the default floating-point environment
31  * (that is, the one installed at program startup) and has type pointer to
32  * const-qualified fenv_t.
33  *
34  * It can be used as an argument to the functions within the <fenv.h> header
35  * that manage the floating-point environment, namely fesetenv() and
36  * feupdateenv().
37  */
38 fenv_t __fe_dfl_env = {
39 	0,
40 	0,
41 	0
42 };
43 
44 /*
45  * The feclearexcept() function clears the supported floating-point exceptions
46  * represented by `excepts'.
47  */
48 int
49 feclearexcept(int excepts)
50 {
51 	excepts &= FE_ALL_EXCEPT;
52 
53 	/* Clear the requested floating-point exceptions */
54 	_softfloat_float_exception_flags &= ~excepts;
55 
56 	return (0);
57 }
58 
59 /*
60  * The fegetexceptflag() function stores an implementation-defined
61  * representation of the states of the floating-point status flags indicated by
62  * the argument excepts in the object pointed to by the argument flagp.
63  */
64 int
65 fegetexceptflag(fexcept_t *flagp, int excepts)
66 {
67 	excepts &= FE_ALL_EXCEPT;
68 
69 	/* Store the results in flagp */
70 	*flagp = _softfloat_float_exception_flags & excepts;
71 
72 	return (0);
73 }
74 
75 /*
76  * The feraiseexcept() function raises the supported floating-point exceptions
77  * represented by the argument `excepts'.
78  */
79 int
80 feraiseexcept(int excepts)
81 {
82 	excepts &= FE_ALL_EXCEPT;
83 
84 	fesetexceptflag((fexcept_t *)&excepts, excepts);
85 	_softfloat_float_raise(excepts);
86 
87 	return (0);
88 }
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 
107 /*
108  * The fetestexcept() function determines which of a specified subset of the
109  * floating-point exception flags are currently set. The `excepts' argument
110  * specifies the floating-point status flags to be queried.
111  */
112 int
113 fetestexcept(int excepts)
114 {
115 	excepts &= FE_ALL_EXCEPT;
116 
117 	return (_softfloat_float_exception_flags & excepts);
118 }
119 
120 /*
121  * The fegetround() function gets the current rounding direction.
122  */
123 int
124 fegetround(void)
125 {
126 	return (_softfloat_float_rounding_mode & _ROUND_MASK);
127 }
128 
129 /*
130  * The fesetround() function establishes the rounding direction represented by
131  * its argument `round'. If the argument is not equal to the value of a rounding
132  * direction macro, the rounding direction is not changed.
133  */
134 int
135 fesetround(int round)
136 {
137 	/* Check whether requested rounding direction is supported */
138 	if (round & ~_ROUND_MASK)
139 		return (-1);
140 
141 	/* Set the rounding direction */
142 	_softfloat_float_rounding_mode &= ~_ROUND_MASK;
143 	_softfloat_float_rounding_mode |= round;
144 
145 	return (0);
146 }
147 
148 /*
149  * The fegetenv() function attempts to store the current floating-point
150  * environment in the object pointed to by envp.
151  */
152 int
153 fegetenv(fenv_t *envp)
154 {
155 	/* Store the current floating-point sticky flags */
156 	envp->__sticky = _softfloat_float_exception_flags;
157 
158 	/* Store the current floating-point masks */
159 	envp->__mask = _softfloat_float_exception_mask;
160 
161 	/* Store the current floating-point control register */
162 	envp->__round = _softfloat_float_rounding_mode;
163 
164 	return (0);
165 }
166 
167 /*
168  * The feholdexcept() function saves the current floating-point environment
169  * in the object pointed to by envp, clears the floating-point status flags, and
170  * then installs a non-stop (continue on floating-point exceptions) mode, if
171  * available, for all floating-point exceptions.
172  */
173 int
174 feholdexcept(fenv_t *envp)
175 {
176 	/* Store the current floating-point environment */
177 	fegetenv(envp);
178 
179 	/* Clear exception flags */
180 	_softfloat_float_exception_flags &= ~FE_ALL_EXCEPT;
181 
182 	/* Mask all exceptions */
183 	_softfloat_float_exception_mask &= ~FE_ALL_EXCEPT;
184 
185 	return (0);
186 }
187 
188 /*
189  * The fesetenv() function attempts to establish the floating-point environment
190  * represented by the object pointed to by envp. The argument `envp' points
191  * to an object set by a call to fegetenv() or feholdexcept(), or equal a
192  * floating-point environment macro. The fesetenv() function does not raise
193  * floating-point exceptions, but only installs the state of the floating-point
194  * status flags represented through its argument.
195  */
196 int
197 fesetenv(const fenv_t *envp)
198 {
199 	/* Load the floating-point sticky flags */
200 	_softfloat_float_exception_flags = envp->__sticky & FE_ALL_EXCEPT;
201 
202 	/* Load the floating-point masks */
203 	_softfloat_float_exception_mask = envp->__mask & FE_ALL_EXCEPT;
204 
205 	/* Load the floating-point rounding mode */
206 	_softfloat_float_rounding_mode = envp->__round & _ROUND_MASK;
207 
208 	return (0);
209 }
210 
211 /*
212  * The feupdateenv() function saves the currently raised floating-point
213  * exceptions in its automatic storage, installs the floating-point environment
214  * represented by the object pointed to by `envp', and then raises the saved
215  * floating-point exceptions. The argument `envp' shall point to an object set
216  * by a call to feholdexcept() or fegetenv(), or equal a floating-point
217  * environment macro.
218  */
219 int
220 feupdateenv(const fenv_t *envp)
221 {
222 	int excepts = _softfloat_float_exception_flags;
223 
224 	/* Install new floating-point environment */
225 	fesetenv(envp);
226 
227 	/* Raise any previously accumulated exceptions */
228 	feraiseexcept(excepts);
229 
230 	return (0);
231 }
232 
233 /*
234  * The following functions are extentions to the standard
235  */
236 int
237 feenableexcept(int mask)
238 {
239 	int omask;
240 
241 	mask &= FE_ALL_EXCEPT;
242 
243 	omask = _softfloat_float_exception_mask & FE_ALL_EXCEPT;
244 	_softfloat_float_exception_mask |= mask;
245 
246 	return (omask);
247 
248 }
249 
250 int
251 fedisableexcept(int mask)
252 {
253 	unsigned int omask;
254 
255 	mask &= FE_ALL_EXCEPT;
256 
257 	omask = _softfloat_float_exception_mask & FE_ALL_EXCEPT;
258 	_softfloat_float_exception_mask &= ~mask;
259 
260 	return (omask);
261 }
262 
263 int
264 fegetexcept(void)
265 {
266 	return (_softfloat_float_exception_mask & FE_ALL_EXCEPT);
267 }
268