261 lines
9.5 KiB
C
261 lines
9.5 KiB
C
/******************************** -*- 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
|