fenv.c revision 1.3
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
22extern	fp_except	_softfloat_float_exception_flags;
23extern	fp_except	_softfloat_float_exception_mask;
24extern	fp_rnd		_softfloat_float_rounding_mode;
25extern	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 */
36fenv_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 */
46int
47feclearexcept(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 */
62int
63fegetexceptflag(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 */
77int
78feraiseexcept(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 */
93int
94fesetexceptflag(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 */
110int
111fetestexcept(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 */
121int
122fegetround(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 */
132int
133fesetround(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 */
150int
151fegetenv(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 */
171int
172feholdexcept(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 */
194int
195fesetenv(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 */
217int
218feupdateenv(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 */
234int
235feenableexcept(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
248int
249fedisableexcept(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
261int
262fegetexcept(void)
263{
264	return (_softfloat_float_exception_mask & FE_ALL_EXCEPT);
265}
266