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