/******************************** -*- C -*- ****************************
 *
 *	Platform-independent layer floating-point interface
 *
 ***********************************************************************/


/***********************************************************************
 *
 * Copyright 2000, 2001, 2002 Free Software Foundation, Inc.
 * Written by Paolo Bonzini.
 *
 * This file is part of GNU lightning.
 *
 * GNU lightning is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published
 * by the Free Software Foundation; either version 2.1, or (at your option)
 * any later version.
 * 
 * GNU lightning is distributed in the hope that it will be useful, but 
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
 * License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with GNU lightning; see the file COPYING.LESSER; if not, write to the
 * Free Software Foundation, 59 Temple Place - Suite 330, Boston,
 * MA 02111-1307, USA.
 *
 ***********************************************************************/

struct jit_fp {
  char	kind;
  char  subkind;
  union {
    struct {
      int   displ;
      char  reg1;
      char  reg2;
    } addr;
    union {
      double number;
      long   split[sizeof(double) / sizeof(long)];
    } imm;
    struct {
      struct jit_fp *lhs, *rhs;
    } ops;
  } d;
};

#ifdef jit_trunc

enum {	JIT_NULL,						/* unused */
        
        JIT_CMP, JIT_FLOOR, JIT_CEIL, JIT_ROUND, JIT_TRUNC,	/* integer */
	
	JIT_XI, JIT_ADD, JIT_XR, JIT_SUB,			/* subkinds */
	JIT_I,  JIT_MUL, JIT_R,  JIT_DIV,
	JIT_INT,
	
	JIT_ABS, JIT_SIN, JIT_COS, JIT_TAN, JIT_ATN,		/* functions */
	JIT_EXP, JIT_LOG, JIT_NEG, JIT_SQRT,
	
	JIT_OP,  JIT_FN,  JIT_LD,  JIT_IMM };			/* kinds */

/* Declarations */

static void _jit_emit(jit_state *, struct jit_fp *,
		      int, int, int, int) JIT_UNUSED;
static struct jit_fp *_jit_op(struct jit_fp *, int, 
			      struct jit_fp *, struct jit_fp *) JIT_UNUSED;
static struct jit_fp *_jit_ld(struct jit_fp *, int, 
			      int, int) JIT_UNUSED;
static struct jit_fp *_jit_fn(struct jit_fp *, int, 
			      struct jit_fp *) JIT_UNUSED;
static struct jit_fp *_jit_imm(struct jit_fp *, double) JIT_UNUSED;

/* Internal function to walk the tree */

void
_jit_emit(jit_state *jit, struct jit_fp *head,
	  int store_kind, int store1, int store2, int reg0)
{
#define _jit (*jit)
  switch (head->kind) {
    case JIT_OP:
      _jit_emit(jit, head->d.ops.lhs, JIT_NULL, 0, 0, reg0);
      _jit_emit(jit, head->d.ops.rhs, JIT_NULL, 0, 0, reg0 + 1);
      switch (head->subkind) {
        case JIT_ADD: jit_add_two(reg0); break;
        case JIT_SUB: jit_sub_two(reg0); break;
        case JIT_MUL: jit_mul_two(reg0); break;
        case JIT_DIV: jit_div_two(reg0); break;
      }
      break;

    case JIT_IMM:
#ifdef JIT_LONG_IS_INT
      jit_fpimm(reg0, head->d.imm.split[0], head->d.imm.split[1]);
#else
      jit_fpimm(reg0, head->d.imm.split[0]);
#endif
      break;

    case JIT_FN:
      _jit_emit(jit, head->d.ops.lhs, JIT_NULL, 0, 0, reg0);
      switch (head->subkind) {
	case JIT_ABS: jit_abs(reg0); break;
#ifdef JIT_TRANSCENDENTAL
	case JIT_SIN: jit_sin(reg0); break;
	case JIT_SQRT: jit_sqrt(reg0); break;
	case JIT_COS: jit_cos(reg0); break;
	case JIT_TAN: jit_tan(reg0); break;
	case JIT_ATN: jit_atn(reg0); break;
	case JIT_EXP: jit_exp(reg0); break;
	case JIT_LOG: jit_log(reg0); break;
	case JIT_NEG: jit_neg(reg0); break;
#endif
      }
      break;

    case JIT_LD:
      switch (head->subkind) {
        case JIT_INT:    jit_exti_d(reg0, head->d.addr.reg1); break;
        case JIT_XI:     jit_ldxi_f(reg0, head->d.addr.reg1, head->d.addr.displ); break;
        case JIT_XR:     jit_ldxr_f(reg0, head->d.addr.reg1, head->d.addr.reg2);  break;
        case JIT_XI | 1: jit_ldxi_d(reg0, head->d.addr.reg1, head->d.addr.displ); break;
        case JIT_XR | 1: jit_ldxr_d(reg0, head->d.addr.reg1, head->d.addr.reg2);  break;
#ifndef JIT_RZERO
        case JIT_I:      jit_ldi_f(reg0, head->d.addr.displ); break;
        case JIT_R:      jit_ldr_f(reg0, head->d.addr.reg1);  break;
        case JIT_I | 1:  jit_ldi_d(reg0, head->d.addr.displ); break;
        case JIT_R | 1:  jit_ldr_d(reg0, head->d.addr.reg1);  break;
#endif
      }
      break;
  }

  switch (store_kind) {
    case JIT_FLOOR:  jit_floor(store1, reg0);		 break;
    case JIT_CEIL:   jit_ceil(store1, reg0);		 break;
    case JIT_TRUNC:  jit_trunc(store1, reg0);		 break;
    case JIT_ROUND:  jit_round(store1, reg0);		 break;
    case JIT_CMP:    jit_cmp(store1, store2, reg0);	 break;
    case JIT_XI:     jit_stxi_f(store2, store1, reg0);   break;
    case JIT_XR:     jit_stxr_f(store2, store1, reg0);   break;
    case JIT_XI | 1: jit_stxi_d(store2, store1, reg0);   break;
    case JIT_XR | 1: jit_stxr_d(store2, store1, reg0);   break;
#ifndef JIT_RZERO
    case JIT_I:      jit_sti_f(store2, reg0);		 break;
    case JIT_R:      jit_str_f(store2, reg0);		 break;
    case JIT_I | 1:  jit_sti_d(store2, reg0);		 break;
    case JIT_R | 1:  jit_str_d(store2, reg0);		 break;
     case JIT_NULL:  break;
#endif
  }
#undef _jit
}

