xref: /openbsd/lib/libm/arch/riscv64/fenv.c (revision 097a140d)
1 /* $OpenBSD: fenv.c,v 1.1 2021/04/27 00:31:34 drahn Exp $ */
2 /*-
3  * Copyright (c) 2004-2005 David Schultz <das@FreeBSD.ORG>
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  * $FreeBSD: head/lib/msun/aarch64/fenv.h 280857 2015-03-30 16:42:08Z emaste $
28  */
29 
30 #include <fenv.h>
31 #include <machine/ieeefp.h>
32 
33 /* We need to be able to map status flag positions to mask flag positions */
34 #define	_FPUSW_SHIFT	8
35 #define	_ENABLE_MASK	(FE_ALL_EXCEPT << _FPUSW_SHIFT)
36 
37 #define	__get_fcsr(r)	asm volatile("frcsr %0" : "=r" (r))
38 #define	__set_fcsr(r)	asm volatile("fscsr %0" : "+r" (r))
39 #define	__get_flags(r)	asm volatile("frflags %0" : "=r" (r))
40 #define	__set_flags(r)	asm volatile("fsflags %0" : "+r" (r))
41 #define	__get_frm(r)	asm volatile("frrm %0" : "=r" (r))
42 #define	__set_frm(r)	asm volatile("fsrm %0" : "+r"(r) )
43 
44 /*
45  * The following constant represents the default floating-point environment
46  * (that is, the one installed at program startup) and has type pointer to
47  * const-qualified fenv_t.
48  *
49  * It can be used as an argument to the functions within the <fenv.h> header
50  * that manage the floating-point environment, namely fesetenv() and
51  * feupdateenv().
52  */
53 fenv_t __fe_dfl_env = 0;
54 
55 /*
56  * The feclearexcept() function clears the supported floating-point exceptions
57  * represented by `excepts'.
58  */
59 int
60 feclearexcept(int excepts)
61 {
62 	fexcept_t r;
63 
64 	excepts &= FE_ALL_EXCEPT;
65 	__get_flags(r);
66 	r &= ~excepts;
67 	__set_flags(r);
68 	return (0);
69 }
70 DEF_STD(feclearexcept);
71 
72 /*
73  * The fegetexceptflag() function stores an implementation-defined
74  * representation of the states of the floating-point status flags indicated by
75  * the argument excepts in the object pointed to by the argument flagp.
76  */
77 int
78 fegetexceptflag(fexcept_t *flagp, int excepts)
79 {
80 	fexcept_t r;
81 
82 	excepts &= FE_ALL_EXCEPT;
83 	__get_flags(r);
84 	*flagp = r & excepts;
85 	return (0);
86 }
87 
88 /*
89  * The feraiseexcept() function raises the supported floating-point exceptions
90  * represented by the argument `excepts'.
91  */
92 int
93 feraiseexcept(int excepts)
94 {
95 	fexcept_t r;
96 
97 	excepts &= FE_ALL_EXCEPT;
98 	__get_flags(r);
99 	r |= excepts;
100 	__set_flags(r);
101 	return (0);
102 }
103 DEF_STD(feraiseexcept);
104 
105 /*
106  * This function sets the floating-point status flags indicated by the argument
107  * `excepts' to the states stored in the object pointed to by `flagp'. It does
108  * NOT raise any floating-point exceptions, but only sets the state of the flags.
109  */
110 int
111 fesetexceptflag(const fexcept_t *flagp, int excepts)
112 {
113 	fexcept_t r;
114 
115 	excepts &= FE_ALL_EXCEPT;
116 	__get_flags(r);
117 	r &= ~excepts;
118 	r |= *flagp & excepts;
119 	__set_flags(r);
120 	return (0);
121 }
122 DEF_STD(fesetexceptflag);
123 
124 /*
125  * The fetestexcept() function determines which of a specified subset of the
126  * floating-point exception flags are currently set. The `excepts' argument
127  * specifies the floating-point status flags to be queried.
128  */
129 int
130 fetestexcept(int excepts)
131 {
132 	fexcept_t r;
133 
134 	excepts &= FE_ALL_EXCEPT;
135 	__get_flags(r);
136 	return (r & excepts);
137 }
138 DEF_STD(fetestexcept);
139 
140 /*
141  * The fegetround() function gets the current rounding direction.
142  */
143 int
144 fegetround(void)
145 {
146 	fenv_t r;
147 
148 	__get_frm(r);
149 	return ((r >> _ROUND_SHIFT) & _ROUND_MASK);
150 }
151 DEF_STD(fegetround);
152 
153 /*
154  * The fesetround() function establishes the rounding direction represented by
155  * its argument `round'. If the argument is not equal to the value of a rounding
156  * direction macro, the rounding direction is not changed.
157  */
158 int
159 fesetround(int round)
160 {
161 	fenv_t r;
162 
163 	if (round & ~_ROUND_MASK)
164 		return (-1);
165 	__set_frm(round);
166 	return (0);
167 }
168 DEF_STD(fesetround);
169 
170 /*
171  * The fegetenv() function attempts to store the current floating-point
172  * environment in the object pointed to by envp.
173  */
174 int
175 fegetenv(fenv_t *envp)
176 {
177 	fenv_t r;
178 
179 	__get_fcsr(r);
180 	*envp = r;
181 
182 	return (0);
183 }
184 DEF_STD(fegetenv);
185 
186 /*
187  * The feholdexcept() function saves the current floating-point environment
188  * in the object pointed to by envp, clears the floating-point status flags, and
189  * then installs a non-stop (continue on floating-point exceptions) mode, if
190  * available, for all floating-point exceptions.
191  */
192 int
193 feholdexcept(fenv_t *envp)
194 {
195 	fenv_t r;
196 
197 	__get_fcsr(r);
198 	*envp  = r;
199 	r &= ~_ROUND_MASK;
200 	__set_fcsr(r);
201 
202 	return (0);
203 }
204 DEF_STD(feholdexcept);
205 
206 /*
207  * The fesetenv() function attempts to establish the floating-point environment
208  * represented by the object pointed to by envp. The argument `envp' points
209  * to an object set by a call to fegetenv() or feholdexcept(), or equal a
210  * floating-point environment macro. The fesetenv() function does not raise
211  * floating-point exceptions, but only installs the state of the floating-point
212  * status flags represented through its argument.
213  */
214 int
215 fesetenv(const fenv_t *envp)
216 {
217 
218 	fenv_t r;
219 	r = *envp;
220 	__set_fcsr(r);
221 	return (0);
222 }
223 DEF_STD(fesetenv);
224 
225 /*
226  * The feupdateenv() function saves the currently raised floating-point
227  * exceptions in its automatic storage, installs the floating-point environment
228  * represented by the object pointed to by `envp', and then raises the saved
229  * floating-point exceptions. The argument `envp' shall point to an object set
230  * by a call to feholdexcept() or fegetenv(), or equal a floating-point
231  * environment macro.
232  */
233 int
234 feupdateenv(const fenv_t *envp)
235 {
236 	fexcept_t r;
237 
238 	__get_fcsr(r);
239 	fesetenv(envp);
240 	feraiseexcept(r & FE_ALL_EXCEPT);
241 	return (0);
242 }
243 DEF_STD(feupdateenv);
244 
245 /*
246  * The following functions are extentions to the standard
247  */
248 int
249 feenableexcept(int mask)
250 {
251 	return -1;
252 }
253 
254 int
255 fedisableexcept(int mask)
256 {
257 	return 0;
258 }
259 
260 int
261 fegetexcept(void)
262 {
263 	return 0;
264 }
265