#ifndef _LIBM_INLINES_H
#define _LIBM_INLINES_H
#ifdef __GNUC__
#ifdef __cplusplus
extern "C" {
#endif
#include <sys/types.h>
#include <sys/ieeefp.h>
#define _LO_WORD(x) ((uint32_t *)&x)[0]
#define _HI_WORD(x) ((uint32_t *)&x)[1]
#define _HIER_WORD(x) ((uint32_t *)&x)[2]
extern __GNU_INLINE double
__inline_sqrt(double a)
{
double ret;
__asm__ __volatile__("fsqrt\n\t" : "=t" (ret) : "0" (a) : "cc");
return (ret);
}
extern __GNU_INLINE double
__ieee754_sqrt(double a)
{
return (__inline_sqrt(a));
}
extern __GNU_INLINE float
__inline_sqrtf(float a)
{
float ret;
__asm__ __volatile__("fsqrt\n\t" : "=t" (ret) : "0" (a) : "cc");
return (ret);
}
extern __GNU_INLINE double
__inline_rint(double a)
{
__asm__ __volatile__(
"andl $0x7fffffff,%1\n\t"
"cmpl $0x43300000,%1\n\t"
"jae 1f\n\t"
"frndint\n\t"
"1: fwait\n\t"
: "+t" (a), "+&r" (_HI_WORD(a))
:
: "cc");
return (a);
}
extern __GNU_INLINE int
__swapRP(int i)
{
int ret;
uint16_t cw;
__asm__ __volatile__("fstcw %0\n\t" : "=m" (cw));
ret = (cw >> 8) & 0x3;
cw = (cw & 0xfcff) | ((i & 0x3) << 8);
__asm__ __volatile__("fldcw %0\n\t" : : "m" (cw));
return (ret);
}
extern __GNU_INLINE enum fp_direction_type
__swap87RD(enum fp_direction_type i)
{
int ret;
uint16_t cw;
__asm__ __volatile__("fstcw %0\n\t" : "=m" (cw));
ret = (cw >> 10) & 0x3;
cw = (cw & 0xf3ff) | ((i & 0x3) << 10);
__asm__ __volatile__("fldcw %0\n\t" : : "m" (cw));
return (ret);
}
extern __GNU_INLINE double
ceil(double d)
{
short rd = __swap87RD(fp_positive);
__asm__ __volatile__("frndint" : "+t" (d) : : "cc");
__swap87RD(rd);
return (d);
}
extern __GNU_INLINE double
copysign(double d1, double d2)
{
__asm__ __volatile__(
"andl $0x7fffffff,%0\n\t"
"andl $0x80000000,%1\n\t"
"orl %1,%0\n\t"
: "+&r" (_HI_WORD(d1)), "+r" (_HI_WORD(d2))
:
: "cc");
return (d1);
}
extern __GNU_INLINE double
fabs(double d)
{
__asm__ __volatile__("fabs\n\t" : "+t" (d) : : "cc");
return (d);
}
extern __GNU_INLINE float
fabsf(float d)
{
__asm__ __volatile__("fabs\n\t" : "+t" (d) : : "cc");
return (d);
}
extern __GNU_INLINE long double
fabsl(long double d)
{
__asm__ __volatile__("fabs\n\t" : "+t" (d) : : "cc");
return (d);
}
extern __GNU_INLINE int
finite(double d)
{
int ret = _HI_WORD(d);
__asm__ __volatile__(
"notl %0\n\t"
"andl $0x7ff00000,%0\n\t"
"negl %0\n\t"
"shrl $31,%0\n\t"
: "+r" (ret)
:
: "cc");
return (ret);
}
extern __GNU_INLINE double
floor(double d)
{
short rd = __swap87RD(fp_negative);
__asm__ __volatile__("frndint" : "+t" (d), "+r" (rd) : : "cc");
__swap87RD(rd);
return (d);
}
extern __GNU_INLINE int
isnan(double d)
{
int ret;
__asm__ __volatile__(
"movl %1,%%ecx\n\t"
"negl %%ecx\n\t"
"orl %%ecx,%1\n\t"
"shrl $31,%1\n\t"
"andl $0x7fffffff,%2\n\t"
"orl %2,%1\n\t"
"subl $0x7ff00000,%1\n\t"
"negl %1\n\t"
"shrl $31,%1\n\t"
: "=r" (ret)
: "0" (_HI_WORD(d)), "r" (_LO_WORD(d))
: "ecx");
return (ret);
}
extern __GNU_INLINE int
isnanf(float f)
{
__asm__ __volatile__(
"andl $0x7fffffff,%0\n\t"
"negl %0\n\t"
"addl $0x7f800000,%0\n\t"
"shrl $31,%0\n\t"
: "+r" (f)
:
: "cc");
return (f);
}
extern __GNU_INLINE double
rint(double a)
{
return (__inline_rint(a));
}
extern __GNU_INLINE double
scalbn(double d, int n)
{
double dummy;
__asm__ __volatile__(
"fildl %2\n\t"
"fxch\n\t"
"fscale\n\t"
: "+t" (d), "=u" (dummy)
: "m" (n)
: "cc");
return (d);
}
extern __GNU_INLINE int
signbit(double d)
{
return (_HI_WORD(d) >> 31);
}
extern __GNU_INLINE int
signbitf(float f)
{
return ((*(uint32_t *)&f) >> 31);
}
extern __GNU_INLINE double
sqrt(double d)
{
return (__inline_sqrt(d));
}
extern __GNU_INLINE float
sqrtf(float f)
{
return (__inline_sqrtf(f));
}
extern __GNU_INLINE long double
sqrtl(long double ld)
{
__asm__ __volatile__("fsqrt" : "+t" (ld) : : "cc");
return (ld);
}
extern __GNU_INLINE int
isnanl(long double ld)
{
int ret = _HIER_WORD(ld);
__asm__ __volatile__(
"andl $0x00007fff,%0\n\t"
"jz 1f\n\t"
"xorl $0x00007fff,%0\n\t"
"jz 2f\n\t"
"testl $0x80000000,%1\n\t"
"jz 3f\n\t"
"xorl %0,%0\n\t"
"jmp 1f\n\t"
"2:\n\t"
"cmpl $0x80000000,%1\n\t"
"jnz 3f\n\t"
"testl $0xffffffff,%2\n\t"
"jnz 3f\n\t"
"jmp 1f\n\t"
"3:\n\t"
"movl $1,%0\n\t"
"1:\n\t"
: "+&r" (ret)
: "r" (_HI_WORD(ld)), "r" (_LO_WORD(ld))
: "cc");
return (ret);
}
#ifdef __cplusplus
}
#endif
#endif
#endif