#ifndef _FPU_H
#define _FPU_H

/*
 * include file for FPU instructions.  
 *
 * It would be nice to be able to communicate the various forms of these
 * insns to the compiler, but it is not to be.
 *
 * For instance, "fsinb #1,fp0" is reasonable and small, but
 * I don't want to have multiple #define's for 'sin(x)'.
 */

/*
 * The _81 macro below turns "#define sin(x) _81("fsinx",x)" into this:
 *
 * #define sin(x) ({double in=(x), out; 
 * 	asm("fsinx %1,%0" : "=f" (out) : "f" (in)); out;})
 *
 * And then a call like x=sin(x) (for global double x) produces this 
 * assembly code:
 *
 *	fmoved _x,fp0
 *	fsinx fp0,fp0
 *	fmoved fp0,_x
 */

#define _81(insn,x) (double)({double in=(x), out; \
	__asm(insn " %1,%0" : "=f" (out) : "f" (in)); out;})

#define acos(x) _81("facosx",x)
#define asin(x) _81("fasinx",x)
#define atan(x) _81("fatanx",x)
#define atanh(x) _81("fatanhx",x)
#define cos(x) _81("fcosx",x)
#define cosh(x) _81("fcoshx",x)
#define dabs(x) _81("fabsx",x)
#define fabs(x) dabs(x)
#define exp(x) _81("fetoxx",x)
#define log(x) _81("flognx",x)
#define log10(x) _81("flog10x",x)
#define sin(x) _81("fsinx",x)
#define sinh(x) _81("fsinhx",x)
#define sqrt(x) _81("fsqrtx",x)
#define tan(x) _81("ftanx",x)
#define tanh(x) _81("ftanhx",x)

#define floor(x) _81("fintrzx",x)
#define ceil(x) (- _81("fintrzx",-(x)))

#define rint(x) _81("fintx",x)

#define fmod(x,y) (double)({double _x=(x), _y=(y); \
	__asm("fmodx %2,%0" : "=f" (_x) : "0" (_x), "f" (_y)); _x;})

#define copysign(x,y) ({double _x=x, _y=y; (y>0.0 ? (x>0.0 ? x : -x) : (x<0.0 ? x : -x));})

static inline double pow(double x,double y)
{
    double temp;
    long l;
    if (x <= 0.) {
	if (x == 0.) {
	    if (y <= 0.) goto domain;
	    return 0.;
	}
	l = y;
	if (l != y) goto domain;
	temp = exp(y * log(-x));
	if (l & 1) temp = -temp;
	return temp;
    }
    return (exp(y * log(x)));

domain:
    return HUGE;
}

#endif