/* Internal functions to build the tree */

struct jit_fp *
_jit_op(struct jit_fp *where, int which, 
	struct jit_fp *op1, struct jit_fp *op2)
{
  where->kind = JIT_OP;
  where->subkind = which;
  where->d.ops.lhs = op1;
  where->d.ops.rhs = op2;
  return (where);
}

struct jit_fp *
_jit_ld(struct jit_fp *where, int which, int op1, int op2)
{
  where->kind = JIT_LD;
  where->subkind = which;
  switch (which & ~1) {
    case JIT_XI: where->d.addr.reg1 = op1;
    case JIT_I:  where->d.addr.displ = op2;	break;
    case JIT_XR: where->d.addr.reg2  = op2;
    case JIT_INT:
    case JIT_R:  where->d.addr.reg1  = op1;	break;
  }
  return (where);
}

struct jit_fp *
_jit_fn(struct jit_fp *where, int which, struct jit_fp *op1)
{
  where->kind = JIT_FN;
  where->subkind = which;
  where->d.ops.lhs = op1;
  return (where);
}

struct jit_fp *
_jit_imm(struct jit_fp *where, double number)
{
  where->kind = JIT_IMM;
  where->d.imm.number = number;
  return (where);
}

#define jitfp_begin(buf)		(_jit.fp = (buf), --_jit.fp)
#define jitfp_add(op1, op2)		_jit_op(++_jit.fp, JIT_ADD, (op1), (op2))
#define jitfp_sub(op1, op2)		_jit_op(++_jit.fp, JIT_SUB, (op1), (op2))
#define jitfp_mul(op1, op2)		_jit_op(++_jit.fp, JIT_MUL, (op1), (op2))
#define jitfp_div(op1, op2)		_jit_op(++_jit.fp, JIT_DIV, (op1), (op2))
#define jitfp_imm(imm)			_jit_imm(++_jit.fp, (imm))
#define jitfp_exti_d(reg1)		_jit_ld(++_jit.fp, JIT_INT, (reg1), 0)
#define jitfp_ldxi_f(reg1, imm)		_jit_ld(++_jit.fp, JIT_XI, (reg1), (long)(imm))
#define jitfp_ldxr_f(reg1, reg2)	_jit_ld(++_jit.fp, JIT_XR, (reg1), (reg2))
#define jitfp_ldxi_d(reg1, imm)		_jit_ld(++_jit.fp, JIT_XI | 1, (reg1), (long)(imm))
#define jitfp_ldxr_d(reg1, reg2)	_jit_ld(++_jit.fp, JIT_XR | 1, (reg1), (reg2))
#define jitfp_abs(op1)	 		_jit_fn(++_jit.fp, JIT_ABS, (op1))
#define jitfp_sqrt(op1)	 		_jit_fn(++_jit.fp, JIT_SQRT, (op1))
#define jitfp_neg(op1)			_jit_fn(++_jit.fp, JIT_NEG, (op1))
#define jitfp_stxi_f(imm, reg1, op1)	_jit_emit(&_jit, (op1), JIT_XI, (reg1), (long)(imm), 0)
#define jitfp_stxr_f(reg1, reg2, op2)	_jit_emit(&_jit, (op1), JIT_XR, (reg1), (reg2), 0)
#define jitfp_stxi_d(imm, reg1, op1)	_jit_emit(&_jit, (op1), JIT_XI | 1, (reg1), (long)(imm), 0)
#define jitfp_stxr_d(reg1, reg2, op2)	_jit_emit(&_jit, (op1), JIT_XR | 1, (reg1), (reg2), 0)
#define jitfp_cmp(regle, regge, op1)	_jit_emit(&_jit, (op1), JIT_CMP, regle, regge, 0)
#define jitfp_floor(reg1, op1)		_jit_emit(&_jit, (op1), JIT_FLOOR, reg1, 0, 0)
#define jitfp_ceil(reg1, op1)		_jit_emit(&_jit, (op1), JIT_CEIL, reg1, 0, 0)
#define jitfp_trunc(reg1, op1)		_jit_emit(&_jit, (op1), JIT_TRUNC, reg1, 0, 0)
#define jitfp_round(reg1, op1)		_jit_emit(&_jit, (op1), JIT_ROUND, reg1, 0, 0)


