xref: /openbsd-src/lib/libm/arch/sh/fenv.c (revision 2c53affbcc0119d6480b86c18f2790523b6a0aad)
1*2c53affbSjmc /*	$OpenBSD: fenv.c,v 1.6 2022/12/27 17:10:07 jmc Exp $	*/
26e40b843Smartynas 
36e40b843Smartynas /*
46e40b843Smartynas  * Copyright (c) 2011 Martynas Venckus <martynas@openbsd.org>
56e40b843Smartynas  *
66e40b843Smartynas  * Permission to use, copy, modify, and distribute this software for any
76e40b843Smartynas  * purpose with or without fee is hereby granted, provided that the above
86e40b843Smartynas  * copyright notice and this permission notice appear in all copies.
96e40b843Smartynas  *
106e40b843Smartynas  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
116e40b843Smartynas  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
126e40b843Smartynas  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
136e40b843Smartynas  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
146e40b843Smartynas  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
156e40b843Smartynas  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
166e40b843Smartynas  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
176e40b843Smartynas  */
186e40b843Smartynas 
196e40b843Smartynas #include <fenv.h>
206e40b843Smartynas 
216e40b843Smartynas extern	unsigned int	__fpscr_values[2];
226e40b843Smartynas 
236e40b843Smartynas /*
246e40b843Smartynas  * The following constant represents the default floating-point environment
256e40b843Smartynas  * (that is, the one installed at program startup) and has type pointer to
266e40b843Smartynas  * const-qualified fenv_t.
276e40b843Smartynas  *
286e40b843Smartynas  * It can be used as an argument to the functions within the <fenv.h> header
296e40b843Smartynas  * that manage the floating-point environment, namely fesetenv() and
306e40b843Smartynas  * feupdateenv().
316e40b843Smartynas  */
326e40b843Smartynas fenv_t __fe_dfl_env = 0xc0000;
336e40b843Smartynas 
346e40b843Smartynas /*
356e40b843Smartynas  * The feclearexcept() function clears the supported floating-point exceptions
366e40b843Smartynas  * represented by `excepts'.
376e40b843Smartynas  */
386e40b843Smartynas int
feclearexcept(int excepts)396e40b843Smartynas feclearexcept(int excepts)
406e40b843Smartynas {
416e40b843Smartynas 	unsigned int fpscr;
426e40b843Smartynas 
436e40b843Smartynas 	excepts &= FE_ALL_EXCEPT;
446e40b843Smartynas 
45d6f349c8Smartynas 	/* Store the current floating-point status and control register */
46b5aa3b33Sguenther 	__asm__ volatile ("sts fpscr, %0" : "=r" (fpscr));
476e40b843Smartynas 
486e40b843Smartynas 	/* Clear the requested floating-point exceptions */
496e40b843Smartynas 	fpscr &= ~excepts;
506e40b843Smartynas 	__fpscr_values[0] &= ~excepts;
516e40b843Smartynas 	__fpscr_values[1] &= ~excepts;
526e40b843Smartynas 
53d6f349c8Smartynas 	/* Load the floating-point status and control register */
54b5aa3b33Sguenther 	__asm__ volatile ("lds %0, fpscr" : : "r" (fpscr));
556e40b843Smartynas 
566e40b843Smartynas 	return (0);
576e40b843Smartynas }
582f2c0062Sguenther DEF_STD(feclearexcept);
596e40b843Smartynas 
606e40b843Smartynas /*
616e40b843Smartynas  * The fegetexceptflag() function stores an implementation-defined
626e40b843Smartynas  * representation of the states of the floating-point status flags indicated by
636e40b843Smartynas  * the argument excepts in the object pointed to by the argument flagp.
646e40b843Smartynas  */
656e40b843Smartynas int
fegetexceptflag(fexcept_t * flagp,int excepts)666e40b843Smartynas fegetexceptflag(fexcept_t *flagp, int excepts)
676e40b843Smartynas {
686e40b843Smartynas 	unsigned int fpscr;
696e40b843Smartynas 
706e40b843Smartynas 	excepts &= FE_ALL_EXCEPT;
716e40b843Smartynas 
72d6f349c8Smartynas 	/* Store the current floating-point status and control register */
73b5aa3b33Sguenther 	__asm__ volatile ("sts fpscr, %0" : "=r" (fpscr));
746e40b843Smartynas 
756e40b843Smartynas 	/* Store the results in flagp */
766e40b843Smartynas 	*flagp = fpscr & excepts;
776e40b843Smartynas 
786e40b843Smartynas 	return (0);
796e40b843Smartynas }
806e40b843Smartynas 
816e40b843Smartynas /*
826e40b843Smartynas  * The feraiseexcept() function raises the supported floating-point exceptions
836e40b843Smartynas  * represented by the argument `excepts'.
846e40b843Smartynas  */
856e40b843Smartynas int
feraiseexcept(int excepts)866e40b843Smartynas feraiseexcept(int excepts)
876e40b843Smartynas {
886e40b843Smartynas 	volatile double d;
896e40b843Smartynas 
906e40b843Smartynas 	excepts &= FE_ALL_EXCEPT;
916e40b843Smartynas 
926e40b843Smartynas 	/*
936e40b843Smartynas 	 * With a compiler that supports the FENV_ACCESS pragma
946e40b843Smartynas 	 * properly, simple expressions like '0.0 / 0.0' should
956e40b843Smartynas 	 * be sufficient to generate traps.  Unfortunately, we
966e40b843Smartynas 	 * need to bring a volatile variable into the equation
976e40b843Smartynas 	 * to prevent incorrect optimizations.
986e40b843Smartynas 	 */
996e40b843Smartynas 	if (excepts & FE_INVALID) {
1006e40b843Smartynas 		d = 0.0;
1016e40b843Smartynas 		d = 0.0 / d;
1026e40b843Smartynas 	}
1036e40b843Smartynas 	if (excepts & FE_DIVBYZERO) {
1046e40b843Smartynas 		d = 0.0;
1056e40b843Smartynas 		d = 1.0 / d;
1066e40b843Smartynas 	}
1076e40b843Smartynas 	if (excepts & FE_OVERFLOW) {
1086e40b843Smartynas 		d = 0x1.ffp1023;
1096e40b843Smartynas 		d *= 2.0;
1106e40b843Smartynas 	}
1116e40b843Smartynas 	if (excepts & FE_UNDERFLOW) {
1126e40b843Smartynas 		d = 0x1p-1022;
1136e40b843Smartynas 		d /= 0x1p1023;
1146e40b843Smartynas 	}
1156e40b843Smartynas 	if (excepts & FE_INEXACT) {
1166e40b843Smartynas 		d = 0x1p-1022;
1176e40b843Smartynas 		d += 1.0;
1186e40b843Smartynas 	}
1196e40b843Smartynas 
1206e40b843Smartynas 	return (0);
1216e40b843Smartynas }
1222f2c0062Sguenther DEF_STD(feraiseexcept);
1236e40b843Smartynas 
1246e40b843Smartynas /*
1256e40b843Smartynas  * This function sets the floating-point status flags indicated by the argument
1266e40b843Smartynas  * `excepts' to the states stored in the object pointed to by `flagp'. It does
1276e40b843Smartynas  * NOT raise any floating-point exceptions, but only sets the state of the flags.
1286e40b843Smartynas  */
1296e40b843Smartynas int
fesetexceptflag(const fexcept_t * flagp,int excepts)1306e40b843Smartynas fesetexceptflag(const fexcept_t *flagp, int excepts)
1316e40b843Smartynas {
1326e40b843Smartynas 	unsigned int fpscr;
1336e40b843Smartynas 
1346e40b843Smartynas 	excepts &= FE_ALL_EXCEPT;
1356e40b843Smartynas 
136d6f349c8Smartynas 	/* Store the current floating-point status and control register */
137b5aa3b33Sguenther 	__asm__ volatile ("sts fpscr, %0" : "=r" (fpscr));
1386e40b843Smartynas 
1396e40b843Smartynas 	/* Set the requested status flags */
1406e40b843Smartynas 	fpscr &= ~excepts;
1416e40b843Smartynas 	__fpscr_values[0] &= ~excepts;
1426e40b843Smartynas 	__fpscr_values[1] &= ~excepts;
1436e40b843Smartynas 
1446e40b843Smartynas 	fpscr |= *flagp & excepts;
1456e40b843Smartynas 	__fpscr_values[0] |= *flagp & excepts;
1466e40b843Smartynas 	__fpscr_values[1] |= *flagp & excepts;
1476e40b843Smartynas 
148d6f349c8Smartynas 	/* Load the floating-point status and control register */
149b5aa3b33Sguenther 	__asm__ volatile ("lds %0, fpscr" : : "r" (fpscr));
1506e40b843Smartynas 
1516e40b843Smartynas 	return (0);
1526e40b843Smartynas }
1532f2c0062Sguenther DEF_STD(fesetexceptflag);
1546e40b843Smartynas 
1556e40b843Smartynas /*
1566e40b843Smartynas  * The fetestexcept() function determines which of a specified subset of the
1576e40b843Smartynas  * floating-point exception flags are currently set. The `excepts' argument
1586e40b843Smartynas  * specifies the floating-point status flags to be queried.
1596e40b843Smartynas  */
1606e40b843Smartynas int
fetestexcept(int excepts)1616e40b843Smartynas fetestexcept(int excepts)
1626e40b843Smartynas {
1636e40b843Smartynas 	unsigned int fpscr;
1646e40b843Smartynas 
1656e40b843Smartynas 	excepts &= FE_ALL_EXCEPT;
1666e40b843Smartynas 
167d6f349c8Smartynas 	/* Store the current floating-point status and control register */
168b5aa3b33Sguenther 	__asm__ volatile ("sts fpscr, %0" : "=r" (fpscr));
1696e40b843Smartynas 
1706e40b843Smartynas 	return (fpscr & excepts);
1716e40b843Smartynas }
1722f2c0062Sguenther DEF_STD(fetestexcept);
1736e40b843Smartynas 
1746e40b843Smartynas /*
1756e40b843Smartynas  * The fegetround() function gets the current rounding direction.
1766e40b843Smartynas  */
1776e40b843Smartynas int
fegetround(void)1786e40b843Smartynas fegetround(void)
1796e40b843Smartynas {
1806e40b843Smartynas 	unsigned int fpscr;
1816e40b843Smartynas 
182d6f349c8Smartynas 	/* Store the current floating-point status and control register */
183b5aa3b33Sguenther 	__asm__ volatile ("sts fpscr, %0" : "=r" (fpscr));
1846e40b843Smartynas 
1856e40b843Smartynas 	return (fpscr & _ROUND_MASK);
1866e40b843Smartynas }
1872f2c0062Sguenther DEF_STD(fegetround);
1886e40b843Smartynas 
1896e40b843Smartynas /*
1906e40b843Smartynas  * The fesetround() function establishes the rounding direction represented by
1916e40b843Smartynas  * its argument `round'. If the argument is not equal to the value of a rounding
1926e40b843Smartynas  * direction macro, the rounding direction is not changed.
1936e40b843Smartynas  */
1946e40b843Smartynas int
fesetround(int round)1956e40b843Smartynas fesetround(int round)
1966e40b843Smartynas {
1976e40b843Smartynas 	unsigned int fpscr;
1986e40b843Smartynas 
1996e40b843Smartynas 	/* Check whether requested rounding direction is supported */
2006e40b843Smartynas 	if (round & ~_ROUND_MASK)
2016e40b843Smartynas 		return (-1);
2026e40b843Smartynas 
203d6f349c8Smartynas 	/* Store the current floating-point status and control register */
204b5aa3b33Sguenther 	__asm__ volatile ("sts fpscr, %0" : "=r" (fpscr));
2056e40b843Smartynas 
206d6f349c8Smartynas 	/* Set the rounding direction */
2076e40b843Smartynas 	fpscr &= ~_ROUND_MASK;
2086e40b843Smartynas 	__fpscr_values[0] &= ~_ROUND_MASK;
2096e40b843Smartynas 	__fpscr_values[1] &= ~_ROUND_MASK;
2106e40b843Smartynas 
2116e40b843Smartynas 	fpscr |= round;
2126e40b843Smartynas 	__fpscr_values[0] |= round;
2136e40b843Smartynas 	__fpscr_values[1] |= round;
2146e40b843Smartynas 
215d6f349c8Smartynas 	/* Load the floating-point status and control register */
216b5aa3b33Sguenther 	__asm__ volatile ("lds %0, fpscr" : : "r" (fpscr));
2176e40b843Smartynas 
2186e40b843Smartynas 	return (0);
2196e40b843Smartynas }
2202f2c0062Sguenther DEF_STD(fesetround);
2216e40b843Smartynas 
2226e40b843Smartynas /*
2236e40b843Smartynas  * The fegetenv() function attempts to store the current floating-point
2246e40b843Smartynas  * environment in the object pointed to by envp.
2256e40b843Smartynas  */
2266e40b843Smartynas int
fegetenv(fenv_t * envp)2276e40b843Smartynas fegetenv(fenv_t *envp)
2286e40b843Smartynas {
229d6f349c8Smartynas 	/* Store the current floating-point status and control register */
230b5aa3b33Sguenther 	__asm__ volatile ("sts fpscr, %0" : "=r" (*envp));
2316e40b843Smartynas 
2326e40b843Smartynas 	return (0);
2336e40b843Smartynas }
2342f2c0062Sguenther DEF_STD(fegetenv);
2356e40b843Smartynas 
2366e40b843Smartynas /*
2376e40b843Smartynas  * The feholdexcept() function saves the current floating-point environment
2386e40b843Smartynas  * in the object pointed to by envp, clears the floating-point status flags, and
2396e40b843Smartynas  * then installs a non-stop (continue on floating-point exceptions) mode, if
2406e40b843Smartynas  * available, for all floating-point exceptions.
2416e40b843Smartynas  */
2426e40b843Smartynas int
feholdexcept(fenv_t * envp)2436e40b843Smartynas feholdexcept(fenv_t *envp)
2446e40b843Smartynas {
2456e40b843Smartynas 	unsigned int fpscr;
2466e40b843Smartynas 
247d6f349c8Smartynas 	/* Store the current floating-point status and control register */
248b5aa3b33Sguenther 	__asm__ volatile ("sts fpscr, %0" : "=r" (fpscr));
2496e40b843Smartynas 
2506e40b843Smartynas 	*envp = fpscr;
2516e40b843Smartynas 
252d6f349c8Smartynas 	/* Clear exception flags in FPSCR */
2536e40b843Smartynas 	fpscr &= ~FE_ALL_EXCEPT;
2546e40b843Smartynas 	__fpscr_values[0] &= ~FE_ALL_EXCEPT;
2556e40b843Smartynas 	__fpscr_values[1] &= ~FE_ALL_EXCEPT;
2566e40b843Smartynas 
2576e40b843Smartynas 	/* Mask all exceptions */
258d6f349c8Smartynas 	fpscr &= ~(FE_ALL_EXCEPT << _MASK_SHIFT);
259d6f349c8Smartynas 	__fpscr_values[0] &= ~(FE_ALL_EXCEPT << _MASK_SHIFT);
260d6f349c8Smartynas 	__fpscr_values[1] &= ~(FE_ALL_EXCEPT << _MASK_SHIFT);
2616e40b843Smartynas 
262d6f349c8Smartynas 	/* Load the floating-point status and control register */
263b5aa3b33Sguenther 	__asm__ volatile ("lds %0, fpscr" : : "r" (fpscr));
2646e40b843Smartynas 
2656e40b843Smartynas 	return (0);
2666e40b843Smartynas }
2672f2c0062Sguenther DEF_STD(feholdexcept);
2686e40b843Smartynas 
2696e40b843Smartynas /*
2706e40b843Smartynas  * The fesetenv() function attempts to establish the floating-point environment
2716e40b843Smartynas  * represented by the object pointed to by envp. The argument `envp' points
2726e40b843Smartynas  * to an object set by a call to fegetenv() or feholdexcept(), or equal a
2736e40b843Smartynas  * floating-point environment macro. The fesetenv() function does not raise
2746e40b843Smartynas  * floating-point exceptions, but only installs the state of the floating-point
2756e40b843Smartynas  * status flags represented through its argument.
2766e40b843Smartynas  */
2776e40b843Smartynas int
fesetenv(const fenv_t * envp)2786e40b843Smartynas fesetenv(const fenv_t *envp)
2796e40b843Smartynas {
2806e40b843Smartynas 	unsigned int fpscr;
2816e40b843Smartynas 
282d6f349c8Smartynas 	/* Store the current floating-point status and control register */
283b5aa3b33Sguenther 	__asm__ volatile ("sts fpscr, %0" : "=r" (fpscr));
2846e40b843Smartynas 
2856e40b843Smartynas 	/* Set the requested flags */
286d6f349c8Smartynas 	fpscr &= ~((FE_ALL_EXCEPT << _MASK_SHIFT) | _ROUND_MASK |
2876e40b843Smartynas 	    FE_ALL_EXCEPT);
288d6f349c8Smartynas 	__fpscr_values[0] &= ~((FE_ALL_EXCEPT << _MASK_SHIFT) | _ROUND_MASK |
2896e40b843Smartynas 	    FE_ALL_EXCEPT);
290d6f349c8Smartynas 	__fpscr_values[1] &= ~((FE_ALL_EXCEPT << _MASK_SHIFT) | _ROUND_MASK |
2916e40b843Smartynas 	    FE_ALL_EXCEPT);
2926e40b843Smartynas 
293d6f349c8Smartynas 	fpscr |= *envp & ((FE_ALL_EXCEPT << _MASK_SHIFT) | _ROUND_MASK |
2946e40b843Smartynas 	    FE_ALL_EXCEPT);
295d6f349c8Smartynas 	__fpscr_values[0] |= *envp & ((FE_ALL_EXCEPT << _MASK_SHIFT) |
2966e40b843Smartynas 	    _ROUND_MASK | FE_ALL_EXCEPT);
297d6f349c8Smartynas 	__fpscr_values[1] |= *envp & ((FE_ALL_EXCEPT << _MASK_SHIFT) |
2986e40b843Smartynas 	    _ROUND_MASK | FE_ALL_EXCEPT);
2996e40b843Smartynas 
300d6f349c8Smartynas 	/* Load the floating-point status and control register */
301b5aa3b33Sguenther 	__asm__ volatile ("lds %0, fpscr" : : "r" (fpscr));
3026e40b843Smartynas 
3036e40b843Smartynas 	return (0);
3046e40b843Smartynas }
3052f2c0062Sguenther DEF_STD(fesetenv);
3066e40b843Smartynas 
3076e40b843Smartynas /*
3086e40b843Smartynas  * The feupdateenv() function saves the currently raised floating-point
3096e40b843Smartynas  * exceptions in its automatic storage, installs the floating-point environment
3106e40b843Smartynas  * represented by the object pointed to by `envp', and then raises the saved
3116e40b843Smartynas  * floating-point exceptions. The argument `envp' shall point to an object set
3126e40b843Smartynas  * by a call to feholdexcept() or fegetenv(), or equal a floating-point
3136e40b843Smartynas  * environment macro.
3146e40b843Smartynas  */
3156e40b843Smartynas int
feupdateenv(const fenv_t * envp)3166e40b843Smartynas feupdateenv(const fenv_t *envp)
3176e40b843Smartynas {
3186e40b843Smartynas 	unsigned int fpscr;
3196e40b843Smartynas 
320d6f349c8Smartynas 	/* Store the current floating-point status and control register */
321b5aa3b33Sguenther 	__asm__ volatile ("sts fpscr, %0" : "=r" (fpscr));
3226e40b843Smartynas 
3236e40b843Smartynas 	/* Install new floating-point environment */
3246e40b843Smartynas 	fesetenv(envp);
3256e40b843Smartynas 
3266e40b843Smartynas 	/* Raise any previously accumulated exceptions */
3276e40b843Smartynas 	feraiseexcept(fpscr);
3286e40b843Smartynas 
3296e40b843Smartynas 	return (0);
3306e40b843Smartynas }
3312f2c0062Sguenther DEF_STD(feupdateenv);
3326e40b843Smartynas 
3336e40b843Smartynas /*
334*2c53affbSjmc  * The following functions are extensions to the standard
3356e40b843Smartynas  */
3366e40b843Smartynas int
feenableexcept(int mask)3376e40b843Smartynas feenableexcept(int mask)
3386e40b843Smartynas {
3396e40b843Smartynas 	unsigned int fpscr, omask;
3406e40b843Smartynas 
3416e40b843Smartynas 	mask &= FE_ALL_EXCEPT;
3426e40b843Smartynas 
343d6f349c8Smartynas 	/* Store the current floating-point status and control register */
344b5aa3b33Sguenther 	__asm__ volatile ("sts fpscr, %0" : "=r" (fpscr));
3456e40b843Smartynas 
346d6f349c8Smartynas 	omask = (fpscr >> _MASK_SHIFT) & FE_ALL_EXCEPT;
347d6f349c8Smartynas 	fpscr |= mask << _MASK_SHIFT;
348d6f349c8Smartynas 	__fpscr_values[0] |= mask << _MASK_SHIFT;
349d6f349c8Smartynas 	__fpscr_values[1] |= mask << _MASK_SHIFT;
3506e40b843Smartynas 
351d6f349c8Smartynas 	/* Load the floating-point status and control register */
352b5aa3b33Sguenther 	__asm__ volatile ("lds %0, fpscr" : : "r" (fpscr));
3536e40b843Smartynas 
3546e40b843Smartynas 	return (omask);
3556e40b843Smartynas 
3566e40b843Smartynas }
3576e40b843Smartynas 
3586e40b843Smartynas int
fedisableexcept(int mask)3596e40b843Smartynas fedisableexcept(int mask)
3606e40b843Smartynas {
3616e40b843Smartynas 	unsigned int fpscr, omask;
3626e40b843Smartynas 
3636e40b843Smartynas 	mask &= FE_ALL_EXCEPT;
3646e40b843Smartynas 
365d6f349c8Smartynas 	/* Store the current floating-point status and control register */
366b5aa3b33Sguenther 	__asm__ volatile ("sts fpscr, %0" : "=r" (fpscr));
3676e40b843Smartynas 
368d6f349c8Smartynas 	omask = (fpscr >> _MASK_SHIFT) & FE_ALL_EXCEPT;
369d6f349c8Smartynas 	fpscr &= ~(mask << _MASK_SHIFT);
370d6f349c8Smartynas 	__fpscr_values[0] &= ~(mask << _MASK_SHIFT);
371d6f349c8Smartynas 	__fpscr_values[1] &= ~(mask << _MASK_SHIFT);
3726e40b843Smartynas 
373d6f349c8Smartynas 	/* Load the floating-point status and control register */
374b5aa3b33Sguenther 	__asm__ volatile ("lds %0, fpscr" : : "r" (fpscr));
3756e40b843Smartynas 
3766e40b843Smartynas 	return (omask);
3776e40b843Smartynas }
3786e40b843Smartynas 
3796e40b843Smartynas int
fegetexcept(void)3806e40b843Smartynas fegetexcept(void)
3816e40b843Smartynas {
3826e40b843Smartynas 	unsigned int fpscr;
3836e40b843Smartynas 
384d6f349c8Smartynas 	/* Store the current floating-point status and control register */
385b5aa3b33Sguenther 	__asm__ volatile ("sts fpscr, %0" : "=r" (fpscr));
3866e40b843Smartynas 
387d6f349c8Smartynas 	return ((fpscr >> _MASK_SHIFT) & FE_ALL_EXCEPT);
3886e40b843Smartynas }
389