xref: /netbsd-src/lib/libm/arch/aarch64/fenv.c (revision 8c835d389596f07937fb828784f9910515e0f886)
1*8c835d38Sskrll /* $NetBSD: fenv.c,v 1.7 2024/05/06 15:59:53 skrll Exp $ */
2beb9c6d1Smatt 
3beb9c6d1Smatt /*-
4beb9c6d1Smatt  * Copyright (c) 2014 The NetBSD Foundation, Inc.
5beb9c6d1Smatt  * All rights reserved.
6beb9c6d1Smatt  *
7beb9c6d1Smatt  * This code is derived from software contributed to The NetBSD Foundation
8beb9c6d1Smatt  * by Matt Thomas of 3am Software Foundry.
9beb9c6d1Smatt  *
10beb9c6d1Smatt  * Redistribution and use in source and binary forms, with or without
11beb9c6d1Smatt  * modification, are permitted provided that the following conditions
12beb9c6d1Smatt  * are met:
13beb9c6d1Smatt  * 1. Redistributions of source code must retain the above copyright
14beb9c6d1Smatt  *    notice, this list of conditions and the following disclaimer.
15beb9c6d1Smatt  * 2. Redistributions in binary form must reproduce the above copyright
16beb9c6d1Smatt  *    notice, this list of conditions and the following disclaimer in the
17beb9c6d1Smatt  *    documentation and/or other materials provided with the distribution.
18beb9c6d1Smatt  *
19beb9c6d1Smatt  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20beb9c6d1Smatt  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21beb9c6d1Smatt  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22beb9c6d1Smatt  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23beb9c6d1Smatt  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24beb9c6d1Smatt  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25beb9c6d1Smatt  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26beb9c6d1Smatt  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27beb9c6d1Smatt  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28beb9c6d1Smatt  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29beb9c6d1Smatt  * POSSIBILITY OF SUCH DAMAGE.
30beb9c6d1Smatt  */
31beb9c6d1Smatt 
32beb9c6d1Smatt #include <sys/cdefs.h>
33*8c835d38Sskrll __RCSID("$NetBSD: fenv.c,v 1.7 2024/05/06 15:59:53 skrll Exp $");
347e30e943Schs 
357e30e943Schs #include "namespace.h"
36beb9c6d1Smatt 
37beb9c6d1Smatt #include <sys/param.h>
38beb9c6d1Smatt #include <sys/types.h>
39beb9c6d1Smatt #include <assert.h>
40beb9c6d1Smatt #include <fenv.h>
41beb9c6d1Smatt #include <string.h>
42beb9c6d1Smatt #include <unistd.h>
43beb9c6d1Smatt #include <inttypes.h>
44beb9c6d1Smatt 
45beb9c6d1Smatt #include <aarch64/armreg.h>
46beb9c6d1Smatt 
477e30e943Schs #ifdef __weak_alias
487e30e943Schs __weak_alias(feclearexcept,_feclearexcept)
497e30e943Schs __weak_alias(fedisableexcept,_fedisableexcept)
507e30e943Schs __weak_alias(feenableexcept,_feenableexcept)
517e30e943Schs __weak_alias(fegetenv,_fegetenv)
527e30e943Schs __weak_alias(fegetexcept,_fegetexcept)
537e30e943Schs __weak_alias(fegetexceptflag,_fegetexceptflag)
547e30e943Schs __weak_alias(fegetround,_fegetround)
557e30e943Schs __weak_alias(feholdexcept,_feholdexcept)
567e30e943Schs __weak_alias(feraiseexcept,_feraiseexcept)
577e30e943Schs __weak_alias(fesetenv,_fesetenv)
587e30e943Schs __weak_alias(fesetexceptflag,_fesetexceptflag)
597e30e943Schs __weak_alias(fesetround,_fesetround)
607e30e943Schs __weak_alias(fetestexcept,_fetestexcept)
617e30e943Schs __weak_alias(feupdateenv,_feupdateenv)
627e30e943Schs #endif
637e30e943Schs 
64beb9c6d1Smatt const fenv_t __fe_dfl_env = {
65beb9c6d1Smatt 	.__fpsr = 0,
667374a226Sriastradh 	.__fpcr = __SHIFTIN(FPCR_RN, FPCR_RMODE),
67beb9c6d1Smatt };
68beb9c6d1Smatt 
69beb9c6d1Smatt /*
70beb9c6d1Smatt  * The feclearexcept() function shall attempt to clear the supported
71beb9c6d1Smatt  * floating-point exceptions represented by excepts.
72beb9c6d1Smatt  */
73beb9c6d1Smatt int
feclearexcept(int excepts)74beb9c6d1Smatt feclearexcept(int excepts)
75beb9c6d1Smatt {
76beb9c6d1Smatt #ifndef lint
77b19178f8Smartin 	_DIAGASSERT((except & ~FE_ALL_EXCEPT) == 0);
78beb9c6d1Smatt #endif
79beb9c6d1Smatt 	unsigned int tmp = reg_fpsr_read() & ~__SHIFTIN(excepts, FPSR_CSUM);
80beb9c6d1Smatt 	reg_fpsr_write(tmp);
81beb9c6d1Smatt 	return 0;
82beb9c6d1Smatt }
83beb9c6d1Smatt 
84beb9c6d1Smatt /*
85beb9c6d1Smatt  * The fegetexceptflag() function shall attempt to store an
86beb9c6d1Smatt  * implementation-defined representation of the states of the floating-point
87beb9c6d1Smatt  * status flags indicated by the argument excepts in the object pointed to by
88beb9c6d1Smatt  * the argument flagp.
89beb9c6d1Smatt  */
90beb9c6d1Smatt int
fegetexceptflag(fexcept_t * flagp,int excepts)91beb9c6d1Smatt fegetexceptflag(fexcept_t *flagp, int excepts)
92beb9c6d1Smatt {
93b19178f8Smartin 	_DIAGASSERT((except & ~FE_ALL_EXCEPT) == 0);
94beb9c6d1Smatt 	*flagp = __SHIFTOUT(reg_fpsr_read(), FPSR_CSUM) & excepts;
95beb9c6d1Smatt 	return 0;
96beb9c6d1Smatt }
97beb9c6d1Smatt 
98beb9c6d1Smatt /*
99beb9c6d1Smatt  * The feraiseexcept() function shall attempt to raise the supported
100beb9c6d1Smatt  * floating-point exceptions represented by the argument excepts. The order
101beb9c6d1Smatt  * in which these floating-point exceptions are raised is unspecified.
102beb9c6d1Smatt  */
103beb9c6d1Smatt int
feraiseexcept(int excepts)104beb9c6d1Smatt feraiseexcept(int excepts)
105beb9c6d1Smatt {
106beb9c6d1Smatt #ifndef lint
107b19178f8Smartin 	_DIAGASSERT((except & ~FE_ALL_EXCEPT) == 0);
108beb9c6d1Smatt #endif
109beb9c6d1Smatt 	unsigned int fpsr = reg_fpsr_read();
110ab94299dSriastradh 	excepts &= FE_ALL_EXCEPT; /* paranoia */
111ab94299dSriastradh 	fpsr |= __SHIFTIN(excepts, FPSR_CSUM);
112beb9c6d1Smatt 	reg_fpsr_write(fpsr);
113beb9c6d1Smatt 	return 0;
114beb9c6d1Smatt }
115beb9c6d1Smatt 
116beb9c6d1Smatt /*
117beb9c6d1Smatt  * The fesetexceptflag() function shall attempt to set the floating-point
118beb9c6d1Smatt  * status flags indicated by the argument excepts to the states stored in the
119beb9c6d1Smatt  * object pointed to by flagp. The value pointed to by flagp shall have been
120beb9c6d1Smatt  * set by a previous call to fegetexceptflag() whose second argument
121beb9c6d1Smatt  * represented at least those floating-point exceptions represented by the
122beb9c6d1Smatt  * argument excepts. This function does not raise floating-point exceptions,
123beb9c6d1Smatt  * but only sets the state of the flags.
124beb9c6d1Smatt  */
125beb9c6d1Smatt int
fesetexceptflag(const fexcept_t * flagp,int excepts)126beb9c6d1Smatt fesetexceptflag(const fexcept_t *flagp, int excepts)
127beb9c6d1Smatt {
128beb9c6d1Smatt #ifndef lint
129b19178f8Smartin 	_DIAGASSERT((except & ~FE_ALL_EXCEPT) == 0);
130beb9c6d1Smatt #endif
131beb9c6d1Smatt 	unsigned int fpsr = reg_fpsr_read();
132beb9c6d1Smatt 	fpsr &= ~__SHIFTIN(excepts, FPSR_CSUM);
133beb9c6d1Smatt 	fpsr |= __SHIFTIN((*flagp & excepts), FPSR_CSUM);
134beb9c6d1Smatt 	reg_fpsr_write(fpsr);
135beb9c6d1Smatt 	return 0;
136beb9c6d1Smatt }
137beb9c6d1Smatt 
138beb9c6d1Smatt /*
139beb9c6d1Smatt  * The fetestexcept() function shall determine which of a specified subset of
140beb9c6d1Smatt  * the floating-point exception flags are currently set. The excepts argument
141beb9c6d1Smatt  * specifies the floating-point status flags to be queried.
142beb9c6d1Smatt  */
143beb9c6d1Smatt int
fetestexcept(int excepts)144beb9c6d1Smatt fetestexcept(int excepts)
145beb9c6d1Smatt {
146b19178f8Smartin 	_DIAGASSERT((except & ~FE_ALL_EXCEPT) == 0);
147beb9c6d1Smatt 	return __SHIFTOUT(reg_fpsr_read(), FPSR_CSUM) & excepts;
148beb9c6d1Smatt }
149beb9c6d1Smatt 
150beb9c6d1Smatt /*
151beb9c6d1Smatt  * The fegetround() function shall get the current rounding direction.
152beb9c6d1Smatt  */
153beb9c6d1Smatt int
fegetround(void)154beb9c6d1Smatt fegetround(void)
155beb9c6d1Smatt {
156beb9c6d1Smatt 	return __SHIFTOUT(reg_fpcr_read(), FPCR_RMODE);
157beb9c6d1Smatt }
158beb9c6d1Smatt 
159beb9c6d1Smatt /*
160beb9c6d1Smatt  * The fesetround() function shall establish the rounding direction represented
161beb9c6d1Smatt  * by its argument round. If the argument is not equal to the value of a
162beb9c6d1Smatt  * rounding direction macro, the rounding direction is not changed.
163beb9c6d1Smatt  */
164beb9c6d1Smatt int
fesetround(int round)165beb9c6d1Smatt fesetround(int round)
166beb9c6d1Smatt {
167beb9c6d1Smatt #ifndef lint
168beb9c6d1Smatt 	_DIAGASSERT(!(round & ~__SHIFTOUT(FPCR_RMODE, FPCR_RMODE)));
169beb9c6d1Smatt #endif
170beb9c6d1Smatt 	unsigned int fpcr = reg_fpcr_read() & ~FPCR_RMODE;
171beb9c6d1Smatt 	fpcr |= __SHIFTIN(round, FPCR_RMODE);
172beb9c6d1Smatt 	reg_fpcr_write(fpcr);
173beb9c6d1Smatt 	return 0;
174beb9c6d1Smatt }
175beb9c6d1Smatt 
176beb9c6d1Smatt /*
177beb9c6d1Smatt  * The fegetenv() function shall attempt to store the current floating-point
178beb9c6d1Smatt  * environment in the object pointed to by envp.
179beb9c6d1Smatt  */
180beb9c6d1Smatt int
fegetenv(fenv_t * envp)181beb9c6d1Smatt fegetenv(fenv_t *envp)
182beb9c6d1Smatt {
183beb9c6d1Smatt 	envp->__fpcr = reg_fpcr_read();
184beb9c6d1Smatt 	envp->__fpsr = reg_fpsr_read();
185beb9c6d1Smatt 	return 0;
186beb9c6d1Smatt }
187beb9c6d1Smatt 
188beb9c6d1Smatt /*
189beb9c6d1Smatt  * The feholdexcept() function shall save the current floating-point
190beb9c6d1Smatt  * environment in the object pointed to by envp, clear the floating-point
191beb9c6d1Smatt  * status flags, and then install a non-stop (continue on floating-point
192beb9c6d1Smatt  * exceptions) mode, if available, for all floating-point exceptions.
193beb9c6d1Smatt  */
194beb9c6d1Smatt int
feholdexcept(fenv_t * envp)195beb9c6d1Smatt feholdexcept(fenv_t *envp)
196beb9c6d1Smatt {
197beb9c6d1Smatt 	envp->__fpsr = reg_fpsr_read();
198beb9c6d1Smatt 	envp->__fpcr = reg_fpcr_read();
199beb9c6d1Smatt 	reg_fpsr_write(envp->__fpsr & ~FPSR_CSUM);
200beb9c6d1Smatt 	reg_fpcr_write(envp->__fpcr & ~FPCR_ESUM);
201beb9c6d1Smatt 	return 0;
202beb9c6d1Smatt }
203beb9c6d1Smatt 
204beb9c6d1Smatt /*
205beb9c6d1Smatt  * The fesetenv() function shall attempt to establish the floating-point
206beb9c6d1Smatt  * environment represented by the object pointed to by envp. The fesetenv()
207beb9c6d1Smatt  * function does not raise floating-point exceptions, but only installs the
208beb9c6d1Smatt  * state of the floating-point status flags represented through its argument.
209beb9c6d1Smatt  */
210beb9c6d1Smatt int
fesetenv(const fenv_t * envp)211beb9c6d1Smatt fesetenv(const fenv_t *envp)
212beb9c6d1Smatt {
213beb9c6d1Smatt 	reg_fpsr_write(envp->__fpsr);
214f527f350Sriastradh 	reg_fpcr_write(envp->__fpcr);
215beb9c6d1Smatt 	return 0;
216beb9c6d1Smatt }
217beb9c6d1Smatt 
218beb9c6d1Smatt /*
219beb9c6d1Smatt  * The feupdateenv() function shall attempt to save the currently raised
220beb9c6d1Smatt  * floating-point exceptions in its automatic storage, attempt to install the
221beb9c6d1Smatt  * floating-point environment represented by the object pointed to by envp,
222beb9c6d1Smatt  * and then attempt to raise the saved floating-point exceptions.
223beb9c6d1Smatt  */
224beb9c6d1Smatt int
feupdateenv(const fenv_t * envp)225beb9c6d1Smatt feupdateenv(const fenv_t *envp)
226beb9c6d1Smatt {
227f527f350Sriastradh 	int except = fetestexcept(FE_ALL_EXCEPT);
228f527f350Sriastradh 
229f527f350Sriastradh 	fesetenv(envp);
230f527f350Sriastradh 	feraiseexcept(except);
231beb9c6d1Smatt 
232beb9c6d1Smatt 	/* Success */
233beb9c6d1Smatt 	return 0;
234beb9c6d1Smatt }
235beb9c6d1Smatt 
236beb9c6d1Smatt int
feenableexcept(int excepts)237beb9c6d1Smatt feenableexcept(int excepts)
238beb9c6d1Smatt {
239beb9c6d1Smatt 	const uint32_t __fpcr = reg_fpcr_read();
240beb9c6d1Smatt 	reg_fpcr_write((__fpcr & ~FPCR_ESUM) | __SHIFTIN(excepts, FPCR_ESUM));
241beb9c6d1Smatt 	return __SHIFTOUT(__fpcr, FPCR_ESUM);
242beb9c6d1Smatt }
243beb9c6d1Smatt 
244beb9c6d1Smatt int
fedisableexcept(int excepts)245beb9c6d1Smatt fedisableexcept(int excepts)
246beb9c6d1Smatt {
247beb9c6d1Smatt 	const uint32_t __fpcr = reg_fpcr_read();
248beb9c6d1Smatt 	reg_fpcr_write(__fpcr & ~__SHIFTIN(excepts, FPCR_ESUM));
249beb9c6d1Smatt 	return __SHIFTOUT(__fpcr, FPCR_ESUM);
250beb9c6d1Smatt }
251beb9c6d1Smatt 
252beb9c6d1Smatt int
fegetexcept(void)253beb9c6d1Smatt fegetexcept(void)
254beb9c6d1Smatt {
255beb9c6d1Smatt 	const uint32_t __fpcr = reg_fpcr_read();
256beb9c6d1Smatt 	return __SHIFTOUT(__fpcr, FPCR_ESUM);
257beb9c6d1Smatt }
258