xref: /netbsd/lib/libm/arch/sparc/fenv.c (revision 35339755)
1*35339755Sandvar /*	$NetBSD: fenv.c,v 1.3 2021/09/03 21:54:59 andvar Exp $	*/
26c6496b6Snakayama 
36c6496b6Snakayama /*-
46c6496b6Snakayama  * Copyright (c) 2004-2005 David Schultz <das@FreeBSD.ORG>
56c6496b6Snakayama  * All rights reserved.
66c6496b6Snakayama  *
76c6496b6Snakayama  * Redistribution and use in source and binary forms, with or without
86c6496b6Snakayama  * modification, are permitted provided that the following conditions
96c6496b6Snakayama  * are met:
106c6496b6Snakayama  * 1. Redistributions of source code must retain the above copyright
116c6496b6Snakayama  *    notice, this list of conditions and the following disclaimer.
126c6496b6Snakayama  * 2. Redistributions in binary form must reproduce the above copyright
136c6496b6Snakayama  *    notice, this list of conditions and the following disclaimer in the
146c6496b6Snakayama  *    documentation and/or other materials provided with the distribution.
156c6496b6Snakayama  *
166c6496b6Snakayama  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
176c6496b6Snakayama  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
186c6496b6Snakayama  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
196c6496b6Snakayama  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
206c6496b6Snakayama  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
216c6496b6Snakayama  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
226c6496b6Snakayama  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
236c6496b6Snakayama  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
246c6496b6Snakayama  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
256c6496b6Snakayama  */
266c6496b6Snakayama #include <sys/cdefs.h>
27*35339755Sandvar __RCSID("$NetBSD: fenv.c,v 1.3 2021/09/03 21:54:59 andvar Exp $");
28ce8aa0c8Schs 
29ce8aa0c8Schs #include "namespace.h"
306c6496b6Snakayama 
316c6496b6Snakayama #include <assert.h>
326c6496b6Snakayama #include <fenv.h>
336c6496b6Snakayama 
34ce8aa0c8Schs #ifdef __weak_alias
__weak_alias(feclearexcept,_feclearexcept)35ce8aa0c8Schs __weak_alias(feclearexcept,_feclearexcept)
36ce8aa0c8Schs __weak_alias(fedisableexcept,_fedisableexcept)
37ce8aa0c8Schs __weak_alias(feenableexcept,_feenableexcept)
38ce8aa0c8Schs __weak_alias(fegetenv,_fegetenv)
39ce8aa0c8Schs __weak_alias(fegetexcept,_fegetexcept)
40ce8aa0c8Schs __weak_alias(fegetexceptflag,_fegetexceptflag)
41ce8aa0c8Schs __weak_alias(fegetround,_fegetround)
42ce8aa0c8Schs __weak_alias(feholdexcept,_feholdexcept)
43ce8aa0c8Schs __weak_alias(feraiseexcept,_feraiseexcept)
44ce8aa0c8Schs __weak_alias(fesetenv,_fesetenv)
45ce8aa0c8Schs __weak_alias(fesetexceptflag,_fesetexceptflag)
46ce8aa0c8Schs __weak_alias(fesetround,_fesetround)
47ce8aa0c8Schs __weak_alias(fetestexcept,_fetestexcept)
48ce8aa0c8Schs __weak_alias(feupdateenv,_feupdateenv)
49ce8aa0c8Schs #endif
50ce8aa0c8Schs 
516c6496b6Snakayama /* Load floating-point state register (32bits) */
526c6496b6Snakayama #define	__ldfsr(__r)	__asm__	__volatile__		\
536c6496b6Snakayama 	("ld %0, %%fsr" : : "m" (__r))
546c6496b6Snakayama 
556c6496b6Snakayama /* Save floating-point state register (32bits) */
566c6496b6Snakayama #define	__stfsr(__r)	__asm__	__volatile__		\
576c6496b6Snakayama 	("st %%fsr, %0" : "=m" (*(__r)))
586c6496b6Snakayama 
596c6496b6Snakayama /*
606c6496b6Snakayama  * The feclearexcept() function clears the supported floating-point exceptions
616c6496b6Snakayama  * represented by `excepts'.
626c6496b6Snakayama  */
636c6496b6Snakayama int
646c6496b6Snakayama feclearexcept(int excepts)
656c6496b6Snakayama {
666c6496b6Snakayama 	fexcept_t r;
676c6496b6Snakayama 	int ex;
686c6496b6Snakayama 
696c6496b6Snakayama 	_DIAGASSERT((excepts & ~FE_ALL_EXCEPT) == 0);
706c6496b6Snakayama 
716c6496b6Snakayama 	ex = excepts & FE_ALL_EXCEPT;
726c6496b6Snakayama 
736c6496b6Snakayama 	__stfsr(&r);
746c6496b6Snakayama 	r &= ~ex;
756c6496b6Snakayama 	__ldfsr(r);
766c6496b6Snakayama 
776c6496b6Snakayama 	/* Success */
786c6496b6Snakayama 	return 0;
796c6496b6Snakayama }
806c6496b6Snakayama 
816c6496b6Snakayama /*
826c6496b6Snakayama  * The fegetexceptflag() function stores an implementation-defined
836c6496b6Snakayama  * representation of the states of the floating-point status flags indicated
846c6496b6Snakayama  * by the argument excepts in the object pointed to by the argument flagp.
856c6496b6Snakayama  */
866c6496b6Snakayama int
fegetexceptflag(fexcept_t * flagp,int excepts)876c6496b6Snakayama fegetexceptflag(fexcept_t *flagp, int excepts)
886c6496b6Snakayama {
896c6496b6Snakayama 	fexcept_t r;
906c6496b6Snakayama 	int ex;
916c6496b6Snakayama 
926c6496b6Snakayama 	_DIAGASSERT(flagp != NULL);
936c6496b6Snakayama 	_DIAGASSERT((excepts & ~_FE_ALL_EXCEPT) == 0);
946c6496b6Snakayama 
956c6496b6Snakayama 	ex = excepts & FE_ALL_EXCEPT;
966c6496b6Snakayama 
976c6496b6Snakayama 	__stfsr(&r);
986c6496b6Snakayama 	*flagp = r & ex;
996c6496b6Snakayama 
1006c6496b6Snakayama 	/* Success */
1016c6496b6Snakayama 	return 0;
1026c6496b6Snakayama }
1036c6496b6Snakayama 
1046c6496b6Snakayama 
1056c6496b6Snakayama /*
1066c6496b6Snakayama  * This function sets the floating-point status flags indicated by the argument
1076c6496b6Snakayama  * `excepts' to the states stored in the object pointed to by `flagp'. It does
1086c6496b6Snakayama  * NOT raise any floating-point exceptions, but only sets the state of the flags.
1096c6496b6Snakayama  */
1106c6496b6Snakayama int
fesetexceptflag(const fexcept_t * flagp,int excepts)1116c6496b6Snakayama fesetexceptflag(const fexcept_t *flagp, int excepts)
1126c6496b6Snakayama {
1136c6496b6Snakayama 	fexcept_t r;
1146c6496b6Snakayama 	int ex;
1156c6496b6Snakayama 
1166c6496b6Snakayama 	_DIAGASSERT(flagp != NULL);
1176c6496b6Snakayama 	_DIAGASSERT((excepts & ~FE_ALL_EXCEPT) == 0);
1186c6496b6Snakayama 
1196c6496b6Snakayama 	ex = excepts & FE_ALL_EXCEPT;
1206c6496b6Snakayama 
1216c6496b6Snakayama 	__stfsr(&r);
1226c6496b6Snakayama 	r &= ~ex;
1236c6496b6Snakayama 	r |= *flagp & ex;
1246c6496b6Snakayama 	__ldfsr(r);
1256c6496b6Snakayama 
1266c6496b6Snakayama 	/* Success */
1276c6496b6Snakayama 	return 0;
1286c6496b6Snakayama }
1296c6496b6Snakayama 
1306c6496b6Snakayama /*
1316c6496b6Snakayama  * The feraiseexcept() function raises the supported floating-point exceptions
1326c6496b6Snakayama  * represented by the argument `excepts'.
1336c6496b6Snakayama  *
1346c6496b6Snakayama  * The order in which these floating-point exceptions are raised is unspecified
1356c6496b6Snakayama  * (by the standard).
1366c6496b6Snakayama  */
1376c6496b6Snakayama int
feraiseexcept(int excepts)1386c6496b6Snakayama feraiseexcept(int excepts)
1396c6496b6Snakayama {
1406c6496b6Snakayama 	volatile double d;
1416c6496b6Snakayama 	int ex;
1426c6496b6Snakayama 
1436c6496b6Snakayama 	_DIAGASSERT((excepts & ~FE_ALL_EXCEPT) == 0);
1446c6496b6Snakayama 
1456c6496b6Snakayama 	ex = excepts & FE_ALL_EXCEPT;
1466c6496b6Snakayama 
1476c6496b6Snakayama 	/*
1486c6496b6Snakayama 	 * With a compiler that supports the FENV_ACCESS pragma properly, simple
1496c6496b6Snakayama 	 * expressions like '0.0 / 0.0' should be sufficient to generate traps.
1506c6496b6Snakayama 	 * Unfortunately, we need to bring a volatile variable into the equation
1516c6496b6Snakayama 	 * to prevent incorrect optimizations.
1526c6496b6Snakayama 	 */
1536c6496b6Snakayama 	if (ex & FE_INVALID) {
1546c6496b6Snakayama 		d = 0.0;
1556c6496b6Snakayama 		d = 0.0 / d;
1566c6496b6Snakayama 	}
1576c6496b6Snakayama 	if (ex & FE_DIVBYZERO) {
1586c6496b6Snakayama 		d = 0.0;
1596c6496b6Snakayama 		d = 1.0 / d;
1606c6496b6Snakayama 	}
1616c6496b6Snakayama 	if (ex & FE_OVERFLOW) {
1626c6496b6Snakayama 		d = 0x1.ffp1023;
1636c6496b6Snakayama 		d *= 2.0;
1646c6496b6Snakayama 	}
1656c6496b6Snakayama 	if (ex & FE_UNDERFLOW) {
1666c6496b6Snakayama 		d = 0x1p-1022;
1676c6496b6Snakayama 		d /= 0x1p1023;
1686c6496b6Snakayama 	}
1696c6496b6Snakayama 	if (ex & FE_INEXACT) {
1706c6496b6Snakayama 		d = 0x1p-1022;
1716c6496b6Snakayama 		d += 1.0;
1726c6496b6Snakayama 	}
1736c6496b6Snakayama 
1746c6496b6Snakayama 	/* Success */
1756c6496b6Snakayama 	return 0;
1766c6496b6Snakayama }
1776c6496b6Snakayama 
1786c6496b6Snakayama /*
1796c6496b6Snakayama  * The fetestexcept() function determines which of a specified subset of the
1806c6496b6Snakayama  * floating-point exception flags are currently set. The `excepts' argument
1816c6496b6Snakayama  * specifies the floating-point status flags to be queried.
1826c6496b6Snakayama  */
1836c6496b6Snakayama int
fetestexcept(int excepts)1846c6496b6Snakayama fetestexcept(int excepts)
1856c6496b6Snakayama {
1866c6496b6Snakayama 	fexcept_t r;
1876c6496b6Snakayama 
1886c6496b6Snakayama 	_DIAGASSERT((excepts & ~FE_ALL_EXCEPT) == 0);
1896c6496b6Snakayama 
1906c6496b6Snakayama 	__stfsr(&r);
1916c6496b6Snakayama 
1926c6496b6Snakayama 	return r & (excepts & FE_ALL_EXCEPT);
1936c6496b6Snakayama }
1946c6496b6Snakayama 
1956c6496b6Snakayama /*
1966c6496b6Snakayama  * The fegetround() function gets the current rounding direction.
1976c6496b6Snakayama  */
1986c6496b6Snakayama int
fegetround(void)1996c6496b6Snakayama fegetround(void)
2006c6496b6Snakayama {
2016c6496b6Snakayama 	fenv_t r;
2026c6496b6Snakayama 
2036c6496b6Snakayama 	__stfsr(&r);
2046c6496b6Snakayama 
2056c6496b6Snakayama 	return (r >> _ROUND_SHIFT) & _ROUND_MASK;
2066c6496b6Snakayama }
2076c6496b6Snakayama 
2086c6496b6Snakayama /*
2096c6496b6Snakayama  * The fesetround() function establishes the rounding direction represented by
2106c6496b6Snakayama  * its argument `round'. If the argument is not equal to the value of a rounding
2116c6496b6Snakayama  * direction macro, the rounding direction is not changed.
2126c6496b6Snakayama  */
2136c6496b6Snakayama int
fesetround(int round)2146c6496b6Snakayama fesetround(int round)
2156c6496b6Snakayama {
2166c6496b6Snakayama 	fenv_t r;
2176c6496b6Snakayama 
2186c6496b6Snakayama 	_DIAGASSERT((round & ~_ROUND_MASK) == 0);
2196c6496b6Snakayama 	if (round & ~_ROUND_MASK)
2206c6496b6Snakayama 		return -1;
2216c6496b6Snakayama 
2226c6496b6Snakayama 	__stfsr(&r);
2236c6496b6Snakayama 	r &= ~(_ROUND_MASK << _ROUND_SHIFT);
2246c6496b6Snakayama 	r |= round << _ROUND_SHIFT;
2256c6496b6Snakayama 	__ldfsr(r);
2266c6496b6Snakayama 
2276c6496b6Snakayama 	/* Success */
2286c6496b6Snakayama 	return 0;
2296c6496b6Snakayama }
2306c6496b6Snakayama 
2316c6496b6Snakayama /*
2326c6496b6Snakayama  * The fegetenv() function attempts to store the current floating-point
2336c6496b6Snakayama  * environment in the object pointed to by envp.
2346c6496b6Snakayama  */
2356c6496b6Snakayama int
fegetenv(fenv_t * envp)2366c6496b6Snakayama fegetenv(fenv_t *envp)
2376c6496b6Snakayama {
2386c6496b6Snakayama 	_DIAGASSERT(envp != NULL);
2396c6496b6Snakayama 
2406c6496b6Snakayama 	__stfsr(envp);
2416c6496b6Snakayama 
2426c6496b6Snakayama 	/* Success */
2436c6496b6Snakayama 	return 0;
2446c6496b6Snakayama }
2456c6496b6Snakayama 
2466c6496b6Snakayama 
2476c6496b6Snakayama /*
2486c6496b6Snakayama  * The feholdexcept() function saves the current floating-point environment
2496c6496b6Snakayama  * in the object pointed to by envp, clears the floating-point status flags, and
2506c6496b6Snakayama  * then installs a non-stop (continue on floating-point exceptions) mode, if
2516c6496b6Snakayama  * available, for all floating-point exceptions.
2526c6496b6Snakayama  */
2536c6496b6Snakayama int
feholdexcept(fenv_t * envp)2546c6496b6Snakayama feholdexcept(fenv_t *envp)
2556c6496b6Snakayama {
2566c6496b6Snakayama 	fenv_t r;
2576c6496b6Snakayama 
2586c6496b6Snakayama 	_DIAGASSERT(envp != NULL);
2596c6496b6Snakayama 
2606c6496b6Snakayama 	__stfsr(&r);
2616c6496b6Snakayama 	*envp = r;
2626c6496b6Snakayama 	r &= ~(FE_ALL_EXCEPT | _ENABLE_MASK);
2636c6496b6Snakayama 	__ldfsr(r);
2646c6496b6Snakayama 
2656c6496b6Snakayama 	/* Success */
2666c6496b6Snakayama 	return 0;
2676c6496b6Snakayama }
2686c6496b6Snakayama 
2696c6496b6Snakayama /*
2706c6496b6Snakayama  * The fesetenv() function attempts to establish the floating-point environment
2716c6496b6Snakayama  * represented by the object pointed to by envp. The argument `envp' points
2726c6496b6Snakayama  * to an object set by a call to fegetenv() or feholdexcept(), or equal a
2736c6496b6Snakayama  * floating-point environment macro. The fesetenv() function does not raise
2746c6496b6Snakayama  * floating-point exceptions, but only installs the state of the floating-point
2756c6496b6Snakayama  * status flags represented through its argument.
2766c6496b6Snakayama  */
2776c6496b6Snakayama int
fesetenv(const fenv_t * envp)2786c6496b6Snakayama fesetenv(const fenv_t *envp)
2796c6496b6Snakayama {
2806c6496b6Snakayama 	_DIAGASSERT(envp != NULL);
2816c6496b6Snakayama 
2826c6496b6Snakayama 	__ldfsr(*envp);
2836c6496b6Snakayama 
2846c6496b6Snakayama 	/* Success */
2856c6496b6Snakayama 	return 0;
2866c6496b6Snakayama }
2876c6496b6Snakayama 
2886c6496b6Snakayama 
2896c6496b6Snakayama /*
2906c6496b6Snakayama  * The feupdateenv() function saves the currently raised floating-point
2916c6496b6Snakayama  * exceptions in its automatic storage, installs the floating-point environment
2926c6496b6Snakayama  * represented by the object pointed to by `envp', and then raises the saved
2936c6496b6Snakayama  * floating-point exceptions. The argument `envp' shall point to an object set
2946c6496b6Snakayama  * by a call to feholdexcept() or fegetenv(), or equal a floating-point
2956c6496b6Snakayama  * environment macro.
2966c6496b6Snakayama  */
2976c6496b6Snakayama int
feupdateenv(const fenv_t * envp)2986c6496b6Snakayama feupdateenv(const fenv_t *envp)
2996c6496b6Snakayama {
3006c6496b6Snakayama 	fexcept_t r;
3016c6496b6Snakayama 
3026c6496b6Snakayama 	_DIAGASSERT(envp != NULL);
3036c6496b6Snakayama 
3046c6496b6Snakayama 	__stfsr(&r);
3056c6496b6Snakayama 	__ldfsr(*envp);
3066c6496b6Snakayama 
3076c6496b6Snakayama 	_DIAGASSERT((r & ~FE_ALL_EXCEPT) == 0);
3086c6496b6Snakayama 	feraiseexcept(r & FE_ALL_EXCEPT);
3096c6496b6Snakayama 
3106c6496b6Snakayama 	/* Success */
3116c6496b6Snakayama 	return 0;
3126c6496b6Snakayama }
3136c6496b6Snakayama 
3146c6496b6Snakayama /*
315*35339755Sandvar  * The following functions are extensions to the standard
3166c6496b6Snakayama  */
3176c6496b6Snakayama int
feenableexcept(int mask)3186c6496b6Snakayama feenableexcept(int mask)
3196c6496b6Snakayama {
3206c6496b6Snakayama 	fenv_t old_r, new_r;
3216c6496b6Snakayama 
3226c6496b6Snakayama 	__stfsr(&old_r);
3236c6496b6Snakayama 	new_r = old_r | ((mask & FE_ALL_EXCEPT) << _FPUSW_SHIFT);
3246c6496b6Snakayama 	__ldfsr(new_r);
3256c6496b6Snakayama 
3266c6496b6Snakayama 	return (old_r >> _FPUSW_SHIFT) & FE_ALL_EXCEPT;
3276c6496b6Snakayama }
3286c6496b6Snakayama 
3296c6496b6Snakayama int
fedisableexcept(int mask)3306c6496b6Snakayama fedisableexcept(int mask)
3316c6496b6Snakayama {
3326c6496b6Snakayama 	fenv_t old_r, new_r;
3336c6496b6Snakayama 
3346c6496b6Snakayama 	__stfsr(&old_r);
3356c6496b6Snakayama 	new_r = old_r & ~((mask & FE_ALL_EXCEPT) << _FPUSW_SHIFT);
3366c6496b6Snakayama 	__ldfsr(new_r);
3376c6496b6Snakayama 
3386c6496b6Snakayama 	return (old_r >> _FPUSW_SHIFT) & FE_ALL_EXCEPT;
3396c6496b6Snakayama }
3406c6496b6Snakayama 
3416c6496b6Snakayama int
fegetexcept(void)3426c6496b6Snakayama fegetexcept(void)
3436c6496b6Snakayama {
3446c6496b6Snakayama 	fenv_t r;
3456c6496b6Snakayama 
3466c6496b6Snakayama 	__stfsr(&r);
3476c6496b6Snakayama 	return (r & _ENABLE_MASK) >> _FPUSW_SHIFT;
3486c6496b6Snakayama }
349