xref: /openbsd/lib/libm/arch/sparc64/fenv.c (revision 2c53affb)
1*2c53affbSjmc /*	$OpenBSD: fenv.c,v 1.7 2022/12/27 17:10:07 jmc Exp $	*/
2b9557bebSmartynas /*	$NetBSD: fenv.c,v 1.1 2011/01/31 00:19:33 christos Exp $	*/
3b9557bebSmartynas 
4b9557bebSmartynas /*-
5b9557bebSmartynas  * Copyright (c) 2004-2005 David Schultz <das@FreeBSD.ORG>
6b9557bebSmartynas  * All rights reserved.
7b9557bebSmartynas  *
8b9557bebSmartynas  * Redistribution and use in source and binary forms, with or without
9b9557bebSmartynas  * modification, are permitted provided that the following conditions
10b9557bebSmartynas  * are met:
11b9557bebSmartynas  * 1. Redistributions of source code must retain the above copyright
12b9557bebSmartynas  *    notice, this list of conditions and the following disclaimer.
13b9557bebSmartynas  * 2. Redistributions in binary form must reproduce the above copyright
14b9557bebSmartynas  *    notice, this list of conditions and the following disclaimer in the
15b9557bebSmartynas  *    documentation and/or other materials provided with the distribution.
16b9557bebSmartynas  *
17b9557bebSmartynas  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18b9557bebSmartynas  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19b9557bebSmartynas  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20b9557bebSmartynas  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21b9557bebSmartynas  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22b9557bebSmartynas  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23b9557bebSmartynas  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24b9557bebSmartynas  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25b9557bebSmartynas  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26b9557bebSmartynas  */
27b9557bebSmartynas 
28b9557bebSmartynas #include <fenv.h>
29b9557bebSmartynas 
30b9557bebSmartynas /*
31d111e6b3Smartynas  * The following constant represents the default floating-point environment
32d111e6b3Smartynas  * (that is, the one installed at program startup) and has type pointer to
33d111e6b3Smartynas  * const-qualified fenv_t.
34d111e6b3Smartynas  *
35d111e6b3Smartynas  * It can be used as an argument to the functions within the <fenv.h> header
36d111e6b3Smartynas  * that manage the floating-point environment, namely fesetenv() and
37d111e6b3Smartynas  * feupdateenv().
38d111e6b3Smartynas  */
39d111e6b3Smartynas fenv_t __fe_dfl_env = 0;
40d111e6b3Smartynas 
41d111e6b3Smartynas /*
42b9557bebSmartynas  * The feclearexcept() function clears the supported floating-point exceptions
43b9557bebSmartynas  * represented by `excepts'.
44b9557bebSmartynas  */
45b9557bebSmartynas int
feclearexcept(int excepts)46b9557bebSmartynas feclearexcept(int excepts)
47b9557bebSmartynas {
48b9557bebSmartynas 	fexcept_t r;
49b9557bebSmartynas 
50d6f349c8Smartynas 	excepts &= FE_ALL_EXCEPT;
51b9557bebSmartynas 
52d6f349c8Smartynas 	/* Save floating-point state register */
53b5aa3b33Sguenther 	__asm__ volatile ("stx %%fsr, %0" : "=m" (r));
54b9557bebSmartynas 
55d6f349c8Smartynas 	r &= ~excepts;
56b9557bebSmartynas 
57d6f349c8Smartynas 	/* Load floating-point state register */
58b5aa3b33Sguenther 	__asm__ volatile ("ldx %0, %%fsr" : : "m" (r));
59d6f349c8Smartynas 
60b9557bebSmartynas 	return 0;
61b9557bebSmartynas }
622f2c0062Sguenther DEF_STD(feclearexcept);
63b9557bebSmartynas 
64b9557bebSmartynas /*
65b9557bebSmartynas  * The fegetexceptflag() function stores an implementation-defined
66b9557bebSmartynas  * representation of the states of the floating-point status flags indicated
67b9557bebSmartynas  * by the argument excepts in the object pointed to by the argument flagp.
68b9557bebSmartynas  */
69b9557bebSmartynas int
fegetexceptflag(fexcept_t * flagp,int excepts)70b9557bebSmartynas fegetexceptflag(fexcept_t *flagp, int excepts)
71b9557bebSmartynas {
72b9557bebSmartynas 	fexcept_t r;
73b9557bebSmartynas 
74d6f349c8Smartynas 	excepts &= FE_ALL_EXCEPT;
75b9557bebSmartynas 
76d6f349c8Smartynas 	/* Save floating-point state register */
77b5aa3b33Sguenther 	__asm__ volatile ("stx %%fsr, %0" : "=m" (r));
78b9557bebSmartynas 
79d6f349c8Smartynas 	*flagp = r & excepts;
80b9557bebSmartynas 
81b9557bebSmartynas 	return 0;
82b9557bebSmartynas }
83b9557bebSmartynas 
84b9557bebSmartynas 
85b9557bebSmartynas /*
86b9557bebSmartynas  * This function sets the floating-point status flags indicated by the argument
87b9557bebSmartynas  * `excepts' to the states stored in the object pointed to by `flagp'. It does
88b9557bebSmartynas  * NOT raise any floating-point exceptions, but only sets the state of the flags.
89b9557bebSmartynas  */
90b9557bebSmartynas int
fesetexceptflag(const fexcept_t * flagp,int excepts)91b9557bebSmartynas fesetexceptflag(const fexcept_t *flagp, int excepts)
92b9557bebSmartynas {
93b9557bebSmartynas 	fexcept_t r;
94b9557bebSmartynas 
95d6f349c8Smartynas 	excepts &= FE_ALL_EXCEPT;
96b9557bebSmartynas 
97d6f349c8Smartynas 	/* Save floating-point state register */
98b5aa3b33Sguenther 	__asm__ volatile ("stx %%fsr, %0" : "=m" (r));
99b9557bebSmartynas 
100d6f349c8Smartynas 	r &= ~excepts;
101d6f349c8Smartynas 	r |= *flagp & excepts;
102b9557bebSmartynas 
103d6f349c8Smartynas 	/* Load floating-point state register */
104b5aa3b33Sguenther 	__asm__ volatile ("ldx %0, %%fsr" : : "m" (r));
105d6f349c8Smartynas 
106b9557bebSmartynas 	return 0;
107b9557bebSmartynas }
1082f2c0062Sguenther DEF_STD(fesetexceptflag);
109b9557bebSmartynas 
110b9557bebSmartynas /*
111b9557bebSmartynas  * The feraiseexcept() function raises the supported floating-point exceptions
112b9557bebSmartynas  * represented by the argument `excepts'.
113b9557bebSmartynas  *
114b9557bebSmartynas  * The order in which these floating-point exceptions are raised is unspecified
115b9557bebSmartynas  * (by the standard).
116b9557bebSmartynas  */
117b9557bebSmartynas int
feraiseexcept(int excepts)118b9557bebSmartynas feraiseexcept(int excepts)
119b9557bebSmartynas {
120b9557bebSmartynas 	volatile double d;
121b9557bebSmartynas 
122d6f349c8Smartynas 	excepts &= FE_ALL_EXCEPT;
123b9557bebSmartynas 
124b9557bebSmartynas 	/*
125b9557bebSmartynas 	 * With a compiler that supports the FENV_ACCESS pragma properly, simple
126b9557bebSmartynas 	 * expressions like '0.0 / 0.0' should be sufficient to generate traps.
127b9557bebSmartynas 	 * Unfortunately, we need to bring a volatile variable into the equation
128b9557bebSmartynas 	 * to prevent incorrect optimizations.
129b9557bebSmartynas 	 */
130d6f349c8Smartynas 	if (excepts & FE_INVALID) {
131b9557bebSmartynas 		d = 0.0;
132b9557bebSmartynas 		d = 0.0 / d;
133b9557bebSmartynas 	}
134d6f349c8Smartynas 	if (excepts & FE_DIVBYZERO) {
135b9557bebSmartynas 		d = 0.0;
136b9557bebSmartynas 		d = 1.0 / d;
137b9557bebSmartynas 	}
138d6f349c8Smartynas 	if (excepts & FE_OVERFLOW) {
139b9557bebSmartynas 		d = 0x1.ffp1023;
140b9557bebSmartynas 		d *= 2.0;
141b9557bebSmartynas 	}
142d6f349c8Smartynas 	if (excepts & FE_UNDERFLOW) {
143b9557bebSmartynas 		d = 0x1p-1022;
144b9557bebSmartynas 		d /= 0x1p1023;
145b9557bebSmartynas 	}
146d6f349c8Smartynas 	if (excepts & FE_INEXACT) {
147b9557bebSmartynas 		d = 0x1p-1022;
148b9557bebSmartynas 		d += 1.0;
149b9557bebSmartynas 	}
150b9557bebSmartynas 
151b9557bebSmartynas 	return 0;
152b9557bebSmartynas }
1532f2c0062Sguenther DEF_STD(feraiseexcept);
154b9557bebSmartynas 
155b9557bebSmartynas /*
156b9557bebSmartynas  * The fetestexcept() function determines which of a specified subset of the
157b9557bebSmartynas  * floating-point exception flags are currently set. The `excepts' argument
158b9557bebSmartynas  * specifies the floating-point status flags to be queried.
159b9557bebSmartynas  */
160b9557bebSmartynas int
fetestexcept(int excepts)161b9557bebSmartynas fetestexcept(int excepts)
162b9557bebSmartynas {
163b9557bebSmartynas 	fexcept_t r;
164b9557bebSmartynas 
165d6f349c8Smartynas 	excepts &= FE_ALL_EXCEPT;
166b9557bebSmartynas 
167d6f349c8Smartynas 	/* Save floating-point state register */
168b5aa3b33Sguenther 	__asm__ volatile ("stx %%fsr, %0" : "=m" (r));
169b9557bebSmartynas 
170d6f349c8Smartynas 	return r & excepts;
171b9557bebSmartynas }
1722f2c0062Sguenther DEF_STD(fetestexcept);
173b9557bebSmartynas 
174b9557bebSmartynas /*
175b9557bebSmartynas  * The fegetround() function gets the current rounding direction.
176b9557bebSmartynas  */
177b9557bebSmartynas int
fegetround(void)178b9557bebSmartynas fegetround(void)
179b9557bebSmartynas {
180b9557bebSmartynas 	fenv_t r;
181b9557bebSmartynas 
182d6f349c8Smartynas 	/* Save floating-point state register */
183b5aa3b33Sguenther 	__asm__ volatile ("stx %%fsr, %0" : "=m" (r));
184b9557bebSmartynas 
185b9557bebSmartynas 	return (r >> _ROUND_SHIFT) & _ROUND_MASK;
186b9557bebSmartynas }
1872f2c0062Sguenther DEF_STD(fegetround);
188b9557bebSmartynas 
189b9557bebSmartynas /*
190b9557bebSmartynas  * The fesetround() function establishes the rounding direction represented by
191b9557bebSmartynas  * its argument `round'. If the argument is not equal to the value of a rounding
192b9557bebSmartynas  * direction macro, the rounding direction is not changed.
193b9557bebSmartynas  */
194b9557bebSmartynas int
fesetround(int round)195b9557bebSmartynas fesetround(int round)
196b9557bebSmartynas {
197b9557bebSmartynas 	fenv_t r;
198b9557bebSmartynas 
199b9557bebSmartynas 	if (round & ~_ROUND_MASK)
200b9557bebSmartynas 		return -1;
201b9557bebSmartynas 
202d6f349c8Smartynas 	/* Save floating-point state register */
203b5aa3b33Sguenther 	__asm__ volatile ("stx %%fsr, %0" : "=m" (r));
204d6f349c8Smartynas 
205b9557bebSmartynas 	r &= ~(_ROUND_MASK << _ROUND_SHIFT);
206b9557bebSmartynas 	r |= round << _ROUND_SHIFT;
207b9557bebSmartynas 
208d6f349c8Smartynas 	/* Load floating-point state register */
209b5aa3b33Sguenther 	__asm__ volatile ("ldx %0, %%fsr" : : "m" (r));
210d6f349c8Smartynas 
211b9557bebSmartynas 	return 0;
212b9557bebSmartynas }
2132f2c0062Sguenther DEF_STD(fesetround);
214b9557bebSmartynas 
215b9557bebSmartynas /*
216b9557bebSmartynas  * The fegetenv() function attempts to store the current floating-point
217b9557bebSmartynas  * environment in the object pointed to by envp.
218b9557bebSmartynas  */
219b9557bebSmartynas int
fegetenv(fenv_t * envp)220b9557bebSmartynas fegetenv(fenv_t *envp)
221b9557bebSmartynas {
222d6f349c8Smartynas 	/* Save floating-point state register */
223b5aa3b33Sguenther 	__asm__ volatile ("stx %%fsr, %0" : "=m" (*envp));
224b9557bebSmartynas 
225b9557bebSmartynas 	return 0;
226b9557bebSmartynas }
2272f2c0062Sguenther DEF_STD(fegetenv);
228b9557bebSmartynas 
229b9557bebSmartynas 
230b9557bebSmartynas /*
231b9557bebSmartynas  * The feholdexcept() function saves the current floating-point environment
232b9557bebSmartynas  * in the object pointed to by envp, clears the floating-point status flags, and
233b9557bebSmartynas  * then installs a non-stop (continue on floating-point exceptions) mode, if
234b9557bebSmartynas  * available, for all floating-point exceptions.
235b9557bebSmartynas  */
236b9557bebSmartynas int
feholdexcept(fenv_t * envp)237b9557bebSmartynas feholdexcept(fenv_t *envp)
238b9557bebSmartynas {
239b9557bebSmartynas 	fenv_t r;
240b9557bebSmartynas 
241d6f349c8Smartynas 	/* Save floating-point state register */
242b5aa3b33Sguenther 	__asm__ volatile ("stx %%fsr, %0" : "=m" (r));
243b9557bebSmartynas 
244b9557bebSmartynas 	*envp = r;
245d6f349c8Smartynas 	r &= ~(FE_ALL_EXCEPT | (FE_ALL_EXCEPT << _MASK_SHIFT));
246b9557bebSmartynas 
247d6f349c8Smartynas 	/* Load floating-point state register */
248b5aa3b33Sguenther 	__asm__ volatile ("ldx %0, %%fsr" : : "m" (r));
249d6f349c8Smartynas 
250b9557bebSmartynas 	return 0;
251b9557bebSmartynas }
2522f2c0062Sguenther DEF_STD(feholdexcept);
253b9557bebSmartynas 
254b9557bebSmartynas /*
255b9557bebSmartynas  * The fesetenv() function attempts to establish the floating-point environment
256b9557bebSmartynas  * represented by the object pointed to by envp. The argument `envp' points
257b9557bebSmartynas  * to an object set by a call to fegetenv() or feholdexcept(), or equal a
258b9557bebSmartynas  * floating-point environment macro. The fesetenv() function does not raise
259b9557bebSmartynas  * floating-point exceptions, but only installs the state of the floating-point
260b9557bebSmartynas  * status flags represented through its argument.
261b9557bebSmartynas  */
262b9557bebSmartynas int
fesetenv(const fenv_t * envp)263b9557bebSmartynas fesetenv(const fenv_t *envp)
264b9557bebSmartynas {
265d6f349c8Smartynas 	/* Load floating-point state register */
266b5aa3b33Sguenther 	__asm__ volatile ("ldx %0, %%fsr" : : "m" (*envp));
267b9557bebSmartynas 
268b9557bebSmartynas 	return 0;
269b9557bebSmartynas }
2702f2c0062Sguenther DEF_STD(fesetenv);
271b9557bebSmartynas 
272b9557bebSmartynas 
273b9557bebSmartynas /*
274b9557bebSmartynas  * The feupdateenv() function saves the currently raised floating-point
275b9557bebSmartynas  * exceptions in its automatic storage, installs the floating-point environment
276b9557bebSmartynas  * represented by the object pointed to by `envp', and then raises the saved
277b9557bebSmartynas  * floating-point exceptions. The argument `envp' shall point to an object set
278b9557bebSmartynas  * by a call to feholdexcept() or fegetenv(), or equal a floating-point
279b9557bebSmartynas  * environment macro.
280b9557bebSmartynas  */
281b9557bebSmartynas int
feupdateenv(const fenv_t * envp)282b9557bebSmartynas feupdateenv(const fenv_t *envp)
283b9557bebSmartynas {
284b9557bebSmartynas 	fexcept_t r;
285b9557bebSmartynas 
286d6f349c8Smartynas 	/* Save floating-point state register */
287b5aa3b33Sguenther 	__asm__ volatile ("stx %%fsr, %0" : "=m" (r));
288b9557bebSmartynas 
289d6f349c8Smartynas 	/* Load floating-point state register */
290b5aa3b33Sguenther 	__asm__ volatile ("ldx %0, %%fsr" : : "m" (*envp));
291b9557bebSmartynas 
292b9557bebSmartynas 	feraiseexcept(r & FE_ALL_EXCEPT);
293b9557bebSmartynas 
294b9557bebSmartynas 	return 0;
295b9557bebSmartynas }
2962f2c0062Sguenther DEF_STD(feupdateenv);
297b9557bebSmartynas 
298b9557bebSmartynas /*
299*2c53affbSjmc  * The following functions are extensions to the standard
300b9557bebSmartynas  */
301b9557bebSmartynas int
feenableexcept(int mask)302b9557bebSmartynas feenableexcept(int mask)
303b9557bebSmartynas {
304b9557bebSmartynas 	fenv_t old_r, new_r;
305b9557bebSmartynas 
306d6f349c8Smartynas 	mask &= FE_ALL_EXCEPT;
307b9557bebSmartynas 
308d6f349c8Smartynas 	/* Save floating-point state register */
309b5aa3b33Sguenther 	__asm__ volatile ("stx %%fsr, %0" : "=m" (old_r));
310d6f349c8Smartynas 
311d6f349c8Smartynas 	new_r = old_r | (mask << _MASK_SHIFT);
312d6f349c8Smartynas 
313d6f349c8Smartynas 	/* Load floating-point state register */
314b5aa3b33Sguenther 	__asm__ volatile ("ldx %0, %%fsr" : : "m" (new_r));
315d6f349c8Smartynas 
316d6f349c8Smartynas 	return (old_r >> _MASK_SHIFT) & FE_ALL_EXCEPT;
317b9557bebSmartynas }
318b9557bebSmartynas 
319b9557bebSmartynas int
fedisableexcept(int mask)320b9557bebSmartynas fedisableexcept(int mask)
321b9557bebSmartynas {
322b9557bebSmartynas 	fenv_t old_r, new_r;
323b9557bebSmartynas 
324d6f349c8Smartynas 	mask &= FE_ALL_EXCEPT;
325b9557bebSmartynas 
326d6f349c8Smartynas 	/* Save floating-point state register */
327b5aa3b33Sguenther 	__asm__ volatile ("stx %%fsr, %0" : "=m" (old_r));
328d6f349c8Smartynas 
329d6f349c8Smartynas 	new_r = old_r & ~(mask << _MASK_SHIFT);
330d6f349c8Smartynas 
331d6f349c8Smartynas 	/* Load floating-point state register */
332b5aa3b33Sguenther 	__asm__ volatile ("ldx %0, %%fsr" : : "m" (new_r));
333d6f349c8Smartynas 
334d6f349c8Smartynas 	return (old_r >> _MASK_SHIFT) & FE_ALL_EXCEPT;
335b9557bebSmartynas }
336b9557bebSmartynas 
337b9557bebSmartynas int
fegetexcept(void)338b9557bebSmartynas fegetexcept(void)
339b9557bebSmartynas {
340b9557bebSmartynas 	fenv_t r;
341b9557bebSmartynas 
342d6f349c8Smartynas 	/* Save floating-point state register */
343b5aa3b33Sguenther 	__asm__ volatile ("stx %%fsr, %0" : "=m" (r));
344d6f349c8Smartynas 
345d6f349c8Smartynas 	return (r & (FE_ALL_EXCEPT << _MASK_SHIFT)) >> _MASK_SHIFT;
346b9557bebSmartynas }
347