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