1 /*
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright © 2020 Keith Packard
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  *
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above
14  *    copyright notice, this list of conditions and the following
15  *    disclaimer in the documentation and/or other materials provided
16  *    with the distribution.
17  *
18  * 3. Neither the name of the copyright holder nor the names of its
19  *    contributors may be used to endorse or promote products derived
20  *    from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
27  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
31  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
33  * OF THE POSSIBILITY OF SUCH DAMAGE.
34  */
35 
36 #ifndef _MACHINE_MATH_H_
37 #define _MACHINE_MATH_H_
38 
39 #if defined(__riscv_flen) || defined(__riscv_zfinx)
40 
41 #if (__riscv_flen >= 64) || defined(__riscv_zdinx)
42 #define __RISCV_HARD_FLOAT 64
43 #else
44 #define __RISCV_HARD_FLOAT 32
45 #endif
46 
47 #ifdef _WANT_MATH_ERRNO
48 #include <errno.h>
49 #endif
50 
51 #define FCLASS_NEG_INF       (1 << 0)
52 #define FCLASS_NEG_NORMAL    (1 << 1)
53 #define FCLASS_NEG_SUBNORMAL (1 << 2)
54 #define FCLASS_NEG_ZERO      (1 << 3)
55 #define FCLASS_POS_ZERO      (1 << 4)
56 #define FCLASS_POS_SUBNORMAL (1 << 5)
57 #define FCLASS_POS_NORMAL    (1 << 6)
58 #define FCLASS_POS_INF       (1 << 7)
59 #define FCLASS_SNAN          (1 << 8)
60 #define FCLASS_QNAN          (1 << 9)
61 
62 #define FCLASS_INF           (FCLASS_NEG_INF | FCLASS_POS_INF)
63 #define FCLASS_ZERO          (FCLASS_NEG_ZERO | FCLASS_POS_ZERO)
64 #define FCLASS_NORMAL        (FCLASS_NEG_NORMAL | FCLASS_POS_NORMAL)
65 #define FCLASS_SUBNORMAL     (FCLASS_NEG_SUBNORMAL | FCLASS_POS_SUBNORMAL)
66 #define FCLASS_NAN           (FCLASS_SNAN | FCLASS_QNAN)
67 
68 #if __RISCV_HARD_FLOAT >= 64
69 
70 /* anything with a 64-bit FPU has FMA */
71 #define _HAVE_FAST_FMA 1
72 
73 #define _fclass_d(_x) (__extension__(                                   \
74                                {                                        \
75                                        long __fclass;                   \
76                                        __asm__("fclass.d %0, %1" :      \
77                                                "=r" (__fclass) :        \
78                                                "f" (_x));               \
79                                        __fclass;                        \
80                                }))
81 
82 #endif
83 
84 #if __RISCV_HARD_FLOAT >= 32
85 
86 /* anything with a 32-bit FPU has FMAF */
87 #define _HAVE_FAST_FMAF 1
88 
89 #define _fclass_f(_x) (__extension__(                                   \
90                                {                                        \
91                                        long __fclass;                   \
92                                        __asm__("fclass.s %0, %1" :      \
93                                                "=r" (__fclass) :        \
94                                                "f" (_x));               \
95                                        __fclass;                        \
96                                }))
97 
98 #endif
99 
100 
101 #ifdef __declare_extern_inline
102 
103 #if __RISCV_HARD_FLOAT >= 64
104 
105 /* Double-precision functions */
106 __declare_extern_inline(double)
copysign(double x,double y)107 copysign(double x, double y)
108 {
109 	double result;
110 	__asm__("fsgnj.d\t%0, %1, %2" : "=f" (result) : "f" (x), "f" (y));
111 	return result;
112 }
113 
114 __declare_extern_inline(double)
fabs(double x)115 fabs(double x)
116 {
117 	double result;
118 	__asm__("fabs.d\t%0, %1" : "=f"(result) : "f"(x));
119 	return result;
120 }
121 
122 __declare_extern_inline(double)
fmax(double x,double y)123 fmax (double x, double y)
124 {
125 	double result;
126         if (issignaling(x) || issignaling(y))
127             return x + y;
128 
129 	__asm__ volatile("fmax.d\t%0, %1, %2" : "=f" (result) : "f" (x), "f" (y));
130 	return result;
131 }
132 
133 __declare_extern_inline(double)
fmin(double x,double y)134 fmin (double x, double y)
135 {
136 	double result;
137         if (issignaling(x) || issignaling(y))
138             return x + y;
139 
140 	__asm__ volatile("fmin.d\t%0, %1, %2" : "=f" (result) : "f" (x), "f" (y));
141 	return result;
142 }
143 
144 __declare_extern_inline(int)
__finite(double x)145 __finite(double x)
146 {
147 	long fclass = _fclass_d (x);
148 	return (fclass & (FCLASS_INF|FCLASS_NAN)) == 0;
149 }
150 
151 __declare_extern_inline(int)
finite(double x)152 finite(double x)
153 {
154         return __finite(x);
155 }
156 
157 __declare_extern_inline(int)
__fpclassifyd(double x)158 __fpclassifyd (double x)
159 {
160   long fclass = _fclass_d (x);
161 
162   if (fclass & FCLASS_ZERO)
163     return FP_ZERO;
164   else if (fclass & FCLASS_NORMAL)
165     return FP_NORMAL;
166   else if (fclass & FCLASS_SUBNORMAL)
167     return FP_SUBNORMAL;
168   else if (fclass & FCLASS_INF)
169     return FP_INFINITE;
170   else
171     return FP_NAN;
172 }
173 
174 __declare_extern_inline(double)
sqrt(double x)175 sqrt (double x)
176 {
177 	double result;
178 #ifdef _WANT_MATH_ERRNO
179         if (isless(x, 0.0))
180             errno = EDOM;
181 #endif
182 	__asm__ volatile("fsqrt.d %0, %1" : "=f" (result) : "f" (x));
183 	return result;
184 }
185 
186 __declare_extern_inline(double)
fma(double x,double y,double z)187 fma (double x, double y, double z)
188 {
189 	double result;
190 	__asm__ volatile("fmadd.d %0, %1, %2, %3" : "=f" (result) : "f" (x), "f" (y), "f" (z));
191 	return result;
192 }
193 
194 #endif /* __RISCV_HARD_FLOAT >= 64 */
195 
196 #if __RISCV_HARD_FLOAT >= 32
197 
198 /* Single-precision functions */
199 __declare_extern_inline(float)
copysignf(float x,float y)200 copysignf(float x, float y)
201 {
202 	float result;
203 	__asm__("fsgnj.s\t%0, %1, %2" : "=f" (result) : "f" (x), "f" (y));
204 	return result;
205 }
206 
207 __declare_extern_inline(float)
fabsf(float x)208 fabsf (float x)
209 {
210 	float result;
211 	__asm__("fabs.s\t%0, %1" : "=f"(result) : "f"(x));
212 	return result;
213 }
214 
215 __declare_extern_inline(float)
fmaxf(float x,float y)216 fmaxf (float x, float y)
217 {
218 	float result;
219         if (issignaling(x) || issignaling(y))
220             return x + y;
221 
222 	__asm__ volatile("fmax.s\t%0, %1, %2" : "=f" (result) : "f" (x), "f" (y));
223 	return result;
224 }
225 
226 __declare_extern_inline(float)
fminf(float x,float y)227 fminf (float x, float y)
228 {
229 	float result;
230         if (issignaling(x) || issignaling(y))
231             return x + y;
232 
233 	__asm__ volatile("fmin.s\t%0, %1, %2" : "=f" (result) : "f" (x), "f" (y));
234 	return result;
235 }
236 
237 __declare_extern_inline(int)
__finitef(float x)238 __finitef(float x)
239 {
240 	long fclass = _fclass_f (x);
241 	return (fclass & (FCLASS_INF|FCLASS_NAN)) == 0;
242 }
243 
244 __declare_extern_inline(int)
finitef(float x)245 finitef(float x)
246 {
247         return __finitef(x);
248 }
249 
250 __declare_extern_inline(int)
__fpclassifyf(float x)251 __fpclassifyf (float x)
252 {
253   long fclass = _fclass_f (x);
254 
255   if (fclass & FCLASS_ZERO)
256     return FP_ZERO;
257   else if (fclass & FCLASS_NORMAL)
258     return FP_NORMAL;
259   else if (fclass & FCLASS_SUBNORMAL)
260     return FP_SUBNORMAL;
261   else if (fclass & FCLASS_INF)
262     return FP_INFINITE;
263   else
264     return FP_NAN;
265 }
266 
267 __declare_extern_inline(float)
sqrtf(float x)268 sqrtf (float x)
269 {
270 	float result;
271 #ifdef _WANT_MATH_ERRNO
272         if (isless(x, 0.0f))
273             errno = EDOM;
274 #endif
275 	__asm__ volatile("fsqrt.s %0, %1" : "=f" (result) : "f" (x));
276 	return result;
277 }
278 
279 __declare_extern_inline(float)
fmaf(float x,float y,float z)280 fmaf (float x, float y, float z)
281 {
282 	float result;
283 	__asm__ volatile("fmadd.s %0, %1, %2, %3" : "=f" (result) : "f" (x), "f" (y), "f" (z));
284 	return result;
285 }
286 
287 #endif /* __RISCV_HARD_FLOAT >= 32 */
288 
289 #endif /* defined(__GNUC_GNU_INLINE__) || defined(__GNUC_STDC_INLINE__) */
290 
291 #endif /* __RISCV_HARD_FLOAT */
292 
293 #endif /* _MACHINE_MATH_H_ */
294