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