xref: /openbsd-src/lib/libm/arch/arm/fenv.c (revision 91f110e064cd7c194e59e019b83bb7496c1c84d4)
1 /*	$OpenBSD: fenv.c,v 1.3 2012/12/05 23:20:02 deraadt 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 
57 /*
58  * The fegetexceptflag() function stores an implementation-defined
59  * representation of the states of the floating-point status flags indicated by
60  * the argument excepts in the object pointed to by the argument flagp.
61  */
62 int
63 fegetexceptflag(fexcept_t *flagp, int excepts)
64 {
65 	excepts &= FE_ALL_EXCEPT;
66 
67 	/* Store the results in flagp */
68 	*flagp = _softfloat_float_exception_flags & excepts;
69 
70 	return (0);
71 }
72 
73 /*
74  * The feraiseexcept() function raises the supported floating-point exceptions
75  * represented by the argument `excepts'.
76  */
77 int
78 feraiseexcept(int excepts)
79 {
80 	excepts &= FE_ALL_EXCEPT;
81 
82 	fesetexceptflag((fexcept_t *)&excepts, excepts);
83 	_softfloat_float_raise(excepts);
84 
85 	return (0);
86 }
87 
88 /*
89  * This function sets the floating-point status flags indicated by the argument
90  * `excepts' to the states stored in the object pointed to by `flagp'. It does
91  * NOT raise any floating-point exceptions, but only sets the state of the flags.
92  */
93 int
94 fesetexceptflag(const fexcept_t *flagp, int excepts)
95 {
96 	excepts &= FE_ALL_EXCEPT;
97 
98 	/* Set the requested status flags */
99 	_softfloat_float_exception_flags &= ~excepts;
100 	_softfloat_float_exception_flags |= *flagp & excepts;
101 
102 	return (0);
103 }
104 
105 /*
106  * The fetestexcept() function determines which of a specified subset of the
107  * floating-point exception flags are currently set. The `excepts' argument
108  * specifies the floating-point status flags to be queried.
109  */
110 int
111 fetestexcept(int excepts)
112 {
113 	excepts &= FE_ALL_EXCEPT;
114 
115 	return (_softfloat_float_exception_flags & excepts);
116 }
117 
118 /*
119  * The fegetround() function gets the current rounding direction.
120  */
121 int
122 fegetround(void)
123 {
124 	return (_softfloat_float_rounding_mode & _ROUND_MASK);
125 }
126 
127 /*
128  * The fesetround() function establishes the rounding direction represented by
129  * its argument `round'. If the argument is not equal to the value of a rounding
130  * direction macro, the rounding direction is not changed.
131  */
132 int
133 fesetround(int round)
134 {
135 	/* Check whether requested rounding direction is supported */
136 	if (round & ~_ROUND_MASK)
137 		return (-1);
138 
139 	/* Set the rounding direction */
140 	_softfloat_float_rounding_mode &= ~_ROUND_MASK;
141 	_softfloat_float_rounding_mode |= round;
142 
143 	return (0);
144 }
145 
146 /*
147  * The fegetenv() function attempts to store the current floating-point
148  * environment in the object pointed to by envp.
149  */
150 int
151 fegetenv(fenv_t *envp)
152 {
153 	/* Store the current floating-point sticky flags */
154 	envp->__sticky = _softfloat_float_exception_flags;
155 
156 	/* Store the current floating-point masks */
157 	envp->__mask = _softfloat_float_exception_mask;
158 
159 	/* Store the current floating-point control register */
160 	envp->__round = _softfloat_float_rounding_mode;
161 
162 	return (0);
163 }
164 
165 /*
166  * The feholdexcept() function saves the current floating-point environment
167  * in the object pointed to by envp, clears the floating-point status flags, and
168  * then installs a non-stop (continue on floating-point exceptions) mode, if
169  * available, for all floating-point exceptions.
170  */
171 int
172 feholdexcept(fenv_t *envp)
173 {
174 	/* Store the current floating-point environment */
175 	fegetenv(envp);
176 
177 	/* Clear exception flags */
178 	_softfloat_float_exception_flags &= ~FE_ALL_EXCEPT;
179 
180 	/* Mask all exceptions */
181 	_softfloat_float_exception_mask &= ~FE_ALL_EXCEPT;
182 
183 	return (0);
184 }
185 
186 /*
187  * The fesetenv() function attempts to establish the floating-point environment
188  * represented by the object pointed to by envp. The argument `envp' points
189  * to an object set by a call to fegetenv() or feholdexcept(), or equal a
190  * floating-point environment macro. The fesetenv() function does not raise
191  * floating-point exceptions, but only installs the state of the floating-point
192  * status flags represented through its argument.
193  */
194 int
195 fesetenv(const fenv_t *envp)
196 {
197 	/* Load the floating-point sticky flags */
198 	_softfloat_float_exception_flags = envp->__sticky & FE_ALL_EXCEPT;
199 
200 	/* Load the floating-point masks */
201 	_softfloat_float_exception_mask = envp->__mask & FE_ALL_EXCEPT;
202 
203 	/* Load the floating-point rounding mode */
204 	_softfloat_float_rounding_mode = envp->__round & _ROUND_MASK;
205 
206 	return (0);
207 }
208 
209 /*
210  * The feupdateenv() function saves the currently raised floating-point
211  * exceptions in its automatic storage, installs the floating-point environment
212  * represented by the object pointed to by `envp', and then raises the saved
213  * floating-point exceptions. The argument `envp' shall point to an object set
214  * by a call to feholdexcept() or fegetenv(), or equal a floating-point
215  * environment macro.
216  */
217 int
218 feupdateenv(const fenv_t *envp)
219 {
220 	int excepts = _softfloat_float_exception_flags;
221 
222 	/* Install new floating-point environment */
223 	fesetenv(envp);
224 
225 	/* Raise any previously accumulated exceptions */
226 	feraiseexcept(excepts);
227 
228 	return (0);
229 }
230 
231 /*
232  * The following functions are extentions to the standard
233  */
234 int
235 feenableexcept(int mask)
236 {
237 	int omask;
238 
239 	mask &= FE_ALL_EXCEPT;
240 
241 	omask = _softfloat_float_exception_mask & FE_ALL_EXCEPT;
242 	_softfloat_float_exception_mask |= mask;
243 
244 	return (omask);
245 
246 }
247 
248 int
249 fedisableexcept(int mask)
250 {
251 	unsigned int omask;
252 
253 	mask &= FE_ALL_EXCEPT;
254 
255 	omask = _softfloat_float_exception_mask & FE_ALL_EXCEPT;
256 	_softfloat_float_exception_mask &= ~mask;
257 
258 	return (omask);
259 }
260 
261 int
262 fegetexcept(void)
263 {
264 	return (_softfloat_float_exception_mask & FE_ALL_EXCEPT);
265 }
266