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