#ifdef JIT_TRANSCENDENTAL
#define jitfp_sin(op1)			_jit_fn(++_jit.fp, JIT_SIN, (op1))
#define jitfp_cos(op1)			_jit_fn(++_jit.fp, JIT_COS, (op1))
#define jitfp_tan(op1)			_jit_fn(++_jit.fp, JIT_TAN, (op1))
#define jitfp_atn(op1)			_jit_fn(++_jit.fp, JIT_ATN, (op1))
#define jitfp_exp(op1)			_jit_fn(++_jit.fp, JIT_EXP, (op1))
#define jitfp_log(op1)			_jit_fn(++_jit.fp, JIT_LOG, (op1))
#endif

#ifdef JIT_RZERO
#define jitfp_ldi_f(imm)		_jit_ld(++_jit.fp, JIT_XI, JIT_RZERO, (long)(imm))
#define jitfp_ldr_f(reg1)		_jit_ld(++_jit.fp, JIT_XR, JIT_RZERO, (reg1))
#define jitfp_ldi_d(imm)		_jit_ld(++_jit.fp, JIT_XI | 1, JIT_RZERO, (long)(imm))
#define jitfp_ldr_d(reg1)		_jit_ld(++_jit.fp, JIT_XR | 1, JIT_RZERO, (reg1))
#define jitfp_sti_f(imm, op1)		_jit_emit(&_jit, (op1), JIT_XI, JIT_RZERO, (long)(imm), 0)
#define jitfp_str_f(reg1, op1)		_jit_emit(&_jit, (op1), JIT_XR, JIT_RZERO, (reg1), 0)
#define jitfp_sti_d(imm, op1)		_jit_emit(&_jit, (op1), JIT_XI | 1, JIT_RZERO, (long)(imm), 0)
#define jitfp_str_d(reg1, op1)		_jit_emit(&_jit, (op1), JIT_XR | 1, JIT_RZERO, (reg1), 0)
#else
#define jitfp_ldi_f(imm)		_jit_ld(++_jit.fp, JIT_I, 0, (long)(imm))
#define jitfp_ldr_f(reg1)		_jit_ld(++_jit.fp, JIT_R, 0, (reg1))
#define jitfp_ldi_d(imm)		_jit_ld(++_jit.fp, JIT_I | 1, 0, (long)(imm))
#define jitfp_ldr_d(reg1)		_jit_ld(++_jit.fp, JIT_R | 1, 0, (reg1))
#define jitfp_sti_f(imm, op1)		_jit_emit(&_jit, (op1), JIT_I, 0, (long)(imm), 0)
#define jitfp_str_f(reg1, op1)		_jit_emit(&_jit, (op1), JIT_R, 0, (reg1), 0)
#define jitfp_sti_d(imm, op1)		_jit_emit(&_jit, (op1), JIT_I | 1, 0, (long)(imm), 0)
#define jitfp_str_d(reg1, op1)		_jit_emit(&_jit, (op1), JIT_R | 1, 0, (reg1), 0)
#endif


#endif
