1 /*
2  * Copyright (C) 2017 Hangzhou C-SKY Microsystems co.,ltd.
3  *
4  * Licensed under the LGPL v2.1 or later, see the file COPYING.LIB
5  * in this tarball.
6  */
7 
8 #ifdef	__GNUC__
9 
10 #ifdef __USE_ISOC99
11 
12 /* ISO C99 defines some macros to perform unordered comparisons.  The
13    csky FPU supports this with special opcodes and we should use them.
14    These must not be inline functions since we have to be able to handle
15    all floating-point types.  */
16 # define isgreater(x, y)					\
17    __extension__					\
18    ({ char __result;					\
19       __asm__ ("fcmp%.x %2,%1; fsogt %0"		\
20 	       : "=dm" (__result) : "f" (x), "f" (y));	\
21       __result != 0; })
22 
23 # define isgreaterequal(x, y)				\
24    __extension__					\
25    ({ char __result;					\
26       __asm__ ("fcmp%.x %2,%1; fsoge %0"		\
27 	       : "=dm" (__result) : "f" (x), "f" (y));	\
28       __result != 0; })
29 
30 # define isless(x, y)					\
31    __extension__					\
32    ({ char __result;					\
33       __asm__ ("fcmp%.x %2,%1; fsolt %0"		\
34 	       : "=dm" (__result) : "f" (x), "f" (y));	\
35       __result != 0; })
36 
37 # define islessequal(x, y)				\
38    __extension__					\
39    ({ char __result;					\
40       __asm__ ("fcmp%.x %2,%1; fsole %0"		\
41 	       : "=dm" (__result) : "f" (x), "f" (y));	\
42       __result != 0; })
43 
44 # define islessgreater(x, y)				\
45    __extension__					\
46    ({ char __result;					\
47       __asm__ ("fcmp%.x %2,%1; fsogl %0"		\
48 	       : "=dm" (__result) : "f" (x), "f" (y));	\
49       __result != 0; })
50 
51 # define isunordered(x, y)				\
52    __extension__					\
53    ({ char __result;					\
54       __asm__ ("fcmp%.x %2,%1; fsun %0"			\
55 	       : "=dm" (__result) : "f" (x), "f" (y));	\
56       __result != 0; })
57 #endif
58 
59 
60 #if (!defined __NO_MATH_INLINES && defined __OPTIMIZE__) \
61     || defined __LIBC_INTERNAL_MATH_INLINES
62 
63 #ifdef	__LIBC_INTERNAL_MATH_INLINES
64 /* This is used when defining the functions themselves.  Define them with
65    __ names, and with `static inline' instead of `extern inline' so the
66    bodies will always be used, never an external function call.  */
67 # define __m81_u(x)		__CONCAT(__,x)
68 # define __m81_inline		static __inline
69 #else
70 # define __m81_u(x)		x
71 # ifdef __cplusplus
72 #  define __m81_inline		__inline
73 # else
74 #  define __m81_inline		extern __inline
75 # endif
76 # define __M81_MATH_INLINES	1
77 #endif
78 
79 /* Define a const math function.  */
80 #define __m81_defun(rettype, func, args)				      \
81   __m81_inline rettype __attribute__((__const__))			      \
82   __m81_u(func) args
83 
84 /* Define the three variants of a math function that has a direct
85    implementation in the csky fpu.  FUNC is the name for C (which will be
86    suffixed with f and l for the float and long double version, resp).  OP
87    is the name of the fpu operation (without leading f).  */
88 
89 #if defined __USE_MISC || defined __USE_ISOC99
90 # define __inline_mathop(func, op)			\
91   __inline_mathop1(double, func, op)			\
92   __inline_mathop1(float, __CONCAT(func,f), op)		\
93   __inline_mathop1(long double, __CONCAT(func,l), op)
94 #else
95 # define __inline_mathop(func, op)			\
96   __inline_mathop1(double, func, op)
97 #endif
98 
99 #define __inline_mathop1(float_type,func, op)				      \
100   __m81_defun (float_type, func, (float_type __mathop_x)) __THROW	      \
101   {									      \
102     float_type __result;						      \
103     __asm("f" __STRING(op) "%.x %1, %0" : "=f" (__result) : "f" (__mathop_x));\
104     return __result;							      \
105   }
106 
107 __inline_mathop(__atan, atan)
108 __inline_mathop(__cos, cos)
109 __inline_mathop(__sin, sin)
110 __inline_mathop(__tan, tan)
111 __inline_mathop(__tanh, tanh)
112 __inline_mathop(__fabs, abs)
113 
114 #if defined __USE_MISC || defined __USE_XOPEN_EXTENDED || defined __USE_ISOC99
115 __inline_mathop(__rint, int)
116 __inline_mathop(__expm1, etoxm1)
117 __inline_mathop(__log1p, lognp1)
118 #endif
119 
120 #ifdef __USE_MISC
121 __inline_mathop(__significand, getman)
122 #endif
123 
124 #ifdef __USE_ISOC99
125 __inline_mathop(__trunc, intrz)
126 #endif
127 
128 #if !defined __NO_MATH_INLINES && defined __OPTIMIZE__
129 
130 __inline_mathop(atan, atan)
131 __inline_mathop(cos, cos)
132 __inline_mathop(sin, sin)
133 __inline_mathop(tan, tan)
134 __inline_mathop(tanh, tanh)
135 
136 # if defined __USE_MISC || defined __USE_XOPEN_EXTENDED || defined __USE_ISOC99
137 __inline_mathop(rint, int)
138 __inline_mathop(expm1, etoxm1)
139 __inline_mathop(log1p, lognp1)
140 # endif
141 
142 # ifdef __USE_MISC
143 __inline_mathop(significand, getman)
144 # endif
145 
146 # ifdef __USE_ISOC99
147 __inline_mathop(trunc, intrz)
148 # endif
149 
150 #endif /* !__NO_MATH_INLINES && __OPTIMIZE__ */
151 
152 /* This macro contains the definition for the rest of the inline
153    functions, using FLOAT_TYPE as the domain type and S as the suffix
154    for the function names.  */
155 
156 #define __inline_functions(float_type, s)				  \
157 __m81_inline float_type							  \
158 __m81_u(__CONCAT(__frexp,s))(float_type __value, int *__expptr)	__THROW	  \
159 {									  \
160   float_type __mantissa, __exponent;					  \
161   int __iexponent;							  \
162   unsigned long __fpsr;							  \
163   __asm("ftst%.x %1\n"							  \
164 	"fmove%.l %/fpsr, %0" : "=dm" (__fpsr) : "f" (__value));	  \
165   if (__fpsr & (7 << 24))						  \
166     {									  \
167       /* Not finite or zero.  */					  \
168       *__expptr = 0;							  \
169       return __value;							  \
170     }									  \
171   __asm("fgetexp%.x %1, %0" : "=f" (__exponent) : "f" (__value));	  \
172   __iexponent = (int) __exponent + 1;					  \
173   *__expptr = __iexponent;						  \
174   __asm("fscale%.l %2, %0" : "=f" (__mantissa)				  \
175 	: "0" (__value), "dmi" (-__iexponent));				  \
176   return __mantissa;							  \
177 }									  \
178 									  \
179 __m81_defun (float_type, __CONCAT(__floor,s), (float_type __x))	__THROW	  \
180 {									  \
181   float_type __result;							  \
182   unsigned long int __ctrl_reg;						  \
183   __asm __volatile__ ("fmove%.l %!, %0" : "=dm" (__ctrl_reg));		  \
184   /* Set rounding towards negative infinity.  */			  \
185   __asm __volatile__ ("fmove%.l %0, %!" : /* No outputs.  */		  \
186 		      : "dmi" ((__ctrl_reg & ~0x10) | 0x20));		  \
187   /* Convert X to an integer, using -Inf rounding.  */			  \
188   __asm __volatile__ ("fint%.x %1, %0" : "=f" (__result) : "f" (__x));	  \
189   /* Restore the previous rounding mode.  */				  \
190   __asm __volatile__ ("fmove%.l %0, %!" : /* No outputs.  */		  \
191 		      : "dmi" (__ctrl_reg));				  \
192   return __result;							  \
193 }									  \
194 									  \
195 __m81_defun (float_type, __CONCAT(__ceil,s), (float_type __x)) __THROW	  \
196 {									  \
197   float_type __result;							  \
198   unsigned long int __ctrl_reg;						  \
199   __asm __volatile__ ("fmove%.l %!, %0" : "=dm" (__ctrl_reg));		  \
200   /* Set rounding towards positive infinity.  */			  \
201   __asm __volatile__ ("fmove%.l %0, %!" : /* No outputs.  */		  \
202 		      : "dmi" (__ctrl_reg | 0x30));			  \
203   /* Convert X to an integer, using +Inf rounding.  */			  \
204   __asm __volatile__ ("fint%.x %1, %0" : "=f" (__result) : "f" (__x));	  \
205   /* Restore the previous rounding mode.  */				  \
206   __asm __volatile__ ("fmove%.l %0, %!" : /* No outputs.  */		  \
207 		      : "dmi" (__ctrl_reg));				  \
208   return __result;							  \
209 }
210 
211 __inline_functions(double,)
212 #if defined __USE_MISC || defined __USE_ISOC99
213 __inline_functions(float,f)
214 __inline_functions(long double,l)
215 #endif
216 #undef __inline_functions
217 
218 #ifdef __USE_MISC
219 
220 # define __inline_functions(float_type, s)				  \
221 __m81_defun (int, __CONCAT(__isinf,s), (float_type __value)) __THROW	  \
222 {									  \
223   /* There is no branch-condition for infinity,				  \
224      so we must extract and examine the condition codes manually.  */	  \
225   unsigned long int __fpsr;						  \
226   __asm("ftst%.x %1\n"							  \
227 	"fmove%.l %/fpsr, %0" : "=dm" (__fpsr) : "f" (__value));	  \
228   return (__fpsr & (2 << 24)) ? (__fpsr & (8 << 24) ? -1 : 1) : 0;	  \
229 }									  \
230 									  \
231 __m81_defun (int, __CONCAT(__finite,s), (float_type __value)) __THROW	  \
232 {									  \
233   /* There is no branch-condition for infinity, so we must extract and	  \
234      examine the condition codes manually.  */				  \
235   unsigned long int __fpsr;						  \
236   __asm ("ftst%.x %1\n"							  \
237 	 "fmove%.l %/fpsr, %0" : "=dm" (__fpsr) : "f" (__value));	  \
238   return (__fpsr & (3 << 24)) == 0;					  \
239 }									  \
240 									  \
241 __m81_defun (float_type, __CONCAT(__scalbn,s),				  \
242 	     (float_type __x, int __n))	__THROW				  \
243 {									  \
244   float_type __result;							  \
245   __asm ("fscale%.l %1, %0" : "=f" (__result) : "dmi" (__n), "0" (__x));  \
246   return __result;							  \
247 }
248 
249 __inline_functions(double,)
250 __inline_functions(float,f)
251 __inline_functions(long double,l)
252 # undef __inline_functions
253 
254 #endif /* Use misc.  */
255 
256 #if defined __USE_MISC || defined __USE_XOPEN
257 
258 # define __inline_functions(float_type, s)				  \
259 __m81_defun (int, __CONCAT(__isnan,s), (float_type __value)) __THROW	  \
260 {									  \
261   char __result;							  \
262   __asm("ftst%.x %1\n"							  \
263 	"fsun %0" : "=dm" (__result) : "f" (__value));			  \
264   return __result;							  \
265 }
266 
267 __inline_functions(double,)
268 # ifdef __USE_MISC
269 __inline_functions(float,f)
270 __inline_functions(long double,l)
271 # endif
272 # undef __inline_functions
273 
274 #endif
275 
276 #ifdef __USE_ISOC99
277 
278 # define __inline_functions(float_type, s)				  \
279 __m81_defun (int, __CONCAT(__signbit,s), (float_type __value)) __THROW	  \
280 {									  \
281   /* There is no branch-condition for the sign bit, so we must extract	  \
282      and examine the condition codes manually.  */			  \
283   unsigned long int __fpsr;						  \
284   __asm ("ftst%.x %1\n"							  \
285 	 "fmove%.l %/fpsr, %0" : "=dm" (__fpsr) : "f" (__value));	  \
286   return (__fpsr >> 27) & 1;						  \
287 }									  \
288 									  \
289 __m81_defun (float_type, __CONCAT(__scalbln,s),				  \
290 	     (float_type __x, long int __n)) __THROW			  \
291 {									  \
292   return __CONCAT(__scalbn,s) (__x, __n);				  \
293 }									  \
294 									  \
295 __m81_defun (float_type, __CONCAT(__nearbyint,s), (float_type __x)) __THROW \
296 {									  \
297   float_type __result;							  \
298   unsigned long int __ctrl_reg;						  \
299   __asm __volatile__ ("fmove%.l %!, %0" : "=dm" (__ctrl_reg));		  \
300   /* Temporarily disable the inexact exception.  */			  \
301   __asm __volatile__ ("fmove%.l %0, %!" : /* No outputs.  */		  \
302 		      : "dmi" (__ctrl_reg & ~0x200));			  \
303   __asm __volatile__ ("fint%.x %1, %0" : "=f" (__result) : "f" (__x));	  \
304   __asm __volatile__ ("fmove%.l %0, %!" : /* No outputs.  */		  \
305 		      : "dmi" (__ctrl_reg));				  \
306   return __result;							  \
307 }									  \
308 									  \
309 __m81_defun (long int, __CONCAT(__lrint,s), (float_type __x)) __THROW	  \
310 {									  \
311   long int __result;							  \
312   __asm ("fmove%.l %1, %0" : "=dm" (__result) : "f" (__x));		  \
313   return __result;							  \
314 }									  \
315 									  \
316 __m81_inline float_type							  \
317 __m81_u(__CONCAT(__fma,s))(float_type __x, float_type __y,		  \
318 			   float_type __z) __THROW			  \
319 {									  \
320   return (__x * __y) + __z;						  \
321 }
322 
323 __inline_functions (double,)
324 __inline_functions (float,f)
325 __inline_functions (long double,l)
326 # undef __inline_functions
327 
328 #endif /* Use ISO C9x */
329 
330 #ifdef __USE_GNU
331 
332 # define __inline_functions(float_type, s)				\
333 __m81_inline void							\
334 __m81_u(__CONCAT(__sincos,s))(float_type __x, float_type *__sinx,	\
335 			      float_type *__cosx) __THROW		\
336 {									\
337   __asm ("fsincos%.x %2,%1:%0"						\
338 	 : "=f" (*__sinx), "=f" (*__cosx) : "f" (__x));			\
339 }
340 
341 __inline_functions (double,)
342 __inline_functions (float,f)
343 __inline_functions (long double,l)
344 # undef __inline_functions
345 
346 #endif
347 
348 #if !defined __NO_MATH_INLINES && defined __OPTIMIZE__
349 
350 /* Define inline versions of the user visible functions.  */
351 
352 /* Note that there must be no whitespace before the argument passed for
353    NAME, to make token pasting work correctly with -traditional.  */
354 # define __inline_forward_c(rettype, name, args1, args2)	\
355 extern __inline rettype __attribute__((__const__))	\
356 name args1 __THROW					\
357 {							\
358   return __CONCAT(__,name) args2;			\
359 }
360 
361 # define __inline_forward(rettype, name, args1, args2)	\
362 extern __inline rettype name args1 __THROW		\
363 {							\
364   return __CONCAT(__,name) args2;			\
365 }
366 
367 __inline_forward(double,frexp, (double __value, int *__expptr),
368 		 (__value, __expptr))
369 __inline_forward_c(double,floor, (double __x), (__x))
370 __inline_forward_c(double,ceil, (double __x), (__x))
371 # ifdef __USE_MISC
372 #  ifndef __USE_ISOC99 /* Conflict with macro of same name.  */
373 __inline_forward_c(int,isinf, (double __value), (__value))
374 #  endif
375 __inline_forward_c(int,finite, (double __value), (__value))
376 __inline_forward_c(double,scalbn, (double __x, int __n), (__x, __n))
377 # endif
378 # if defined __USE_MISC || defined __USE_XOPEN
379 #  ifndef __USE_ISOC99 /* Conflict with macro of same name.  */
380 __inline_forward_c(int,isnan, (double __value), (__value))
381 #  endif
382 # endif
383 # ifdef __USE_ISOC99
384 __inline_forward_c(double,scalbln, (double __x, long int __n), (__x, __n))
385 __inline_forward_c(double,nearbyint, (double __value), (__value))
386 __inline_forward_c(long int,lrint, (double __value), (__value))
387 __inline_forward_c(double,fma, (double __x, double __y, double __z),
388 		   (__x, __y, __z))
389 # endif
390 # ifdef __USE_GNU
391 __inline_forward(void,sincos, (double __x, double *__sinx, double *__cosx),
392 		 (__x, __sinx, __cosx))
393 # endif
394 
395 # if defined __USE_MISC || defined __USE_ISOC99
396 
397 __inline_forward(float,frexpf, (float __value, int *__expptr),
398 		 (__value, __expptr))
399 __inline_forward_c(float,floorf, (float __x), (__x))
400 __inline_forward_c(float,ceilf, (float __x), (__x))
401 #  ifdef __USE_MISC
402 __inline_forward_c(int,isinff, (float __value), (__value))
403 __inline_forward_c(int,finitef, (float __value), (__value))
404 __inline_forward_c(float,scalbnf, (float __x, int __n), (__x, __n))
405 __inline_forward_c(int,isnanf, (float __value), (__value))
406 #  endif
407 # ifdef __USE_ISOC99
408 __inline_forward_c(float,scalblnf, (float __x, long int __n), (__x, __n))
409 __inline_forward_c(float,nearbyintf, (float __value), (__value))
410 __inline_forward_c(long int,lrintf, (float __value), (__value))
411 __inline_forward_c(float,fmaf, (float __x, float __y, float __z),
412 		   (__x, __y, __z))
413 # endif
414 # ifdef __USE_GNU
415 __inline_forward(void,sincosf, (float __x, float *__sinx, float *__cosx),
416 		 (__x, __sinx, __cosx))
417 # endif
418 
419 __inline_forward(long double,frexpl, (long double __value, int *__expptr),
420 		 (__value, __expptr))
421 __inline_forward_c(long double,floorl, (long double __x), (__x))
422 __inline_forward_c(long double,ceill, (long double __x), (__x))
423 # ifdef __USE_MISC
424 __inline_forward_c(int,isinfl, (long double __value), (__value))
425 __inline_forward_c(int,finitel, (long double __value), (__value))
426 __inline_forward_c(long double,scalbnl, (long double __x, int __n), (__x, __n))
427 __inline_forward_c(int,isnanl, (long double __value), (__value))
428 # endif
429 # ifdef __USE_ISOC99
430 __inline_forward_c(long double,scalblnl, (long double __x, long int __n),
431 		   (__x, __n))
432 __inline_forward_c(long double,nearbyintl, (long double __value), (__value))
433 __inline_forward_c(long int,lrintl, (long double __value), (__value))
434 __inline_forward_c(long double,fmal,
435 		   (long double __x, long double __y, long double __z),
436 		   (__x, __y, __z))
437 # endif
438 # ifdef __USE_GNU
439 __inline_forward(void,sincosl,
440 		 (long double __x, long double *__sinx, long double *__cosx),
441 		 (__x, __sinx, __cosx))
442 # endif
443 
444 #endif /* Use misc or ISO C99 */
445 
446 #undef __inline_forward
447 #undef __inline_forward_c
448 
449 #endif /* !__NO_MATH_INLINES && __OPTIMIZE__ */
450 
451 #endif
452 #endif
453