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