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