xref: /netbsd-src/lib/libm/arch/riscv/fenv.c (revision 70dffce551490796cf15f6c27fd52fddd1c41c50)
1*70dffce5Sriastradh /* $NetBSD: fenv.c,v 1.5 2024/05/17 02:11:07 riastradh Exp $ */
26cf6fe02Smatt 
36cf6fe02Smatt /*-
46cf6fe02Smatt  * Copyright (c) 2014 The NetBSD Foundation, Inc.
56cf6fe02Smatt  * All rights reserved.
66cf6fe02Smatt  *
76cf6fe02Smatt  * This code is derived from software contributed to The NetBSD Foundation
86cf6fe02Smatt  * by Matt Thomas of 3am Software Foundry.
96cf6fe02Smatt  *
106cf6fe02Smatt  * Redistribution and use in source and binary forms, with or without
116cf6fe02Smatt  * modification, are permitted provided that the following conditions
126cf6fe02Smatt  * are met:
136cf6fe02Smatt  * 1. Redistributions of source code must retain the above copyright
146cf6fe02Smatt  *    notice, this list of conditions and the following disclaimer.
156cf6fe02Smatt  * 2. Redistributions in binary form must reproduce the above copyright
166cf6fe02Smatt  *    notice, this list of conditions and the following disclaimer in the
176cf6fe02Smatt  *    documentation and/or other materials provided with the distribution.
186cf6fe02Smatt  *
196cf6fe02Smatt  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
206cf6fe02Smatt  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
216cf6fe02Smatt  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
226cf6fe02Smatt  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
236cf6fe02Smatt  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
246cf6fe02Smatt  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
256cf6fe02Smatt  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
266cf6fe02Smatt  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
276cf6fe02Smatt  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
286cf6fe02Smatt  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
296cf6fe02Smatt  * POSSIBILITY OF SUCH DAMAGE.
306cf6fe02Smatt  */
316cf6fe02Smatt 
326cf6fe02Smatt #include <sys/cdefs.h>
33*70dffce5Sriastradh __RCSID("$NetBSD: fenv.c,v 1.5 2024/05/17 02:11:07 riastradh Exp $");
347e30e943Schs 
357e30e943Schs #include "namespace.h"
366cf6fe02Smatt 
376cf6fe02Smatt #include <sys/param.h>
386cf6fe02Smatt #include <sys/sysctl.h>
396cf6fe02Smatt #include <assert.h>
406cf6fe02Smatt #include <fenv.h>
416cf6fe02Smatt #include <stddef.h>
426cf6fe02Smatt #include <string.h>
436cf6fe02Smatt 
446cf6fe02Smatt #include <riscv/sysreg.h>
456cf6fe02Smatt 
467e30e943Schs #ifdef __weak_alias
477e30e943Schs __weak_alias(feclearexcept,_feclearexcept)
487e30e943Schs __weak_alias(fedisableexcept,_fedisableexcept)
497e30e943Schs __weak_alias(feenableexcept,_feenableexcept)
507e30e943Schs __weak_alias(fegetenv,_fegetenv)
517e30e943Schs __weak_alias(fegetexcept,_fegetexcept)
527e30e943Schs __weak_alias(fegetexceptflag,_fegetexceptflag)
537e30e943Schs __weak_alias(fegetround,_fegetround)
547e30e943Schs __weak_alias(feholdexcept,_feholdexcept)
557e30e943Schs __weak_alias(feraiseexcept,_feraiseexcept)
567e30e943Schs __weak_alias(fesetenv,_fesetenv)
577e30e943Schs __weak_alias(fesetexceptflag,_fesetexceptflag)
587e30e943Schs __weak_alias(fesetround,_fesetround)
597e30e943Schs __weak_alias(fetestexcept,_fetestexcept)
607e30e943Schs __weak_alias(feupdateenv,_feupdateenv)
617e30e943Schs #endif
627e30e943Schs 
636cf6fe02Smatt /*
646cf6fe02Smatt  * The following constant represents the default floating-point environment
656cf6fe02Smatt  * (that is, the one installed at program startup) and has type pointer to
666cf6fe02Smatt  * const-qualified fenv_t.
676cf6fe02Smatt  *
686cf6fe02Smatt  * It can be used as an argument to the functions within the <fenv.h> header
696cf6fe02Smatt  * that manage the floating-point environment, namely fesetenv() and
706cf6fe02Smatt  * feupdateenv().
716cf6fe02Smatt  */
727e30e943Schs const fenv_t __fe_dfl_env = __SHIFTIN(FCSR_FRM_RNE, FCSR_FRM);
736cf6fe02Smatt 
746cf6fe02Smatt /*
756cf6fe02Smatt  * The feclearexcept() function clears the supported floating-point exceptions
766cf6fe02Smatt  * represented by `excepts'.
776cf6fe02Smatt  */
786cf6fe02Smatt int
feclearexcept(int excepts)796cf6fe02Smatt feclearexcept(int excepts)
806cf6fe02Smatt {
816cf6fe02Smatt 	_DIAGASSERT((excepts & ~FE_ALL_EXCEPT) == 0);
826cf6fe02Smatt 
8375b842b8Sskrll 	int fflags = fcsr_fflags_read();
846cf6fe02Smatt 
856cf6fe02Smatt 	fflags &= ~(excepts & FE_ALL_EXCEPT);
866cf6fe02Smatt 
8775b842b8Sskrll 	fcsr_fflags_write(fflags);
886cf6fe02Smatt 
896cf6fe02Smatt 	/* Success */
9075b842b8Sskrll 	return 0;
916cf6fe02Smatt }
926cf6fe02Smatt 
936cf6fe02Smatt /*
946cf6fe02Smatt  * The fegetexceptflag() function stores an implementation-defined
956cf6fe02Smatt  * representation of the states of the floating-point status flags indicated by
966cf6fe02Smatt  * the argument excepts in the object pointed to by the argument flagp.
976cf6fe02Smatt  */
986cf6fe02Smatt int
fegetexceptflag(fexcept_t * flagp,int excepts)996cf6fe02Smatt fegetexceptflag(fexcept_t *flagp, int excepts)
1006cf6fe02Smatt {
1016cf6fe02Smatt 	_DIAGASSERT(flagp != NULL);
1026cf6fe02Smatt 	_DIAGASSERT((excepts & ~FE_ALL_EXCEPT) == 0);
1036cf6fe02Smatt 
10475b842b8Sskrll 	*flagp = fcsr_fflags_read() & excepts;
1056cf6fe02Smatt 
1066cf6fe02Smatt 	/* Success */
10775b842b8Sskrll 	return 0;
1086cf6fe02Smatt }
1096cf6fe02Smatt 
1106cf6fe02Smatt /*
1116cf6fe02Smatt  * The feraiseexcept() function raises the supported floating-point exceptions
1126cf6fe02Smatt  * represented by the argument `excepts'.
1136cf6fe02Smatt  *
1146cf6fe02Smatt  * The standard explicitly allows us to execute an instruction that has the
1156cf6fe02Smatt  * exception as a side effect, but we choose to manipulate the status register
1166cf6fe02Smatt  * directly.
1176cf6fe02Smatt  */
1186cf6fe02Smatt int
feraiseexcept(int excepts)1196cf6fe02Smatt feraiseexcept(int excepts)
1206cf6fe02Smatt {
1216cf6fe02Smatt 
1226cf6fe02Smatt 	_DIAGASSERT((excepts & ~FE_ALL_EXCEPT) == 0);
1236cf6fe02Smatt 
1246cf6fe02Smatt 	excepts &= FE_ALL_EXCEPT;
125*70dffce5Sriastradh 	fcsr_fflags_write(fcsr_fflags_read() | excepts);
1266cf6fe02Smatt 
1276cf6fe02Smatt 	/* Success */
12875b842b8Sskrll 	return 0;
1296cf6fe02Smatt }
1306cf6fe02Smatt 
1316cf6fe02Smatt /*
1326cf6fe02Smatt  * This function sets the floating-point status flags indicated by the argument
1336cf6fe02Smatt  * `excepts' to the states stored in the object pointed to by `flagp'. It does
1346cf6fe02Smatt  * NOT raise any floating-point exceptions, but only sets the state of the flags.
1356cf6fe02Smatt  */
1366cf6fe02Smatt int
fesetexceptflag(const fexcept_t * flagp,int excepts)1376cf6fe02Smatt fesetexceptflag(const fexcept_t *flagp, int excepts)
1386cf6fe02Smatt {
1396cf6fe02Smatt 	_DIAGASSERT(flagp != NULL);
1406cf6fe02Smatt 	_DIAGASSERT((excepts & ~FE_ALL_EXCEPT) == 0);
1416cf6fe02Smatt 
1426cf6fe02Smatt 	excepts &= FE_ALL_EXCEPT;
1436cf6fe02Smatt 
14475b842b8Sskrll 	int fflags = fcsr_fflags_read();
1456cf6fe02Smatt 
1466cf6fe02Smatt 	fflags = (fflags & ~excepts) | (*flagp & excepts);
1476cf6fe02Smatt 
14875b842b8Sskrll 	fcsr_fflags_write(fflags);
1496cf6fe02Smatt 
1506cf6fe02Smatt 	/* Success */
15175b842b8Sskrll 	return 0;
1526cf6fe02Smatt }
1536cf6fe02Smatt 
1546cf6fe02Smatt /*
1556cf6fe02Smatt  * The fetestexcept() function determines which of a specified subset of the
1566cf6fe02Smatt  * floating-point exception flags are currently set. The `excepts' argument
1576cf6fe02Smatt  * specifies the floating-point status flags to be queried.
1586cf6fe02Smatt  */
1596cf6fe02Smatt int
fetestexcept(int excepts)1606cf6fe02Smatt fetestexcept(int excepts)
1616cf6fe02Smatt {
1626cf6fe02Smatt 	_DIAGASSERT((excepts & ~FE_ALL_EXCEPT) == 0);
1636cf6fe02Smatt 
16475b842b8Sskrll 	return fcsr_fflags_read() & excepts & FE_ALL_EXCEPT;
1656cf6fe02Smatt }
1666cf6fe02Smatt 
1676cf6fe02Smatt int
fegetround(void)1686cf6fe02Smatt fegetround(void)
1696cf6fe02Smatt {
17075b842b8Sskrll 	return fcsr_frm_read();
1716cf6fe02Smatt }
1726cf6fe02Smatt 
1736cf6fe02Smatt /*
1746cf6fe02Smatt  * The fesetround() function shall establish the rounding direction represented
1756cf6fe02Smatt  * by its argument round. If the argument is not equal to the value of a
1766cf6fe02Smatt  * rounding direction macro, the rounding direction is not changed.
1776cf6fe02Smatt  */
1786cf6fe02Smatt int
fesetround(int round)1796cf6fe02Smatt fesetround(int round)
1806cf6fe02Smatt {
1816cf6fe02Smatt 	if ((unsigned int)round > FCSR_FRM_RMM) {
1826cf6fe02Smatt 		/* Failure */
1836cf6fe02Smatt 		return (-1);
1846cf6fe02Smatt 	}
1856cf6fe02Smatt 
18675b842b8Sskrll 	fcsr_frm_write(round);
1876cf6fe02Smatt 
1886cf6fe02Smatt 	/* Success */
18975b842b8Sskrll 	return 0;
1906cf6fe02Smatt }
1916cf6fe02Smatt 
1926cf6fe02Smatt /*
1936cf6fe02Smatt  * The fegetenv() function attempts to store the current floating-point
1946cf6fe02Smatt  * environment in the object pointed to by envp.
1956cf6fe02Smatt  */
1966cf6fe02Smatt int
fegetenv(fenv_t * envp)1976cf6fe02Smatt fegetenv(fenv_t *envp)
1986cf6fe02Smatt {
1996cf6fe02Smatt 	_DIAGASSERT(envp != NULL);
2006cf6fe02Smatt 
20175b842b8Sskrll 	*envp = fcsr_read();
2026cf6fe02Smatt 
2036cf6fe02Smatt 	/* Success */
20475b842b8Sskrll 	return 0;
2056cf6fe02Smatt }
2066cf6fe02Smatt 
2076cf6fe02Smatt /*
2086cf6fe02Smatt  * The feholdexcept() function saves the current floating-point environment in
2096cf6fe02Smatt  * the object pointed to by envp, clears the floating-point status flags, and
2106cf6fe02Smatt  * then installs a non-stop (continue on floating-point exceptions) mode, if
2116cf6fe02Smatt  * available, for all floating-point exceptions.
2126cf6fe02Smatt  */
2136cf6fe02Smatt int
feholdexcept(fenv_t * envp)2146cf6fe02Smatt feholdexcept(fenv_t *envp)
2156cf6fe02Smatt {
2166cf6fe02Smatt 	_DIAGASSERT(envp != NULL);
2176cf6fe02Smatt 
21875b842b8Sskrll 	*envp = fcsr_read();
2196cf6fe02Smatt 
22075b842b8Sskrll 	fcsr_fflags_write(0);
2216cf6fe02Smatt 
2226cf6fe02Smatt 	/* Success */
22375b842b8Sskrll 	return 0;
2246cf6fe02Smatt }
2256cf6fe02Smatt 
2266cf6fe02Smatt /*
2276cf6fe02Smatt  * The fesetenv() function attempts to establish the floating-point environment
2286cf6fe02Smatt  * represented by the object pointed to by envp. The argument `envp' points
2296cf6fe02Smatt  * to an object set by a call to fegetenv() or feholdexcept(), or equal a
2306cf6fe02Smatt  * floating-point environment macro. The fesetenv() function does not raise
2316cf6fe02Smatt  * floating-point exceptions, but only installs the state of the floating-point
2326cf6fe02Smatt  * status flags represented through its argument.
2336cf6fe02Smatt  */
2346cf6fe02Smatt int
fesetenv(const fenv_t * envp)2356cf6fe02Smatt fesetenv(const fenv_t *envp)
2366cf6fe02Smatt {
2376cf6fe02Smatt 
2386cf6fe02Smatt 	_DIAGASSERT(envp != NULL);
2396cf6fe02Smatt 
2406cf6fe02Smatt 	fenv_t env = *envp;
2416cf6fe02Smatt 
2426cf6fe02Smatt 	if ((env & ~(FCSR_FRM|FCSR_FFLAGS)
2436cf6fe02Smatt 	    || __SHIFTOUT(env, FCSR_FRM) > FCSR_FRM_RMM)) {
2446cf6fe02Smatt 		return -1;
2456cf6fe02Smatt 	}
2466cf6fe02Smatt 
24775b842b8Sskrll 	fcsr_write(env);
2486cf6fe02Smatt 
2496cf6fe02Smatt 	/* Success */
25075b842b8Sskrll 	return 0;
2516cf6fe02Smatt }
2526cf6fe02Smatt 
2536cf6fe02Smatt /*
2546cf6fe02Smatt  * The feupdateenv() function saves the currently raised floating-point
2556cf6fe02Smatt  * exceptions in its automatic storage, installs the floating-point environment
2566cf6fe02Smatt  * represented by the object pointed to by `envp', and then raises the saved
2576cf6fe02Smatt  * floating-point exceptions. The argument `envp' shall point to an object set
2586cf6fe02Smatt  * by a call to feholdexcept() or fegetenv(), or equal a floating-point
2596cf6fe02Smatt  * environment macro.
2606cf6fe02Smatt  */
2616cf6fe02Smatt int
feupdateenv(const fenv_t * envp)2626cf6fe02Smatt feupdateenv(const fenv_t *envp)
2636cf6fe02Smatt {
2646cf6fe02Smatt 	_DIAGASSERT(envp != NULL);
2656cf6fe02Smatt 
26675b842b8Sskrll 	int fflags = fcsr_fflags_read();
2676cf6fe02Smatt 
2686cf6fe02Smatt 	fesetenv(envp);
2696cf6fe02Smatt 	feraiseexcept(fflags);
2706cf6fe02Smatt 
2716cf6fe02Smatt 	/* Success */
27275b842b8Sskrll 	return 0;
2736cf6fe02Smatt }
2746cf6fe02Smatt 
2756cf6fe02Smatt /*
276f9faf20aSandvar  * The following functions are extensions to the standard
2776cf6fe02Smatt  */
2786cf6fe02Smatt int
feenableexcept(int nmask)2796cf6fe02Smatt feenableexcept(int nmask)
2806cf6fe02Smatt {
2816cf6fe02Smatt 	return 0;
2826cf6fe02Smatt }
2836cf6fe02Smatt 
2846cf6fe02Smatt int
fedisableexcept(int nmask)2856cf6fe02Smatt fedisableexcept(int nmask)
2866cf6fe02Smatt {
2876cf6fe02Smatt 	return 0;
2886cf6fe02Smatt }
2896cf6fe02Smatt 
2906cf6fe02Smatt int
fegetexcept(void)2916cf6fe02Smatt fegetexcept(void)
2926cf6fe02Smatt {
2936cf6fe02Smatt 	return 0;
2946cf6fe02Smatt }
295