xref: /netbsd-src/lib/libm/arch/sparc/fenv.c (revision f9faf20aeffd68c90a9d1a577a17402726208619)
1*f9faf20aSandvar /*	$NetBSD: fenv.c,v 1.3 2021/09/03 21:54:59 andvar Exp $	*/
288e42b60Snakayama 
388e42b60Snakayama /*-
488e42b60Snakayama  * Copyright (c) 2004-2005 David Schultz <das@FreeBSD.ORG>
588e42b60Snakayama  * All rights reserved.
688e42b60Snakayama  *
788e42b60Snakayama  * Redistribution and use in source and binary forms, with or without
888e42b60Snakayama  * modification, are permitted provided that the following conditions
988e42b60Snakayama  * are met:
1088e42b60Snakayama  * 1. Redistributions of source code must retain the above copyright
1188e42b60Snakayama  *    notice, this list of conditions and the following disclaimer.
1288e42b60Snakayama  * 2. Redistributions in binary form must reproduce the above copyright
1388e42b60Snakayama  *    notice, this list of conditions and the following disclaimer in the
1488e42b60Snakayama  *    documentation and/or other materials provided with the distribution.
1588e42b60Snakayama  *
1688e42b60Snakayama  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1788e42b60Snakayama  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1888e42b60Snakayama  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1988e42b60Snakayama  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2088e42b60Snakayama  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2188e42b60Snakayama  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2288e42b60Snakayama  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2388e42b60Snakayama  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2488e42b60Snakayama  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2588e42b60Snakayama  */
2688e42b60Snakayama #include <sys/cdefs.h>
27*f9faf20aSandvar __RCSID("$NetBSD: fenv.c,v 1.3 2021/09/03 21:54:59 andvar Exp $");
287e30e943Schs 
297e30e943Schs #include "namespace.h"
3088e42b60Snakayama 
3188e42b60Snakayama #include <assert.h>
3288e42b60Snakayama #include <fenv.h>
3388e42b60Snakayama 
347e30e943Schs #ifdef __weak_alias
__weak_alias(feclearexcept,_feclearexcept)357e30e943Schs __weak_alias(feclearexcept,_feclearexcept)
367e30e943Schs __weak_alias(fedisableexcept,_fedisableexcept)
377e30e943Schs __weak_alias(feenableexcept,_feenableexcept)
387e30e943Schs __weak_alias(fegetenv,_fegetenv)
397e30e943Schs __weak_alias(fegetexcept,_fegetexcept)
407e30e943Schs __weak_alias(fegetexceptflag,_fegetexceptflag)
417e30e943Schs __weak_alias(fegetround,_fegetround)
427e30e943Schs __weak_alias(feholdexcept,_feholdexcept)
437e30e943Schs __weak_alias(feraiseexcept,_feraiseexcept)
447e30e943Schs __weak_alias(fesetenv,_fesetenv)
457e30e943Schs __weak_alias(fesetexceptflag,_fesetexceptflag)
467e30e943Schs __weak_alias(fesetround,_fesetround)
477e30e943Schs __weak_alias(fetestexcept,_fetestexcept)
487e30e943Schs __weak_alias(feupdateenv,_feupdateenv)
497e30e943Schs #endif
507e30e943Schs 
5188e42b60Snakayama /* Load floating-point state register (32bits) */
5288e42b60Snakayama #define	__ldfsr(__r)	__asm__	__volatile__		\
5388e42b60Snakayama 	("ld %0, %%fsr" : : "m" (__r))
5488e42b60Snakayama 
5588e42b60Snakayama /* Save floating-point state register (32bits) */
5688e42b60Snakayama #define	__stfsr(__r)	__asm__	__volatile__		\
5788e42b60Snakayama 	("st %%fsr, %0" : "=m" (*(__r)))
5888e42b60Snakayama 
5988e42b60Snakayama /*
6088e42b60Snakayama  * The feclearexcept() function clears the supported floating-point exceptions
6188e42b60Snakayama  * represented by `excepts'.
6288e42b60Snakayama  */
6388e42b60Snakayama int
6488e42b60Snakayama feclearexcept(int excepts)
6588e42b60Snakayama {
6688e42b60Snakayama 	fexcept_t r;
6788e42b60Snakayama 	int ex;
6888e42b60Snakayama 
6988e42b60Snakayama 	_DIAGASSERT((excepts & ~FE_ALL_EXCEPT) == 0);
7088e42b60Snakayama 
7188e42b60Snakayama 	ex = excepts & FE_ALL_EXCEPT;
7288e42b60Snakayama 
7388e42b60Snakayama 	__stfsr(&r);
7488e42b60Snakayama 	r &= ~ex;
7588e42b60Snakayama 	__ldfsr(r);
7688e42b60Snakayama 
7788e42b60Snakayama 	/* Success */
7888e42b60Snakayama 	return 0;
7988e42b60Snakayama }
8088e42b60Snakayama 
8188e42b60Snakayama /*
8288e42b60Snakayama  * The fegetexceptflag() function stores an implementation-defined
8388e42b60Snakayama  * representation of the states of the floating-point status flags indicated
8488e42b60Snakayama  * by the argument excepts in the object pointed to by the argument flagp.
8588e42b60Snakayama  */
8688e42b60Snakayama int
fegetexceptflag(fexcept_t * flagp,int excepts)8788e42b60Snakayama fegetexceptflag(fexcept_t *flagp, int excepts)
8888e42b60Snakayama {
8988e42b60Snakayama 	fexcept_t r;
9088e42b60Snakayama 	int ex;
9188e42b60Snakayama 
9288e42b60Snakayama 	_DIAGASSERT(flagp != NULL);
9388e42b60Snakayama 	_DIAGASSERT((excepts & ~_FE_ALL_EXCEPT) == 0);
9488e42b60Snakayama 
9588e42b60Snakayama 	ex = excepts & FE_ALL_EXCEPT;
9688e42b60Snakayama 
9788e42b60Snakayama 	__stfsr(&r);
9888e42b60Snakayama 	*flagp = r & ex;
9988e42b60Snakayama 
10088e42b60Snakayama 	/* Success */
10188e42b60Snakayama 	return 0;
10288e42b60Snakayama }
10388e42b60Snakayama 
10488e42b60Snakayama 
10588e42b60Snakayama /*
10688e42b60Snakayama  * This function sets the floating-point status flags indicated by the argument
10788e42b60Snakayama  * `excepts' to the states stored in the object pointed to by `flagp'. It does
10888e42b60Snakayama  * NOT raise any floating-point exceptions, but only sets the state of the flags.
10988e42b60Snakayama  */
11088e42b60Snakayama int
fesetexceptflag(const fexcept_t * flagp,int excepts)11188e42b60Snakayama fesetexceptflag(const fexcept_t *flagp, int excepts)
11288e42b60Snakayama {
11388e42b60Snakayama 	fexcept_t r;
11488e42b60Snakayama 	int ex;
11588e42b60Snakayama 
11688e42b60Snakayama 	_DIAGASSERT(flagp != NULL);
11788e42b60Snakayama 	_DIAGASSERT((excepts & ~FE_ALL_EXCEPT) == 0);
11888e42b60Snakayama 
11988e42b60Snakayama 	ex = excepts & FE_ALL_EXCEPT;
12088e42b60Snakayama 
12188e42b60Snakayama 	__stfsr(&r);
12288e42b60Snakayama 	r &= ~ex;
12388e42b60Snakayama 	r |= *flagp & ex;
12488e42b60Snakayama 	__ldfsr(r);
12588e42b60Snakayama 
12688e42b60Snakayama 	/* Success */
12788e42b60Snakayama 	return 0;
12888e42b60Snakayama }
12988e42b60Snakayama 
13088e42b60Snakayama /*
13188e42b60Snakayama  * The feraiseexcept() function raises the supported floating-point exceptions
13288e42b60Snakayama  * represented by the argument `excepts'.
13388e42b60Snakayama  *
13488e42b60Snakayama  * The order in which these floating-point exceptions are raised is unspecified
13588e42b60Snakayama  * (by the standard).
13688e42b60Snakayama  */
13788e42b60Snakayama int
feraiseexcept(int excepts)13888e42b60Snakayama feraiseexcept(int excepts)
13988e42b60Snakayama {
14088e42b60Snakayama 	volatile double d;
14188e42b60Snakayama 	int ex;
14288e42b60Snakayama 
14388e42b60Snakayama 	_DIAGASSERT((excepts & ~FE_ALL_EXCEPT) == 0);
14488e42b60Snakayama 
14588e42b60Snakayama 	ex = excepts & FE_ALL_EXCEPT;
14688e42b60Snakayama 
14788e42b60Snakayama 	/*
14888e42b60Snakayama 	 * With a compiler that supports the FENV_ACCESS pragma properly, simple
14988e42b60Snakayama 	 * expressions like '0.0 / 0.0' should be sufficient to generate traps.
15088e42b60Snakayama 	 * Unfortunately, we need to bring a volatile variable into the equation
15188e42b60Snakayama 	 * to prevent incorrect optimizations.
15288e42b60Snakayama 	 */
15388e42b60Snakayama 	if (ex & FE_INVALID) {
15488e42b60Snakayama 		d = 0.0;
15588e42b60Snakayama 		d = 0.0 / d;
15688e42b60Snakayama 	}
15788e42b60Snakayama 	if (ex & FE_DIVBYZERO) {
15888e42b60Snakayama 		d = 0.0;
15988e42b60Snakayama 		d = 1.0 / d;
16088e42b60Snakayama 	}
16188e42b60Snakayama 	if (ex & FE_OVERFLOW) {
16288e42b60Snakayama 		d = 0x1.ffp1023;
16388e42b60Snakayama 		d *= 2.0;
16488e42b60Snakayama 	}
16588e42b60Snakayama 	if (ex & FE_UNDERFLOW) {
16688e42b60Snakayama 		d = 0x1p-1022;
16788e42b60Snakayama 		d /= 0x1p1023;
16888e42b60Snakayama 	}
16988e42b60Snakayama 	if (ex & FE_INEXACT) {
17088e42b60Snakayama 		d = 0x1p-1022;
17188e42b60Snakayama 		d += 1.0;
17288e42b60Snakayama 	}
17388e42b60Snakayama 
17488e42b60Snakayama 	/* Success */
17588e42b60Snakayama 	return 0;
17688e42b60Snakayama }
17788e42b60Snakayama 
17888e42b60Snakayama /*
17988e42b60Snakayama  * The fetestexcept() function determines which of a specified subset of the
18088e42b60Snakayama  * floating-point exception flags are currently set. The `excepts' argument
18188e42b60Snakayama  * specifies the floating-point status flags to be queried.
18288e42b60Snakayama  */
18388e42b60Snakayama int
fetestexcept(int excepts)18488e42b60Snakayama fetestexcept(int excepts)
18588e42b60Snakayama {
18688e42b60Snakayama 	fexcept_t r;
18788e42b60Snakayama 
18888e42b60Snakayama 	_DIAGASSERT((excepts & ~FE_ALL_EXCEPT) == 0);
18988e42b60Snakayama 
19088e42b60Snakayama 	__stfsr(&r);
19188e42b60Snakayama 
19288e42b60Snakayama 	return r & (excepts & FE_ALL_EXCEPT);
19388e42b60Snakayama }
19488e42b60Snakayama 
19588e42b60Snakayama /*
19688e42b60Snakayama  * The fegetround() function gets the current rounding direction.
19788e42b60Snakayama  */
19888e42b60Snakayama int
fegetround(void)19988e42b60Snakayama fegetround(void)
20088e42b60Snakayama {
20188e42b60Snakayama 	fenv_t r;
20288e42b60Snakayama 
20388e42b60Snakayama 	__stfsr(&r);
20488e42b60Snakayama 
20588e42b60Snakayama 	return (r >> _ROUND_SHIFT) & _ROUND_MASK;
20688e42b60Snakayama }
20788e42b60Snakayama 
20888e42b60Snakayama /*
20988e42b60Snakayama  * The fesetround() function establishes the rounding direction represented by
21088e42b60Snakayama  * its argument `round'. If the argument is not equal to the value of a rounding
21188e42b60Snakayama  * direction macro, the rounding direction is not changed.
21288e42b60Snakayama  */
21388e42b60Snakayama int
fesetround(int round)21488e42b60Snakayama fesetround(int round)
21588e42b60Snakayama {
21688e42b60Snakayama 	fenv_t r;
21788e42b60Snakayama 
21888e42b60Snakayama 	_DIAGASSERT((round & ~_ROUND_MASK) == 0);
21988e42b60Snakayama 	if (round & ~_ROUND_MASK)
22088e42b60Snakayama 		return -1;
22188e42b60Snakayama 
22288e42b60Snakayama 	__stfsr(&r);
22388e42b60Snakayama 	r &= ~(_ROUND_MASK << _ROUND_SHIFT);
22488e42b60Snakayama 	r |= round << _ROUND_SHIFT;
22588e42b60Snakayama 	__ldfsr(r);
22688e42b60Snakayama 
22788e42b60Snakayama 	/* Success */
22888e42b60Snakayama 	return 0;
22988e42b60Snakayama }
23088e42b60Snakayama 
23188e42b60Snakayama /*
23288e42b60Snakayama  * The fegetenv() function attempts to store the current floating-point
23388e42b60Snakayama  * environment in the object pointed to by envp.
23488e42b60Snakayama  */
23588e42b60Snakayama int
fegetenv(fenv_t * envp)23688e42b60Snakayama fegetenv(fenv_t *envp)
23788e42b60Snakayama {
23888e42b60Snakayama 	_DIAGASSERT(envp != NULL);
23988e42b60Snakayama 
24088e42b60Snakayama 	__stfsr(envp);
24188e42b60Snakayama 
24288e42b60Snakayama 	/* Success */
24388e42b60Snakayama 	return 0;
24488e42b60Snakayama }
24588e42b60Snakayama 
24688e42b60Snakayama 
24788e42b60Snakayama /*
24888e42b60Snakayama  * The feholdexcept() function saves the current floating-point environment
24988e42b60Snakayama  * in the object pointed to by envp, clears the floating-point status flags, and
25088e42b60Snakayama  * then installs a non-stop (continue on floating-point exceptions) mode, if
25188e42b60Snakayama  * available, for all floating-point exceptions.
25288e42b60Snakayama  */
25388e42b60Snakayama int
feholdexcept(fenv_t * envp)25488e42b60Snakayama feholdexcept(fenv_t *envp)
25588e42b60Snakayama {
25688e42b60Snakayama 	fenv_t r;
25788e42b60Snakayama 
25888e42b60Snakayama 	_DIAGASSERT(envp != NULL);
25988e42b60Snakayama 
26088e42b60Snakayama 	__stfsr(&r);
26188e42b60Snakayama 	*envp = r;
26288e42b60Snakayama 	r &= ~(FE_ALL_EXCEPT | _ENABLE_MASK);
26388e42b60Snakayama 	__ldfsr(r);
26488e42b60Snakayama 
26588e42b60Snakayama 	/* Success */
26688e42b60Snakayama 	return 0;
26788e42b60Snakayama }
26888e42b60Snakayama 
26988e42b60Snakayama /*
27088e42b60Snakayama  * The fesetenv() function attempts to establish the floating-point environment
27188e42b60Snakayama  * represented by the object pointed to by envp. The argument `envp' points
27288e42b60Snakayama  * to an object set by a call to fegetenv() or feholdexcept(), or equal a
27388e42b60Snakayama  * floating-point environment macro. The fesetenv() function does not raise
27488e42b60Snakayama  * floating-point exceptions, but only installs the state of the floating-point
27588e42b60Snakayama  * status flags represented through its argument.
27688e42b60Snakayama  */
27788e42b60Snakayama int
fesetenv(const fenv_t * envp)27888e42b60Snakayama fesetenv(const fenv_t *envp)
27988e42b60Snakayama {
28088e42b60Snakayama 	_DIAGASSERT(envp != NULL);
28188e42b60Snakayama 
28288e42b60Snakayama 	__ldfsr(*envp);
28388e42b60Snakayama 
28488e42b60Snakayama 	/* Success */
28588e42b60Snakayama 	return 0;
28688e42b60Snakayama }
28788e42b60Snakayama 
28888e42b60Snakayama 
28988e42b60Snakayama /*
29088e42b60Snakayama  * The feupdateenv() function saves the currently raised floating-point
29188e42b60Snakayama  * exceptions in its automatic storage, installs the floating-point environment
29288e42b60Snakayama  * represented by the object pointed to by `envp', and then raises the saved
29388e42b60Snakayama  * floating-point exceptions. The argument `envp' shall point to an object set
29488e42b60Snakayama  * by a call to feholdexcept() or fegetenv(), or equal a floating-point
29588e42b60Snakayama  * environment macro.
29688e42b60Snakayama  */
29788e42b60Snakayama int
feupdateenv(const fenv_t * envp)29888e42b60Snakayama feupdateenv(const fenv_t *envp)
29988e42b60Snakayama {
30088e42b60Snakayama 	fexcept_t r;
30188e42b60Snakayama 
30288e42b60Snakayama 	_DIAGASSERT(envp != NULL);
30388e42b60Snakayama 
30488e42b60Snakayama 	__stfsr(&r);
30588e42b60Snakayama 	__ldfsr(*envp);
30688e42b60Snakayama 
30788e42b60Snakayama 	_DIAGASSERT((r & ~FE_ALL_EXCEPT) == 0);
30888e42b60Snakayama 	feraiseexcept(r & FE_ALL_EXCEPT);
30988e42b60Snakayama 
31088e42b60Snakayama 	/* Success */
31188e42b60Snakayama 	return 0;
31288e42b60Snakayama }
31388e42b60Snakayama 
31488e42b60Snakayama /*
315*f9faf20aSandvar  * The following functions are extensions to the standard
31688e42b60Snakayama  */
31788e42b60Snakayama int
feenableexcept(int mask)31888e42b60Snakayama feenableexcept(int mask)
31988e42b60Snakayama {
32088e42b60Snakayama 	fenv_t old_r, new_r;
32188e42b60Snakayama 
32288e42b60Snakayama 	__stfsr(&old_r);
32388e42b60Snakayama 	new_r = old_r | ((mask & FE_ALL_EXCEPT) << _FPUSW_SHIFT);
32488e42b60Snakayama 	__ldfsr(new_r);
32588e42b60Snakayama 
32688e42b60Snakayama 	return (old_r >> _FPUSW_SHIFT) & FE_ALL_EXCEPT;
32788e42b60Snakayama }
32888e42b60Snakayama 
32988e42b60Snakayama int
fedisableexcept(int mask)33088e42b60Snakayama fedisableexcept(int mask)
33188e42b60Snakayama {
33288e42b60Snakayama 	fenv_t old_r, new_r;
33388e42b60Snakayama 
33488e42b60Snakayama 	__stfsr(&old_r);
33588e42b60Snakayama 	new_r = old_r & ~((mask & FE_ALL_EXCEPT) << _FPUSW_SHIFT);
33688e42b60Snakayama 	__ldfsr(new_r);
33788e42b60Snakayama 
33888e42b60Snakayama 	return (old_r >> _FPUSW_SHIFT) & FE_ALL_EXCEPT;
33988e42b60Snakayama }
34088e42b60Snakayama 
34188e42b60Snakayama int
fegetexcept(void)34288e42b60Snakayama fegetexcept(void)
34388e42b60Snakayama {
34488e42b60Snakayama 	fenv_t r;
34588e42b60Snakayama 
34688e42b60Snakayama 	__stfsr(&r);
34788e42b60Snakayama 	return (r & _ENABLE_MASK) >> _FPUSW_SHIFT;
34888e42b60Snakayama }
349