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