xref: /openbsd/lib/libm/arch/arm/fenv.c (revision 2c53affb)
1*2c53affbSjmc /*	$OpenBSD: fenv.c,v 1.6 2022/12/27 17:10:07 jmc Exp $	*/
2ffe28f34Smartynas 
3ffe28f34Smartynas /*
4ffe28f34Smartynas  * Copyright (c) 2011 Martynas Venckus <martynas@openbsd.org>
5ffe28f34Smartynas  *
6ffe28f34Smartynas  * Permission to use, copy, modify, and distribute this software for any
7ffe28f34Smartynas  * purpose with or without fee is hereby granted, provided that the above
8ffe28f34Smartynas  * copyright notice and this permission notice appear in all copies.
9ffe28f34Smartynas  *
10ffe28f34Smartynas  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11ffe28f34Smartynas  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12ffe28f34Smartynas  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13ffe28f34Smartynas  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14ffe28f34Smartynas  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15ffe28f34Smartynas  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16ffe28f34Smartynas  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17ffe28f34Smartynas  */
18ffe28f34Smartynas 
19ffe28f34Smartynas #include <fenv.h>
204a39ccd0Sderaadt #include <machine/ieeefp.h>
21ffe28f34Smartynas 
22ffe28f34Smartynas extern	fp_except	_softfloat_float_exception_flags;
23ffe28f34Smartynas extern	fp_except	_softfloat_float_exception_mask;
24ffe28f34Smartynas extern	fp_rnd		_softfloat_float_rounding_mode;
25ffe28f34Smartynas 
26ffe28f34Smartynas /*
27ffe28f34Smartynas  * The following constant represents the default floating-point environment
28ffe28f34Smartynas  * (that is, the one installed at program startup) and has type pointer to
29ffe28f34Smartynas  * const-qualified fenv_t.
30ffe28f34Smartynas  *
31ffe28f34Smartynas  * It can be used as an argument to the functions within the <fenv.h> header
32ffe28f34Smartynas  * that manage the floating-point environment, namely fesetenv() and
33ffe28f34Smartynas  * feupdateenv().
34ffe28f34Smartynas  */
35ffe28f34Smartynas fenv_t __fe_dfl_env = {
36ffe28f34Smartynas 	0,
37ffe28f34Smartynas 	0,
38ffe28f34Smartynas 	0
39ffe28f34Smartynas };
40ffe28f34Smartynas 
41ffe28f34Smartynas /*
42ffe28f34Smartynas  * The feclearexcept() function clears the supported floating-point exceptions
43ffe28f34Smartynas  * represented by `excepts'.
44ffe28f34Smartynas  */
45ffe28f34Smartynas int
feclearexcept(int excepts)46ffe28f34Smartynas feclearexcept(int excepts)
47ffe28f34Smartynas {
48b02ee2d0Skettenis 	unsigned int fpscr;
49b02ee2d0Skettenis 
50ffe28f34Smartynas 	excepts &= FE_ALL_EXCEPT;
51ffe28f34Smartynas 
52ffe28f34Smartynas 	/* Clear the requested floating-point exceptions */
53ffe28f34Smartynas 	_softfloat_float_exception_flags &= ~excepts;
54ffe28f34Smartynas 
55b02ee2d0Skettenis 	__asm volatile("vmrs %0, fpscr" : "=r" (fpscr));
56b02ee2d0Skettenis 	fpscr &= ~excepts;
57b02ee2d0Skettenis 	__asm volatile("vmsr fpscr, %0" :: "r" (fpscr));
58b02ee2d0Skettenis 
59b02ee2d0Skettenis 	return 0;
60ffe28f34Smartynas }
612f2c0062Sguenther DEF_STD(feclearexcept);
62ffe28f34Smartynas 
63ffe28f34Smartynas /*
64ffe28f34Smartynas  * The fegetexceptflag() function stores an implementation-defined
65ffe28f34Smartynas  * representation of the states of the floating-point status flags indicated by
66ffe28f34Smartynas  * the argument excepts in the object pointed to by the argument flagp.
67ffe28f34Smartynas  */
68ffe28f34Smartynas int
fegetexceptflag(fexcept_t * flagp,int excepts)69ffe28f34Smartynas fegetexceptflag(fexcept_t *flagp, int excepts)
70ffe28f34Smartynas {
71b02ee2d0Skettenis 	unsigned int fpscr;
72b02ee2d0Skettenis 
73ffe28f34Smartynas 	excepts &= FE_ALL_EXCEPT;
74ffe28f34Smartynas 
75ffe28f34Smartynas 	/* Store the results in flagp */
76b02ee2d0Skettenis 	__asm volatile("vmrs %0, fpscr" : "=r" (fpscr));
77b02ee2d0Skettenis 	fpscr |= _softfloat_float_exception_flags;
78b02ee2d0Skettenis 	*flagp = fpscr & excepts;
79ffe28f34Smartynas 
80b02ee2d0Skettenis 	return 0;
81ffe28f34Smartynas }
82ffe28f34Smartynas 
83ffe28f34Smartynas /*
84ffe28f34Smartynas  * The feraiseexcept() function raises the supported floating-point exceptions
85ffe28f34Smartynas  * represented by the argument `excepts'.
86ffe28f34Smartynas  */
87ffe28f34Smartynas int
feraiseexcept(int excepts)88ffe28f34Smartynas feraiseexcept(int excepts)
89ffe28f34Smartynas {
90ffe28f34Smartynas 	excepts &= FE_ALL_EXCEPT;
91ffe28f34Smartynas 
92ffe28f34Smartynas 	fesetexceptflag((fexcept_t *)&excepts, excepts);
93ffe28f34Smartynas 
94b02ee2d0Skettenis 	return 0;
95ffe28f34Smartynas }
962f2c0062Sguenther DEF_STD(feraiseexcept);
97ffe28f34Smartynas 
98ffe28f34Smartynas /*
99ffe28f34Smartynas  * This function sets the floating-point status flags indicated by the argument
100ffe28f34Smartynas  * `excepts' to the states stored in the object pointed to by `flagp'. It does
101ffe28f34Smartynas  * NOT raise any floating-point exceptions, but only sets the state of the flags.
102ffe28f34Smartynas  */
103ffe28f34Smartynas int
fesetexceptflag(const fexcept_t * flagp,int excepts)104ffe28f34Smartynas fesetexceptflag(const fexcept_t *flagp, int excepts)
105ffe28f34Smartynas {
106b02ee2d0Skettenis 	unsigned int fpscr;
107b02ee2d0Skettenis 
108ffe28f34Smartynas 	excepts &= FE_ALL_EXCEPT;
109ffe28f34Smartynas 
110ffe28f34Smartynas 	/* Set the requested status flags */
111ffe28f34Smartynas 	_softfloat_float_exception_flags &= ~excepts;
112ffe28f34Smartynas 	_softfloat_float_exception_flags |= *flagp & excepts;
113ffe28f34Smartynas 
114b02ee2d0Skettenis 	__asm volatile("vmrs %0, fpscr" : "=r" (fpscr));
115b02ee2d0Skettenis 	fpscr &= ~excepts;
116b02ee2d0Skettenis 	fpscr |= *flagp & excepts;
117b02ee2d0Skettenis 	__asm volatile("vmsr fpscr, %0" :: "r" (fpscr));
118b02ee2d0Skettenis 
119b02ee2d0Skettenis 	return 0;
120ffe28f34Smartynas }
1212f2c0062Sguenther DEF_STD(fesetexceptflag);
122ffe28f34Smartynas 
123ffe28f34Smartynas /*
124ffe28f34Smartynas  * The fetestexcept() function determines which of a specified subset of the
125ffe28f34Smartynas  * floating-point exception flags are currently set. The `excepts' argument
126ffe28f34Smartynas  * specifies the floating-point status flags to be queried.
127ffe28f34Smartynas  */
128ffe28f34Smartynas int
fetestexcept(int excepts)129ffe28f34Smartynas fetestexcept(int excepts)
130ffe28f34Smartynas {
131b02ee2d0Skettenis 	unsigned int fpscr;
132b02ee2d0Skettenis 
133ffe28f34Smartynas 	excepts &= FE_ALL_EXCEPT;
134ffe28f34Smartynas 
135b02ee2d0Skettenis 	__asm volatile("vmrs %0, fpscr" : "=r" (fpscr));
136b02ee2d0Skettenis 	fpscr |= _softfloat_float_exception_flags;
137b02ee2d0Skettenis 
138b02ee2d0Skettenis 	return fpscr & excepts;
139ffe28f34Smartynas }
1402f2c0062Sguenther DEF_STD(fetestexcept);
141ffe28f34Smartynas 
142ffe28f34Smartynas /*
143ffe28f34Smartynas  * The fegetround() function gets the current rounding direction.
144ffe28f34Smartynas  */
145ffe28f34Smartynas int
fegetround(void)146ffe28f34Smartynas fegetround(void)
147ffe28f34Smartynas {
148b02ee2d0Skettenis 	unsigned int fpscr;
149b02ee2d0Skettenis 
150b02ee2d0Skettenis 	__asm volatile("vmrs %0, fpscr" : "=r" (fpscr));
151b02ee2d0Skettenis 
152b02ee2d0Skettenis 	return (fpscr >> 22) & _ROUND_MASK;
153ffe28f34Smartynas }
1542f2c0062Sguenther DEF_STD(fegetround);
155ffe28f34Smartynas 
156ffe28f34Smartynas /*
157ffe28f34Smartynas  * The fesetround() function establishes the rounding direction represented by
158ffe28f34Smartynas  * its argument `round'. If the argument is not equal to the value of a rounding
159ffe28f34Smartynas  * direction macro, the rounding direction is not changed.
160ffe28f34Smartynas  */
161ffe28f34Smartynas int
fesetround(int round)162ffe28f34Smartynas fesetround(int round)
163ffe28f34Smartynas {
164b02ee2d0Skettenis 	unsigned int fpscr;
165b02ee2d0Skettenis 
166ffe28f34Smartynas 	/* Check whether requested rounding direction is supported */
167ffe28f34Smartynas 	if (round & ~_ROUND_MASK)
168b02ee2d0Skettenis 		return -1;
169ffe28f34Smartynas 
170d6f349c8Smartynas 	/* Set the rounding direction */
171ffe28f34Smartynas 	_softfloat_float_rounding_mode &= ~_ROUND_MASK;
172ffe28f34Smartynas 	_softfloat_float_rounding_mode |= round;
173ffe28f34Smartynas 
174b02ee2d0Skettenis 	__asm volatile("vmrs %0, fpscr" : "=r" (fpscr));
175b02ee2d0Skettenis 	fpscr &= ~(_ROUND_MASK << 22);
176b02ee2d0Skettenis 	fpscr |= round << 22;
177b02ee2d0Skettenis 	__asm volatile("vmsr fpscr, %0" :: "r" (fpscr));
178b02ee2d0Skettenis 
179b02ee2d0Skettenis 	return 0;
180ffe28f34Smartynas }
1812f2c0062Sguenther DEF_STD(fesetround);
182ffe28f34Smartynas 
183ffe28f34Smartynas /*
184ffe28f34Smartynas  * The fegetenv() function attempts to store the current floating-point
185ffe28f34Smartynas  * environment in the object pointed to by envp.
186ffe28f34Smartynas  */
187ffe28f34Smartynas int
fegetenv(fenv_t * envp)188ffe28f34Smartynas fegetenv(fenv_t *envp)
189ffe28f34Smartynas {
190b02ee2d0Skettenis 	unsigned int fpscr;
191b02ee2d0Skettenis 
192b02ee2d0Skettenis 	__asm volatile("vmrs %0, fpscr" : "=r" (fpscr));
193b02ee2d0Skettenis 	fpscr |= _softfloat_float_exception_flags;
194b02ee2d0Skettenis 
195ffe28f34Smartynas 	/* Store the current floating-point sticky flags */
196b02ee2d0Skettenis 	envp->__sticky = fpscr & FE_ALL_EXCEPT;
197ffe28f34Smartynas 
198ffe28f34Smartynas 	/* Store the current floating-point masks */
199b02ee2d0Skettenis 	envp->__mask = 0;
200ffe28f34Smartynas 
201ffe28f34Smartynas 	/* Store the current floating-point control register */
202b02ee2d0Skettenis 	envp->__round = (fpscr >> 22) & _ROUND_MASK;
203ffe28f34Smartynas 
204b02ee2d0Skettenis 	return 0;
205ffe28f34Smartynas }
2062f2c0062Sguenther DEF_STD(fegetenv);
207ffe28f34Smartynas 
208ffe28f34Smartynas /*
209ffe28f34Smartynas  * The feholdexcept() function saves the current floating-point environment
210ffe28f34Smartynas  * in the object pointed to by envp, clears the floating-point status flags, and
211ffe28f34Smartynas  * then installs a non-stop (continue on floating-point exceptions) mode, if
212ffe28f34Smartynas  * available, for all floating-point exceptions.
213ffe28f34Smartynas  */
214ffe28f34Smartynas int
feholdexcept(fenv_t * envp)215ffe28f34Smartynas feholdexcept(fenv_t *envp)
216ffe28f34Smartynas {
217b02ee2d0Skettenis 	unsigned int fpscr;
218b02ee2d0Skettenis 
219ffe28f34Smartynas 	/* Store the current floating-point environment */
220ffe28f34Smartynas 	fegetenv(envp);
221ffe28f34Smartynas 
222ffe28f34Smartynas 	/* Clear exception flags */
223ffe28f34Smartynas 	_softfloat_float_exception_flags &= ~FE_ALL_EXCEPT;
224ffe28f34Smartynas 
225ffe28f34Smartynas 	/* Mask all exceptions */
226ffe28f34Smartynas 	_softfloat_float_exception_mask &= ~FE_ALL_EXCEPT;
227ffe28f34Smartynas 
228b02ee2d0Skettenis 	__asm volatile("vmrs %0, fpscr" : "=r" (fpscr));
229b02ee2d0Skettenis 	fpscr &= ~(FE_ALL_EXCEPT << 8 | FE_ALL_EXCEPT);
230b02ee2d0Skettenis 	__asm volatile("vmsr fpscr, %0" :: "r" (fpscr));
231b02ee2d0Skettenis 
232b02ee2d0Skettenis 	return 0;
233ffe28f34Smartynas }
2342f2c0062Sguenther DEF_STD(feholdexcept);
235ffe28f34Smartynas 
236ffe28f34Smartynas /*
237ffe28f34Smartynas  * The fesetenv() function attempts to establish the floating-point environment
238ffe28f34Smartynas  * represented by the object pointed to by envp. The argument `envp' points
239ffe28f34Smartynas  * to an object set by a call to fegetenv() or feholdexcept(), or equal a
240ffe28f34Smartynas  * floating-point environment macro. The fesetenv() function does not raise
241ffe28f34Smartynas  * floating-point exceptions, but only installs the state of the floating-point
242ffe28f34Smartynas  * status flags represented through its argument.
243ffe28f34Smartynas  */
244ffe28f34Smartynas int
fesetenv(const fenv_t * envp)245ffe28f34Smartynas fesetenv(const fenv_t *envp)
246ffe28f34Smartynas {
247b02ee2d0Skettenis 	unsigned int fpscr;
248b02ee2d0Skettenis 
249b02ee2d0Skettenis 	__asm volatile("vmrs %0, fpscr" : "=r" (fpscr));
250b02ee2d0Skettenis 	fpscr &= ~(_ROUND_MASK << 22 | FE_ALL_EXCEPT << 8 | FE_ALL_EXCEPT);
251b02ee2d0Skettenis 
252ffe28f34Smartynas 	/* Load the floating-point sticky flags */
253b02ee2d0Skettenis 	fpscr |= envp->__sticky & FE_ALL_EXCEPT;
254d6f349c8Smartynas 	_softfloat_float_exception_flags = envp->__sticky & FE_ALL_EXCEPT;
255ffe28f34Smartynas 
256ffe28f34Smartynas 	/* Load the floating-point masks */
257b02ee2d0Skettenis 	fpscr |= (envp->__mask & FE_ALL_EXCEPT) << 8;
258ffe28f34Smartynas 	_softfloat_float_exception_mask = envp->__mask & FE_ALL_EXCEPT;
259ffe28f34Smartynas 
260ffe28f34Smartynas 	/* Load the floating-point rounding mode */
261b02ee2d0Skettenis 	fpscr |= (envp->__round & _ROUND_MASK) << 22;
262ffe28f34Smartynas 	_softfloat_float_rounding_mode = envp->__round & _ROUND_MASK;
263ffe28f34Smartynas 
264b02ee2d0Skettenis 	__asm volatile("vmsr fpscr, %0" :: "r" (fpscr));
265b02ee2d0Skettenis 
266b02ee2d0Skettenis 	return 0;
267ffe28f34Smartynas }
2682f2c0062Sguenther DEF_STD(fesetenv);
269ffe28f34Smartynas 
270ffe28f34Smartynas /*
271ffe28f34Smartynas  * The feupdateenv() function saves the currently raised floating-point
272ffe28f34Smartynas  * exceptions in its automatic storage, installs the floating-point environment
273ffe28f34Smartynas  * represented by the object pointed to by `envp', and then raises the saved
274ffe28f34Smartynas  * floating-point exceptions. The argument `envp' shall point to an object set
275ffe28f34Smartynas  * by a call to feholdexcept() or fegetenv(), or equal a floating-point
276ffe28f34Smartynas  * environment macro.
277ffe28f34Smartynas  */
278ffe28f34Smartynas int
feupdateenv(const fenv_t * envp)279ffe28f34Smartynas feupdateenv(const fenv_t *envp)
280ffe28f34Smartynas {
281b02ee2d0Skettenis 	unsigned int fpscr;
282b02ee2d0Skettenis 
283b02ee2d0Skettenis 	__asm volatile("vmrs %0, fpscr" : "=r" (fpscr));
284b02ee2d0Skettenis 	fpscr |= _softfloat_float_exception_flags;
285ffe28f34Smartynas 
286ffe28f34Smartynas 	/* Install new floating-point environment */
287ffe28f34Smartynas 	fesetenv(envp);
288ffe28f34Smartynas 
289ffe28f34Smartynas 	/* Raise any previously accumulated exceptions */
290b02ee2d0Skettenis 	feraiseexcept(fpscr & FE_ALL_EXCEPT);
291ffe28f34Smartynas 
292b02ee2d0Skettenis 	return 0;
293ffe28f34Smartynas }
2942f2c0062Sguenther DEF_STD(feupdateenv);
295ffe28f34Smartynas 
296ffe28f34Smartynas /*
297*2c53affbSjmc  * The following functions are extensions to the standard
298ffe28f34Smartynas  */
299ffe28f34Smartynas int
feenableexcept(int mask)300ffe28f34Smartynas feenableexcept(int mask)
301ffe28f34Smartynas {
302b02ee2d0Skettenis 	return -1;
303ffe28f34Smartynas }
304ffe28f34Smartynas 
305ffe28f34Smartynas int
fedisableexcept(int mask)306ffe28f34Smartynas fedisableexcept(int mask)
307ffe28f34Smartynas {
308b02ee2d0Skettenis 	return 0;
309ffe28f34Smartynas }
310ffe28f34Smartynas 
311ffe28f34Smartynas int
fegetexcept(void)312ffe28f34Smartynas fegetexcept(void)
313ffe28f34Smartynas {
314b02ee2d0Skettenis 	return 0;
315ffe28f34Smartynas }
316