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 #ifdef __riscv_flen
40
41 #ifdef _WANT_MATH_ERRNO
42 #include <errno.h>
43 #endif
44
45 #define FCLASS_NEG_INF (1 << 0)
46 #define FCLASS_NEG_NORMAL (1 << 1)
47 #define FCLASS_NEG_SUBNORMAL (1 << 2)
48 #define FCLASS_NEG_ZERO (1 << 3)
49 #define FCLASS_POS_ZERO (1 << 4)
50 #define FCLASS_POS_SUBNORMAL (1 << 5)
51 #define FCLASS_POS_NORMAL (1 << 6)
52 #define FCLASS_POS_INF (1 << 7)
53 #define FCLASS_SNAN (1 << 8)
54 #define FCLASS_QNAN (1 << 9)
55
56 #define FCLASS_INF (FCLASS_NEG_INF | FCLASS_POS_INF)
57 #define FCLASS_ZERO (FCLASS_NEG_ZERO | FCLASS_POS_ZERO)
58 #define FCLASS_NORMAL (FCLASS_NEG_NORMAL | FCLASS_POS_NORMAL)
59 #define FCLASS_SUBNORMAL (FCLASS_NEG_SUBNORMAL | FCLASS_POS_SUBNORMAL)
60 #define FCLASS_NAN (FCLASS_SNAN | FCLASS_QNAN)
61
62 #if __riscv_flen >= 64
63
64 /* anything with a 64-bit FPU has FMA */
65 #define _HAVE_FAST_FMA 1
66
67 #define _fclass_d(_x) (__extension__( \
68 { \
69 long __fclass; \
70 __asm__("fclass.d %0, %1" : \
71 "=r" (__fclass) : \
72 "f" (_x)); \
73 __fclass; \
74 }))
75
76 #endif
77
78 #if __riscv_flen >= 32
79
80 /* anything with a 32-bit FPU has FMAF */
81 #define _HAVE_FAST_FMAF 1
82
83 #define _fclass_f(_x) (__extension__( \
84 { \
85 long __fclass; \
86 __asm__("fclass.s %0, %1" : \
87 "=r" (__fclass) : \
88 "f" (_x)); \
89 __fclass; \
90 }))
91
92 #endif
93
94
95 /**
96 * Not available for all compilers.
97 * In case of absence, fall back to normal function calls
98 */
99 #if defined(__GNUC_GNU_INLINE__) || defined(__GNUC_STDC_INLINE__)
100
101 # define __declare_riscv_macro(type) extern __inline type __attribute((gnu_inline, always_inline))
102
103 #if __riscv_flen >= 64
104
105 /* Double-precision functions */
106 __declare_riscv_macro(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_riscv_macro(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_riscv_macro(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_riscv_macro(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_riscv_macro(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_riscv_macro(int)
finite(double x)152 finite(double x)
153 {
154 return __finite(x);
155 }
156
157 __declare_riscv_macro(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_riscv_macro(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_riscv_macro(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_flen >= 64 */
195
196 #if __riscv_flen >= 32
197
198 /* Single-precision functions */
199 __declare_riscv_macro(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_riscv_macro(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_riscv_macro(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_riscv_macro(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_riscv_macro(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_riscv_macro(int)
finitef(float x)245 finitef(float x)
246 {
247 return __finitef(x);
248 }
249
250 __declare_riscv_macro(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_riscv_macro(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_riscv_macro(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_flen >= 32 */
288
289 #endif /* defined(__GNUC_GNU_INLINE__) || defined(__GNUC_STDC_INLINE__) */
290
291 #endif /* __riscv_flen */
292
293 #endif /* _MACHINE_MATH_H_ */
294