mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-28 20:51:13 +00:00
e2c672da7b
Original commit message from CVS: * gst/goom/goomsl.c: (gsl_read_file): Check return value of fread() to avoid compiler warnings.
1664 lines
48 KiB
C
1664 lines
48 KiB
C
#include <math.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <glib.h>
|
|
#include "goomsl.h"
|
|
#include "goomsl_private.h"
|
|
#include "goomsl_yacc.h"
|
|
|
|
/*#define TRACE_SCRIPT*/
|
|
|
|
/* {{{ definition of the instructions number */
|
|
#define INSTR_SETI_VAR_INTEGER 1
|
|
#define INSTR_SETI_VAR_VAR 2
|
|
#define INSTR_SETF_VAR_FLOAT 3
|
|
#define INSTR_SETF_VAR_VAR 4
|
|
#define INSTR_NOP 5
|
|
/* #define INSTR_JUMP 6 */
|
|
#define INSTR_SETP_VAR_PTR 7
|
|
#define INSTR_SETP_VAR_VAR 8
|
|
#define INSTR_SUBI_VAR_INTEGER 9
|
|
#define INSTR_SUBI_VAR_VAR 10
|
|
#define INSTR_SUBF_VAR_FLOAT 11
|
|
#define INSTR_SUBF_VAR_VAR 12
|
|
#define INSTR_ISLOWERF_VAR_VAR 13
|
|
#define INSTR_ISLOWERF_VAR_FLOAT 14
|
|
#define INSTR_ISLOWERI_VAR_VAR 15
|
|
#define INSTR_ISLOWERI_VAR_INTEGER 16
|
|
#define INSTR_ADDI_VAR_INTEGER 17
|
|
#define INSTR_ADDI_VAR_VAR 18
|
|
#define INSTR_ADDF_VAR_FLOAT 19
|
|
#define INSTR_ADDF_VAR_VAR 20
|
|
#define INSTR_MULI_VAR_INTEGER 21
|
|
#define INSTR_MULI_VAR_VAR 22
|
|
#define INSTR_MULF_VAR_FLOAT 23
|
|
#define INSTR_MULF_VAR_VAR 24
|
|
#define INSTR_DIVI_VAR_INTEGER 25
|
|
#define INSTR_DIVI_VAR_VAR 26
|
|
#define INSTR_DIVF_VAR_FLOAT 27
|
|
#define INSTR_DIVF_VAR_VAR 28
|
|
/* #define INSTR_JZERO 29 */
|
|
#define INSTR_ISEQUALP_VAR_VAR 30
|
|
#define INSTR_ISEQUALP_VAR_PTR 31
|
|
#define INSTR_ISEQUALI_VAR_VAR 32
|
|
#define INSTR_ISEQUALI_VAR_INTEGER 33
|
|
#define INSTR_ISEQUALF_VAR_VAR 34
|
|
#define INSTR_ISEQUALF_VAR_FLOAT 35
|
|
/* #define INSTR_CALL 36 */
|
|
/* #define INSTR_RET 37 */
|
|
/* #define INSTR_EXT_CALL 38 */
|
|
#define INSTR_NOT_VAR 39
|
|
/* #define INSTR_JNZERO 40 */
|
|
#define INSTR_SETS_VAR_VAR 41
|
|
#define INSTR_ISEQUALS_VAR_VAR 42
|
|
#define INSTR_ADDS_VAR_VAR 43
|
|
#define INSTR_SUBS_VAR_VAR 44
|
|
#define INSTR_MULS_VAR_VAR 45
|
|
#define INSTR_DIVS_VAR_VAR 46
|
|
|
|
/* }}} */
|
|
/* {{{ definition of the validation error types */
|
|
static const char *VALIDATE_OK = "ok";
|
|
|
|
#define VALIDATE_ERROR "error while validating "
|
|
#define VALIDATE_TODO "todo"
|
|
#define VALIDATE_SYNTHAX_ERROR "synthax error"
|
|
#define VALIDATE_NO_SUCH_INT "no such integer variable"
|
|
#define VALIDATE_NO_SUCH_VAR "no such variable"
|
|
#define VALIDATE_NO_SUCH_DEST_VAR "no such destination variable"
|
|
#define VALIDATE_NO_SUCH_SRC_VAR "no such src variable"
|
|
/* }}} */
|
|
|
|
/***********************************/
|
|
/* PROTOTYPE OF INTERNAL FUNCTIONS */
|
|
/***********************************/
|
|
|
|
/* {{{ */
|
|
static void gsl_instr_free (Instruction * _this);
|
|
static const char *gsl_instr_validate (Instruction * _this);
|
|
static void gsl_instr_display (Instruction * _this);
|
|
|
|
static InstructionFlow *iflow_new (void);
|
|
static void iflow_add_instr (InstructionFlow * _this, Instruction * instr);
|
|
static void iflow_clean (InstructionFlow * _this);
|
|
static void iflow_free (InstructionFlow * _this);
|
|
static void iflow_execute (FastInstructionFlow * _this, GoomSL * gsl);
|
|
|
|
/* }}} */
|
|
|
|
/************************************/
|
|
/* DEFINITION OF INTERNAL FUNCTIONS */
|
|
/************************************/
|
|
|
|
void
|
|
iflow_free (InstructionFlow * _this)
|
|
{ /* {{{ */
|
|
goom_hash_free (_this->labels);
|
|
free (_this); /*TODO: finir cette fonction */
|
|
} /* }}} */
|
|
|
|
void
|
|
iflow_clean (InstructionFlow * _this)
|
|
{ /* {{{ */
|
|
/* TODO: clean chaque instruction du flot */
|
|
_this->number = 0;
|
|
goom_hash_free (_this->labels);
|
|
_this->labels = goom_hash_new ();
|
|
} /* }}} */
|
|
|
|
InstructionFlow *
|
|
iflow_new (void)
|
|
{ /* {{{ */
|
|
InstructionFlow *_this =
|
|
(InstructionFlow *) malloc (sizeof (InstructionFlow));
|
|
_this->number = 0;
|
|
_this->tabsize = 6;
|
|
_this->instr =
|
|
(Instruction **) malloc (_this->tabsize * sizeof (Instruction *));
|
|
_this->labels = goom_hash_new ();
|
|
|
|
return _this;
|
|
} /* }}} */
|
|
|
|
void
|
|
iflow_add_instr (InstructionFlow * _this, Instruction * instr)
|
|
{ /* {{{ */
|
|
if (_this->number == _this->tabsize) {
|
|
_this->tabsize *= 2;
|
|
_this->instr =
|
|
(Instruction **) realloc (_this->instr,
|
|
_this->tabsize * sizeof (Instruction *));
|
|
}
|
|
_this->instr[_this->number] = instr;
|
|
instr->address = _this->number;
|
|
_this->number++;
|
|
} /* }}} */
|
|
|
|
void
|
|
gsl_instr_set_namespace (Instruction * _this, GoomHash * ns)
|
|
{ /* {{{ */
|
|
if (_this->cur_param <= 0) {
|
|
fprintf (stderr, "ERROR: Line %d, No more params to instructions\n",
|
|
_this->line_number);
|
|
exit (1);
|
|
}
|
|
_this->vnamespace[_this->cur_param - 1] = ns;
|
|
} /* }}} */
|
|
|
|
void
|
|
gsl_instr_add_param (Instruction * instr, char *param, int type)
|
|
{ /* {{{ */
|
|
int len;
|
|
|
|
if (instr == NULL)
|
|
return;
|
|
if (instr->cur_param == 0)
|
|
return;
|
|
--instr->cur_param;
|
|
len = strlen (param);
|
|
instr->params[instr->cur_param] = (char *) malloc (len + 1);
|
|
strcpy (instr->params[instr->cur_param], param);
|
|
instr->types[instr->cur_param] = type;
|
|
if (instr->cur_param == 0) {
|
|
|
|
const char *result = gsl_instr_validate (instr);
|
|
|
|
if (result != VALIDATE_OK) {
|
|
printf ("ERROR: Line %d: ", instr->parent->num_lines + 1);
|
|
gsl_instr_display (instr);
|
|
printf ("... %s\n", result);
|
|
instr->parent->compilationOK = 0;
|
|
exit (1);
|
|
}
|
|
#if USE_JITC_X86
|
|
iflow_add_instr (instr->parent->iflow, instr);
|
|
#else
|
|
if (instr->id != INSTR_NOP)
|
|
iflow_add_instr (instr->parent->iflow, instr);
|
|
else
|
|
gsl_instr_free (instr);
|
|
#endif
|
|
}
|
|
} /* }}} */
|
|
|
|
Instruction *
|
|
gsl_instr_init (GoomSL * parent, const char *name, int id, int nb_param,
|
|
int line_number)
|
|
{ /* {{{ */
|
|
Instruction *instr = (Instruction *) malloc (sizeof (Instruction));
|
|
instr->params = (char **) malloc (nb_param * sizeof (char *));
|
|
instr->vnamespace = (GoomHash **) malloc (nb_param * sizeof (GoomHash *));
|
|
instr->types = (int *) malloc (nb_param * sizeof (int));
|
|
instr->cur_param = instr->nb_param = nb_param;
|
|
instr->parent = parent;
|
|
instr->id = id;
|
|
instr->name = name;
|
|
instr->jump_label = NULL;
|
|
instr->line_number = line_number;
|
|
return instr;
|
|
} /* }}} */
|
|
|
|
void
|
|
gsl_instr_free (Instruction * _this)
|
|
{ /* {{{ */
|
|
int i;
|
|
|
|
free (_this->types);
|
|
for (i = _this->cur_param; i < _this->nb_param; ++i)
|
|
free (_this->params[i]);
|
|
free (_this->params);
|
|
free (_this);
|
|
} /* }}} */
|
|
|
|
void
|
|
gsl_instr_display (Instruction * _this)
|
|
{ /* {{{ */
|
|
int i = _this->nb_param - 1;
|
|
|
|
printf ("%s", _this->name);
|
|
while (i >= _this->cur_param) {
|
|
printf (" %s", _this->params[i]);
|
|
--i;
|
|
}
|
|
} /* }}} */
|
|
|
|
/****************************************/
|
|
/* VALIDATION OF INSTRUCTION PARAMETERS */
|
|
/****************************************/
|
|
|
|
static const char *
|
|
validate_v_v (Instruction * _this)
|
|
{ /* {{{ */
|
|
HashValue *dest = goom_hash_get (_this->vnamespace[1], _this->params[1]);
|
|
HashValue *src = goom_hash_get (_this->vnamespace[0], _this->params[0]);
|
|
|
|
if (dest == NULL) {
|
|
return VALIDATE_NO_SUCH_DEST_VAR;
|
|
}
|
|
if (src == NULL) {
|
|
return VALIDATE_NO_SUCH_SRC_VAR;
|
|
}
|
|
_this->data.udest.var = dest->ptr;
|
|
_this->data.usrc.var = src->ptr;
|
|
return VALIDATE_OK;
|
|
} /* }}} */
|
|
|
|
static const char *
|
|
validate_v_i (Instruction * _this)
|
|
{ /* {{{ */
|
|
HashValue *dest = goom_hash_get (_this->vnamespace[1], _this->params[1]);
|
|
|
|
_this->data.usrc.value_int = strtol (_this->params[0], NULL, 0);
|
|
|
|
if (dest == NULL) {
|
|
return VALIDATE_NO_SUCH_INT;
|
|
}
|
|
_this->data.udest.var = dest->ptr;
|
|
return VALIDATE_OK;
|
|
} /* }}} */
|
|
|
|
static const char *
|
|
validate_v_p (Instruction * _this)
|
|
{ /* {{{ */
|
|
HashValue *dest = goom_hash_get (_this->vnamespace[1], _this->params[1]);
|
|
|
|
_this->data.usrc.value_ptr = strtol (_this->params[0], NULL, 0);
|
|
|
|
if (dest == NULL) {
|
|
return VALIDATE_NO_SUCH_INT;
|
|
}
|
|
_this->data.udest.var = dest->ptr;
|
|
return VALIDATE_OK;
|
|
} /* }}} */
|
|
|
|
static const char *
|
|
validate_v_f (Instruction * _this)
|
|
{ /* {{{ */
|
|
HashValue *dest = goom_hash_get (_this->vnamespace[1], _this->params[1]);
|
|
|
|
_this->data.usrc.value_float = atof (_this->params[0]);
|
|
|
|
if (dest == NULL) {
|
|
return VALIDATE_NO_SUCH_VAR;
|
|
}
|
|
_this->data.udest.var = dest->ptr;
|
|
return VALIDATE_OK;
|
|
} /* }}} */
|
|
|
|
static const char *
|
|
validate (Instruction * _this,
|
|
int vf_f_id, int vf_v_id,
|
|
int vi_i_id, int vi_v_id, int vp_p_id, int vp_v_id, int vs_v_id)
|
|
{ /* {{{ */
|
|
if ((_this->types[1] == TYPE_FVAR) && (_this->types[0] == TYPE_FLOAT)) {
|
|
_this->id = vf_f_id;
|
|
return validate_v_f (_this);
|
|
} else if ((_this->types[1] == TYPE_FVAR) && (_this->types[0] == TYPE_FVAR)) {
|
|
_this->id = vf_v_id;
|
|
return validate_v_v (_this);
|
|
} else if ((_this->types[1] == TYPE_IVAR)
|
|
&& (_this->types[0] == TYPE_INTEGER)) {
|
|
_this->id = vi_i_id;
|
|
return validate_v_i (_this);
|
|
} else if ((_this->types[1] == TYPE_IVAR) && (_this->types[0] == TYPE_IVAR)) {
|
|
_this->id = vi_v_id;
|
|
return validate_v_v (_this);
|
|
} else if ((_this->types[1] == TYPE_PVAR) && (_this->types[0] == TYPE_PTR)) {
|
|
if (vp_p_id == INSTR_NOP)
|
|
return VALIDATE_ERROR;
|
|
_this->id = vp_p_id;
|
|
return validate_v_p (_this);
|
|
} else if ((_this->types[1] == TYPE_PVAR) && (_this->types[0] == TYPE_PVAR)) {
|
|
_this->id = vp_v_id;
|
|
if (vp_v_id == INSTR_NOP)
|
|
return VALIDATE_ERROR;
|
|
return validate_v_v (_this);
|
|
} else if ((_this->types[1] < FIRST_RESERVED) && (_this->types[1] >= 0)
|
|
&& (_this->types[0] == _this->types[1])) {
|
|
_this->id = vs_v_id;
|
|
if (vs_v_id == INSTR_NOP)
|
|
return "Impossible operation to perform between two structs";
|
|
return validate_v_v (_this);
|
|
}
|
|
return VALIDATE_ERROR;
|
|
} /* }}} */
|
|
|
|
const char *
|
|
gsl_instr_validate (Instruction * _this)
|
|
{ /* {{{ */
|
|
if (_this->id != INSTR_EXT_CALL) {
|
|
int i = _this->nb_param;
|
|
|
|
while (i > 0) {
|
|
i--;
|
|
if (_this->types[i] == TYPE_VAR) {
|
|
int type = gsl_type_of_var (_this->vnamespace[i], _this->params[i]);
|
|
|
|
if (type == INSTR_INT)
|
|
_this->types[i] = TYPE_IVAR;
|
|
else if (type == INSTR_FLOAT)
|
|
_this->types[i] = TYPE_FVAR;
|
|
else if (type == INSTR_PTR)
|
|
_this->types[i] = TYPE_PVAR;
|
|
else if ((type >= 0) && (type < FIRST_RESERVED))
|
|
_this->types[i] = type;
|
|
else
|
|
fprintf (stderr, "WARNING: Line %d, %s has no namespace\n",
|
|
_this->line_number, _this->params[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
switch (_this->id) {
|
|
|
|
/* set */
|
|
case INSTR_SET:
|
|
return validate (_this,
|
|
INSTR_SETF_VAR_FLOAT, INSTR_SETF_VAR_VAR,
|
|
INSTR_SETI_VAR_INTEGER, INSTR_SETI_VAR_VAR,
|
|
INSTR_SETP_VAR_PTR, INSTR_SETP_VAR_VAR, INSTR_SETS_VAR_VAR);
|
|
|
|
/* extcall */
|
|
case INSTR_EXT_CALL:
|
|
if (_this->types[0] == TYPE_VAR) {
|
|
HashValue *fval =
|
|
goom_hash_get (_this->parent->functions, _this->params[0]);
|
|
if (fval) {
|
|
_this->data.udest.external_function =
|
|
(struct _ExternalFunctionStruct *) fval->ptr;
|
|
return VALIDATE_OK;
|
|
}
|
|
}
|
|
return VALIDATE_ERROR;
|
|
|
|
/* call */
|
|
case INSTR_CALL:
|
|
if (_this->types[0] == TYPE_LABEL) {
|
|
_this->jump_label = _this->params[0];
|
|
return VALIDATE_OK;
|
|
}
|
|
return VALIDATE_ERROR;
|
|
|
|
/* ret */
|
|
case INSTR_RET:
|
|
return VALIDATE_OK;
|
|
|
|
/* jump */
|
|
case INSTR_JUMP:
|
|
|
|
if (_this->types[0] == TYPE_LABEL) {
|
|
_this->jump_label = _this->params[0];
|
|
return VALIDATE_OK;
|
|
}
|
|
return VALIDATE_ERROR;
|
|
|
|
/* jzero / jnzero */
|
|
case INSTR_JZERO:
|
|
case INSTR_JNZERO:
|
|
|
|
if (_this->types[0] == TYPE_LABEL) {
|
|
_this->jump_label = _this->params[0];
|
|
return VALIDATE_OK;
|
|
}
|
|
return VALIDATE_ERROR;
|
|
|
|
/* label */
|
|
case INSTR_LABEL:
|
|
|
|
if (_this->types[0] == TYPE_LABEL) {
|
|
_this->id = INSTR_NOP;
|
|
_this->nop_label = _this->params[0];
|
|
goom_hash_put_int (_this->parent->iflow->labels, _this->params[0],
|
|
_this->parent->iflow->number);
|
|
return VALIDATE_OK;
|
|
}
|
|
return VALIDATE_ERROR;
|
|
|
|
/* isequal */
|
|
case INSTR_ISEQUAL:
|
|
return validate (_this,
|
|
INSTR_ISEQUALF_VAR_FLOAT, INSTR_ISEQUALF_VAR_VAR,
|
|
INSTR_ISEQUALI_VAR_INTEGER, INSTR_ISEQUALI_VAR_VAR,
|
|
INSTR_ISEQUALP_VAR_PTR, INSTR_ISEQUALP_VAR_VAR,
|
|
INSTR_ISEQUALS_VAR_VAR);
|
|
|
|
/* not */
|
|
case INSTR_NOT:
|
|
_this->id = INSTR_NOT_VAR;
|
|
return VALIDATE_OK;
|
|
|
|
/* islower */
|
|
case INSTR_ISLOWER:
|
|
return validate (_this,
|
|
INSTR_ISLOWERF_VAR_FLOAT, INSTR_ISLOWERF_VAR_VAR,
|
|
INSTR_ISLOWERI_VAR_INTEGER, INSTR_ISLOWERI_VAR_VAR,
|
|
INSTR_NOP, INSTR_NOP, INSTR_NOP);
|
|
|
|
/* add */
|
|
case INSTR_ADD:
|
|
return validate (_this,
|
|
INSTR_ADDF_VAR_FLOAT, INSTR_ADDF_VAR_VAR,
|
|
INSTR_ADDI_VAR_INTEGER, INSTR_ADDI_VAR_VAR,
|
|
INSTR_NOP, INSTR_NOP, INSTR_ADDS_VAR_VAR);
|
|
|
|
/* mul */
|
|
case INSTR_MUL:
|
|
return validate (_this,
|
|
INSTR_MULF_VAR_FLOAT, INSTR_MULF_VAR_VAR,
|
|
INSTR_MULI_VAR_INTEGER, INSTR_MULI_VAR_VAR,
|
|
INSTR_NOP, INSTR_NOP, INSTR_MULS_VAR_VAR);
|
|
|
|
/* sub */
|
|
case INSTR_SUB:
|
|
return validate (_this,
|
|
INSTR_SUBF_VAR_FLOAT, INSTR_SUBF_VAR_VAR,
|
|
INSTR_SUBI_VAR_INTEGER, INSTR_SUBI_VAR_VAR,
|
|
INSTR_NOP, INSTR_NOP, INSTR_SUBS_VAR_VAR);
|
|
|
|
/* div */
|
|
case INSTR_DIV:
|
|
return validate (_this,
|
|
INSTR_DIVF_VAR_FLOAT, INSTR_DIVF_VAR_VAR,
|
|
INSTR_DIVI_VAR_INTEGER, INSTR_DIVI_VAR_VAR,
|
|
INSTR_NOP, INSTR_NOP, INSTR_DIVS_VAR_VAR);
|
|
|
|
default:
|
|
return VALIDATE_TODO;
|
|
}
|
|
} /* }}} */
|
|
|
|
/*************/
|
|
/* EXECUTION */
|
|
/*************/
|
|
void
|
|
iflow_execute (FastInstructionFlow * _this, GoomSL * gsl)
|
|
{ /* {{{ */
|
|
int flag = 0;
|
|
int ip = 0;
|
|
FastInstruction *instr = _this->instr;
|
|
int stack[0x10000];
|
|
int stack_pointer = 0;
|
|
|
|
stack[stack_pointer++] = -1;
|
|
|
|
/* Quelques Macro pour rendre le code plus lisible */
|
|
#define pSRC_VAR instr[ip].data.usrc.var
|
|
#define SRC_VAR_INT *instr[ip].data.usrc.var_int
|
|
#define SRC_VAR_FLOAT *instr[ip].data.usrc.var_float
|
|
#define SRC_VAR_PTR *instr[ip].data.usrc.var_ptr
|
|
|
|
#define pDEST_VAR instr[ip].data.udest.var
|
|
#define DEST_VAR_INT *instr[ip].data.udest.var_int
|
|
#define DEST_VAR_FLOAT *instr[ip].data.udest.var_float
|
|
#define DEST_VAR_PTR *instr[ip].data.udest.var_ptr
|
|
|
|
#define VALUE_INT instr[ip].data.usrc.value_int
|
|
#define VALUE_FLOAT instr[ip].data.usrc.value_float
|
|
#define VALUE_PTR instr[ip].data.usrc.value_ptr
|
|
|
|
#define JUMP_OFFSET instr[ip].data.udest.jump_offset
|
|
|
|
#define SRC_STRUCT_ID instr[ip].data.usrc.var_int[-1]
|
|
#define DEST_STRUCT_ID instr[ip].data.udest.var_int[-1]
|
|
#define SRC_STRUCT_IBLOCK(i) gsl->gsl_struct[SRC_STRUCT_ID]->iBlock[i]
|
|
#define SRC_STRUCT_FBLOCK(i) gsl->gsl_struct[SRC_STRUCT_ID]->fBlock[i]
|
|
#define DEST_STRUCT_IBLOCK(i) gsl->gsl_struct[DEST_STRUCT_ID]->iBlock[i]
|
|
#define DEST_STRUCT_FBLOCK(i) gsl->gsl_struct[DEST_STRUCT_ID]->fBlock[i]
|
|
#define DEST_STRUCT_IBLOCK_VAR(i,j) \
|
|
((int*)((char*)pDEST_VAR + gsl->gsl_struct[DEST_STRUCT_ID]->iBlock[i].data))[j]
|
|
#define DEST_STRUCT_FBLOCK_VAR(i,j) \
|
|
((float*)((char*)pDEST_VAR + gsl->gsl_struct[DEST_STRUCT_ID]->fBlock[i].data))[j]
|
|
#define SRC_STRUCT_IBLOCK_VAR(i,j) \
|
|
((int*)((char*)pSRC_VAR + gsl->gsl_struct[SRC_STRUCT_ID]->iBlock[i].data))[j]
|
|
#define SRC_STRUCT_FBLOCK_VAR(i,j) \
|
|
((float*)((char*)pSRC_VAR + gsl->gsl_struct[SRC_STRUCT_ID]->fBlock[i].data))[j]
|
|
#define DEST_STRUCT_SIZE gsl->gsl_struct[DEST_STRUCT_ID]->size
|
|
|
|
while (1) {
|
|
int i;
|
|
|
|
#ifdef TRACE_SCRIPT
|
|
printf ("execute ");
|
|
gsl_instr_display (instr[ip].proto);
|
|
printf ("\n");
|
|
#endif
|
|
switch (instr[ip].id) {
|
|
|
|
/* SET.I */
|
|
case INSTR_SETI_VAR_INTEGER:
|
|
DEST_VAR_INT = VALUE_INT;
|
|
++ip;
|
|
break;
|
|
|
|
case INSTR_SETI_VAR_VAR:
|
|
DEST_VAR_INT = SRC_VAR_INT;
|
|
++ip;
|
|
break;
|
|
|
|
/* SET.F */
|
|
case INSTR_SETF_VAR_FLOAT:
|
|
DEST_VAR_FLOAT = VALUE_FLOAT;
|
|
++ip;
|
|
break;
|
|
|
|
case INSTR_SETF_VAR_VAR:
|
|
DEST_VAR_FLOAT = SRC_VAR_FLOAT;
|
|
++ip;
|
|
break;
|
|
|
|
/* SET.P */
|
|
case INSTR_SETP_VAR_VAR:
|
|
DEST_VAR_PTR = SRC_VAR_PTR;
|
|
++ip;
|
|
break;
|
|
|
|
case INSTR_SETP_VAR_PTR:
|
|
DEST_VAR_PTR = VALUE_PTR;
|
|
++ip;
|
|
break;
|
|
|
|
/* JUMP */
|
|
case INSTR_JUMP:
|
|
ip += JUMP_OFFSET;
|
|
break;
|
|
|
|
/* JZERO */
|
|
case INSTR_JZERO:
|
|
ip += (flag ? 1 : JUMP_OFFSET);
|
|
break;
|
|
|
|
case INSTR_NOP:
|
|
++ip;
|
|
break;
|
|
|
|
/* ISEQUAL.P */
|
|
case INSTR_ISEQUALP_VAR_VAR:
|
|
flag = (DEST_VAR_PTR == SRC_VAR_PTR);
|
|
++ip;
|
|
break;
|
|
|
|
case INSTR_ISEQUALP_VAR_PTR:
|
|
flag = (DEST_VAR_PTR == VALUE_PTR);
|
|
++ip;
|
|
break;
|
|
|
|
/* ISEQUAL.I */
|
|
case INSTR_ISEQUALI_VAR_VAR:
|
|
flag = (DEST_VAR_INT == SRC_VAR_INT);
|
|
++ip;
|
|
break;
|
|
|
|
case INSTR_ISEQUALI_VAR_INTEGER:
|
|
flag = (DEST_VAR_INT == VALUE_INT);
|
|
++ip;
|
|
break;
|
|
|
|
/* ISEQUAL.F */
|
|
case INSTR_ISEQUALF_VAR_VAR:
|
|
flag = (DEST_VAR_FLOAT == SRC_VAR_FLOAT);
|
|
++ip;
|
|
break;
|
|
|
|
case INSTR_ISEQUALF_VAR_FLOAT:
|
|
flag = (DEST_VAR_FLOAT == VALUE_FLOAT);
|
|
++ip;
|
|
break;
|
|
|
|
/* ISLOWER.I */
|
|
case INSTR_ISLOWERI_VAR_VAR:
|
|
flag = (DEST_VAR_INT < SRC_VAR_INT);
|
|
++ip;
|
|
break;
|
|
|
|
case INSTR_ISLOWERI_VAR_INTEGER:
|
|
flag = (DEST_VAR_INT < VALUE_INT);
|
|
++ip;
|
|
break;
|
|
|
|
/* ISLOWER.F */
|
|
case INSTR_ISLOWERF_VAR_VAR:
|
|
flag = (DEST_VAR_FLOAT < SRC_VAR_FLOAT);
|
|
++ip;
|
|
break;
|
|
|
|
case INSTR_ISLOWERF_VAR_FLOAT:
|
|
flag = (DEST_VAR_FLOAT < VALUE_FLOAT);
|
|
++ip;
|
|
break;
|
|
|
|
/* ADD.I */
|
|
case INSTR_ADDI_VAR_VAR:
|
|
DEST_VAR_INT += SRC_VAR_INT;
|
|
++ip;
|
|
break;
|
|
|
|
case INSTR_ADDI_VAR_INTEGER:
|
|
DEST_VAR_INT += VALUE_INT;
|
|
++ip;
|
|
break;
|
|
|
|
/* ADD.F */
|
|
case INSTR_ADDF_VAR_VAR:
|
|
DEST_VAR_FLOAT += SRC_VAR_FLOAT;
|
|
++ip;
|
|
break;
|
|
|
|
case INSTR_ADDF_VAR_FLOAT:
|
|
DEST_VAR_FLOAT += VALUE_FLOAT;
|
|
++ip;
|
|
break;
|
|
|
|
/* MUL.I */
|
|
case INSTR_MULI_VAR_VAR:
|
|
DEST_VAR_INT *= SRC_VAR_INT;
|
|
++ip;
|
|
break;
|
|
|
|
case INSTR_MULI_VAR_INTEGER:
|
|
DEST_VAR_INT *= VALUE_INT;
|
|
++ip;
|
|
break;
|
|
|
|
/* MUL.F */
|
|
case INSTR_MULF_VAR_FLOAT:
|
|
DEST_VAR_FLOAT *= VALUE_FLOAT;
|
|
++ip;
|
|
break;
|
|
|
|
case INSTR_MULF_VAR_VAR:
|
|
DEST_VAR_FLOAT *= SRC_VAR_FLOAT;
|
|
++ip;
|
|
break;
|
|
|
|
/* DIV.I */
|
|
case INSTR_DIVI_VAR_VAR:
|
|
DEST_VAR_INT /= SRC_VAR_INT;
|
|
++ip;
|
|
break;
|
|
|
|
case INSTR_DIVI_VAR_INTEGER:
|
|
DEST_VAR_INT /= VALUE_INT;
|
|
++ip;
|
|
break;
|
|
|
|
/* DIV.F */
|
|
case INSTR_DIVF_VAR_FLOAT:
|
|
DEST_VAR_FLOAT /= VALUE_FLOAT;
|
|
++ip;
|
|
break;
|
|
|
|
case INSTR_DIVF_VAR_VAR:
|
|
DEST_VAR_FLOAT /= SRC_VAR_FLOAT;
|
|
++ip;
|
|
break;
|
|
|
|
/* SUB.I */
|
|
case INSTR_SUBI_VAR_VAR:
|
|
DEST_VAR_INT -= SRC_VAR_INT;
|
|
++ip;
|
|
break;
|
|
|
|
case INSTR_SUBI_VAR_INTEGER:
|
|
DEST_VAR_INT -= VALUE_INT;
|
|
++ip;
|
|
break;
|
|
|
|
/* SUB.F */
|
|
case INSTR_SUBF_VAR_FLOAT:
|
|
DEST_VAR_FLOAT -= VALUE_FLOAT;
|
|
++ip;
|
|
break;
|
|
|
|
case INSTR_SUBF_VAR_VAR:
|
|
DEST_VAR_FLOAT -= SRC_VAR_FLOAT;
|
|
++ip;
|
|
break;
|
|
|
|
/* CALL */
|
|
case INSTR_CALL:
|
|
stack[stack_pointer++] = ip + 1;
|
|
ip += JUMP_OFFSET;
|
|
break;
|
|
|
|
/* RET */
|
|
case INSTR_RET:
|
|
ip = stack[--stack_pointer];
|
|
if (ip < 0)
|
|
return;
|
|
break;
|
|
|
|
/* EXT_CALL */
|
|
case INSTR_EXT_CALL:
|
|
instr[ip].data.udest.external_function->function (gsl, gsl->vars,
|
|
instr[ip].data.udest.external_function->vars);
|
|
++ip;
|
|
break;
|
|
|
|
/* NOT */
|
|
case INSTR_NOT_VAR:
|
|
flag = !flag;
|
|
++ip;
|
|
break;
|
|
|
|
/* JNZERO */
|
|
case INSTR_JNZERO:
|
|
ip += (flag ? JUMP_OFFSET : 1);
|
|
break;
|
|
|
|
case INSTR_SETS_VAR_VAR:
|
|
memcpy (pDEST_VAR, pSRC_VAR, DEST_STRUCT_SIZE);
|
|
++ip;
|
|
break;
|
|
|
|
case INSTR_ISEQUALS_VAR_VAR:
|
|
break;
|
|
|
|
case INSTR_ADDS_VAR_VAR:
|
|
/* process integers */
|
|
i = 0;
|
|
while (DEST_STRUCT_IBLOCK (i).size > 0) {
|
|
int j = DEST_STRUCT_IBLOCK (i).size;
|
|
|
|
while (j--) {
|
|
DEST_STRUCT_IBLOCK_VAR (i, j) += SRC_STRUCT_IBLOCK_VAR (i, j);
|
|
}
|
|
++i;
|
|
}
|
|
/* process floats */
|
|
i = 0;
|
|
while (DEST_STRUCT_FBLOCK (i).size > 0) {
|
|
int j = DEST_STRUCT_FBLOCK (i).size;
|
|
|
|
while (j--) {
|
|
DEST_STRUCT_FBLOCK_VAR (i, j) += SRC_STRUCT_FBLOCK_VAR (i, j);
|
|
}
|
|
++i;
|
|
}
|
|
++ip;
|
|
break;
|
|
|
|
case INSTR_SUBS_VAR_VAR:
|
|
/* process integers */
|
|
i = 0;
|
|
while (DEST_STRUCT_IBLOCK (i).size > 0) {
|
|
int j = DEST_STRUCT_IBLOCK (i).size;
|
|
|
|
while (j--) {
|
|
DEST_STRUCT_IBLOCK_VAR (i, j) -= SRC_STRUCT_IBLOCK_VAR (i, j);
|
|
}
|
|
++i;
|
|
}
|
|
/* process floats */
|
|
i = 0;
|
|
while (DEST_STRUCT_FBLOCK (i).size > 0) {
|
|
int j = DEST_STRUCT_FBLOCK (i).size;
|
|
|
|
while (j--) {
|
|
DEST_STRUCT_FBLOCK_VAR (i, j) -= SRC_STRUCT_FBLOCK_VAR (i, j);
|
|
}
|
|
++i;
|
|
}
|
|
++ip;
|
|
break;
|
|
|
|
case INSTR_MULS_VAR_VAR:
|
|
/* process integers */
|
|
i = 0;
|
|
while (DEST_STRUCT_IBLOCK (i).size > 0) {
|
|
int j = DEST_STRUCT_IBLOCK (i).size;
|
|
|
|
while (j--) {
|
|
DEST_STRUCT_IBLOCK_VAR (i, j) *= SRC_STRUCT_IBLOCK_VAR (i, j);
|
|
}
|
|
++i;
|
|
}
|
|
/* process floats */
|
|
i = 0;
|
|
while (DEST_STRUCT_FBLOCK (i).size > 0) {
|
|
int j = DEST_STRUCT_FBLOCK (i).size;
|
|
|
|
while (j--) {
|
|
DEST_STRUCT_FBLOCK_VAR (i, j) *= SRC_STRUCT_FBLOCK_VAR (i, j);
|
|
}
|
|
++i;
|
|
}
|
|
++ip;
|
|
break;
|
|
|
|
case INSTR_DIVS_VAR_VAR:
|
|
/* process integers */
|
|
i = 0;
|
|
while (DEST_STRUCT_IBLOCK (i).size > 0) {
|
|
int j = DEST_STRUCT_IBLOCK (i).size;
|
|
|
|
while (j--) {
|
|
DEST_STRUCT_IBLOCK_VAR (i, j) /= SRC_STRUCT_IBLOCK_VAR (i, j);
|
|
}
|
|
++i;
|
|
}
|
|
/* process floats */
|
|
i = 0;
|
|
while (DEST_STRUCT_FBLOCK (i).size > 0) {
|
|
int j = DEST_STRUCT_FBLOCK (i).size;
|
|
|
|
while (j--) {
|
|
DEST_STRUCT_FBLOCK_VAR (i, j) /= SRC_STRUCT_FBLOCK_VAR (i, j);
|
|
}
|
|
++i;
|
|
}
|
|
++ip;
|
|
break;
|
|
|
|
default:
|
|
printf ("NOT IMPLEMENTED : %d\n", instr[ip].id);
|
|
++ip;
|
|
exit (1);
|
|
}
|
|
}
|
|
} /* }}} */
|
|
|
|
int
|
|
gsl_malloc (GoomSL * _this, int size)
|
|
{ /* {{{ */
|
|
if (_this->nbPtr >= _this->ptrArraySize) {
|
|
_this->ptrArraySize *= 2;
|
|
_this->ptrArray =
|
|
(void **) realloc (_this->ptrArray,
|
|
sizeof (void *) * _this->ptrArraySize);
|
|
}
|
|
_this->ptrArray[_this->nbPtr] = malloc (size);
|
|
return _this->nbPtr++;
|
|
} /* }}} */
|
|
|
|
void *
|
|
gsl_get_ptr (GoomSL * _this, int id)
|
|
{ /* {{{ */
|
|
if ((id >= 0) && (id < _this->nbPtr))
|
|
return _this->ptrArray[id];
|
|
fprintf (stderr, "INVALID GET PTR 0x%08x\n", id);
|
|
return NULL;
|
|
} /* }}} */
|
|
|
|
void
|
|
gsl_free_ptr (GoomSL * _this, int id)
|
|
{ /* {{{ */
|
|
if ((id >= 0) && (id < _this->nbPtr)) {
|
|
free (_this->ptrArray[id]);
|
|
_this->ptrArray[id] = 0;
|
|
}
|
|
} /* }}} */
|
|
|
|
void
|
|
gsl_enternamespace (const char *name)
|
|
{ /* {{{ */
|
|
HashValue *val = goom_hash_get (currentGoomSL->functions, name);
|
|
|
|
if (val) {
|
|
ExternalFunctionStruct *function = (ExternalFunctionStruct *) val->ptr;
|
|
|
|
currentGoomSL->currentNS++;
|
|
currentGoomSL->namespaces[currentGoomSL->currentNS] = function->vars;
|
|
} else {
|
|
fprintf (stderr, "ERROR: Line %d, Could not find namespace: %s\n",
|
|
currentGoomSL->num_lines, name);
|
|
exit (1);
|
|
}
|
|
} /* }}} */
|
|
|
|
void
|
|
gsl_reenternamespace (GoomHash * nsinfo)
|
|
{
|
|
currentGoomSL->currentNS++;
|
|
currentGoomSL->namespaces[currentGoomSL->currentNS] = nsinfo;
|
|
}
|
|
|
|
GoomHash *
|
|
gsl_leavenamespace (void)
|
|
{ /* {{{ */
|
|
currentGoomSL->currentNS--;
|
|
return currentGoomSL->namespaces[currentGoomSL->currentNS + 1];
|
|
} /* }}} */
|
|
|
|
GoomHash *
|
|
gsl_find_namespace (const char *name)
|
|
{ /* {{{ */
|
|
int i;
|
|
|
|
for (i = currentGoomSL->currentNS; i >= 0; --i) {
|
|
if (goom_hash_get (currentGoomSL->namespaces[i], name))
|
|
return currentGoomSL->namespaces[i];
|
|
}
|
|
return NULL;
|
|
} /* }}} */
|
|
|
|
void
|
|
gsl_declare_task (const char *name)
|
|
{ /* {{{ */
|
|
if (goom_hash_get (currentGoomSL->functions, name)) {
|
|
return;
|
|
} else {
|
|
ExternalFunctionStruct *gef =
|
|
(ExternalFunctionStruct *) malloc (sizeof (ExternalFunctionStruct));
|
|
gef->function = 0;
|
|
gef->vars = goom_hash_new ();
|
|
gef->is_extern = 0;
|
|
goom_hash_put_ptr (currentGoomSL->functions, name, (void *) gef);
|
|
}
|
|
} /* }}} */
|
|
|
|
void
|
|
gsl_declare_external_task (const char *name)
|
|
{ /* {{{ */
|
|
if (goom_hash_get (currentGoomSL->functions, name)) {
|
|
fprintf (stderr, "ERROR: Line %d, Duplicate declaration of %s\n",
|
|
currentGoomSL->num_lines, name);
|
|
return;
|
|
} else {
|
|
ExternalFunctionStruct *gef =
|
|
(ExternalFunctionStruct *) malloc (sizeof (ExternalFunctionStruct));
|
|
gef->function = 0;
|
|
gef->vars = goom_hash_new ();
|
|
gef->is_extern = 1;
|
|
goom_hash_put_ptr (currentGoomSL->functions, name, (void *) gef);
|
|
}
|
|
} /* }}} */
|
|
|
|
static void
|
|
reset_scanner (GoomSL * gss)
|
|
{ /* {{{ */
|
|
gss->num_lines = 0;
|
|
gss->instr = NULL;
|
|
iflow_clean (gss->iflow);
|
|
|
|
/* reset variables */
|
|
goom_hash_free (gss->vars);
|
|
gss->vars = goom_hash_new ();
|
|
gss->currentNS = 0;
|
|
gss->namespaces[0] = gss->vars;
|
|
|
|
goom_hash_free (gss->structIDS);
|
|
gss->structIDS = goom_hash_new ();
|
|
|
|
while (gss->nbStructID > 0) {
|
|
int i;
|
|
|
|
gss->nbStructID--;
|
|
for (i = 0; i < gss->gsl_struct[gss->nbStructID]->nbFields; ++i)
|
|
free (gss->gsl_struct[gss->nbStructID]->fields[i]);
|
|
free (gss->gsl_struct[gss->nbStructID]);
|
|
}
|
|
|
|
gss->compilationOK = 1;
|
|
|
|
goom_heap_delete (gss->data_heap);
|
|
gss->data_heap = goom_heap_new ();
|
|
} /* }}} */
|
|
|
|
static void
|
|
calculate_labels (InstructionFlow * iflow)
|
|
{ /* {{{ */
|
|
int i = 0;
|
|
|
|
while (i < iflow->number) {
|
|
Instruction *instr = iflow->instr[i];
|
|
|
|
if (instr->jump_label) {
|
|
HashValue *label = goom_hash_get (iflow->labels, instr->jump_label);
|
|
|
|
if (label) {
|
|
instr->data.udest.jump_offset = -instr->address + label->i;
|
|
} else {
|
|
fprintf (stderr, "ERROR: Line %d, Could not find label %s\n",
|
|
instr->line_number, instr->jump_label);
|
|
instr->id = INSTR_NOP;
|
|
instr->nop_label = 0;
|
|
exit (1);
|
|
}
|
|
}
|
|
++i;
|
|
}
|
|
} /* }}} */
|
|
|
|
#ifdef USE_JITC_X86
|
|
static int
|
|
powerOfTwo (int i)
|
|
{
|
|
int b;
|
|
|
|
for (b = 0; b < 31; b++)
|
|
if (i == (1 << b))
|
|
return b;
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
/* Cree un flow d'instruction optimise */
|
|
static void
|
|
gsl_create_fast_iflow (void)
|
|
{ /* {{{ */
|
|
int number = currentGoomSL->iflow->number;
|
|
int i;
|
|
|
|
#ifdef USE_JITC_X86
|
|
|
|
/* pour compatibilite avec les MACROS servant a execution */
|
|
int ip = 0;
|
|
GoomSL *gsl = currentGoomSL;
|
|
|
|
JitcX86Env *jitc;
|
|
|
|
if (currentGoomSL->jitc != NULL)
|
|
jitc_x86_delete (currentGoomSL->jitc);
|
|
jitc = currentGoomSL->jitc = jitc_x86_env_new (0xffff);
|
|
currentGoomSL->jitc_func = jitc_prepare_func (jitc);
|
|
|
|
#if 0
|
|
#define SRC_STRUCT_ID instr[ip].data.usrc.var_int[-1]
|
|
#define DEST_STRUCT_ID instr[ip].data.udest.var_int[-1]
|
|
#define SRC_STRUCT_IBLOCK(i) gsl->gsl_struct[SRC_STRUCT_ID]->iBlock[i]
|
|
#define SRC_STRUCT_FBLOCK(i) gsl->gsl_struct[SRC_STRUCT_ID]->fBlock[i]
|
|
#define DEST_STRUCT_IBLOCK(i) gsl->gsl_struct[DEST_STRUCT_ID]->iBlock[i]
|
|
#define DEST_STRUCT_FBLOCK(i) gsl->gsl_struct[DEST_STRUCT_ID]->fBlock[i]
|
|
#define DEST_STRUCT_IBLOCK_VAR(i,j) \
|
|
((int*)((char*)pDEST_VAR + gsl->gsl_struct[DEST_STRUCT_ID]->iBlock[i].data))[j]
|
|
#define DEST_STRUCT_FBLOCK_VAR(i,j) \
|
|
((float*)((char*)pDEST_VAR + gsl->gsl_struct[DEST_STRUCT_ID]->fBlock[i].data))[j]
|
|
#define SRC_STRUCT_IBLOCK_VAR(i,j) \
|
|
((int*)((char*)pSRC_VAR + gsl->gsl_struct[SRC_STRUCT_ID]->iBlock[i].data))[j]
|
|
#define SRC_STRUCT_FBLOCK_VAR(i,j) \
|
|
((float*)((char*)pSRC_VAR + gsl->gsl_struct[SRC_STRUCT_ID]->fBlock[i].data))[j]
|
|
#define DEST_STRUCT_SIZE gsl->gsl_struct[DEST_STRUCT_ID]->size
|
|
#endif
|
|
|
|
JITC_JUMP_LABEL (jitc, "__very_end__");
|
|
JITC_ADD_LABEL (jitc, "__very_start__");
|
|
|
|
for (i = 0; i < number; ++i) {
|
|
Instruction *instr = currentGoomSL->iflow->instr[i];
|
|
|
|
switch (instr->id) {
|
|
case INSTR_SETI_VAR_INTEGER:
|
|
jitc_add (jitc, "mov [$d], $d", instr->data.udest.var_int,
|
|
instr->data.usrc.value_int);
|
|
break;
|
|
case INSTR_SETI_VAR_VAR:
|
|
jitc_add (jitc, "mov eax, [$d]", instr->data.usrc.var_int);
|
|
jitc_add (jitc, "mov [$d], eax", instr->data.udest.var_int);
|
|
break;
|
|
/* SET.F */
|
|
case INSTR_SETF_VAR_FLOAT:
|
|
jitc_add (jitc, "mov [$d], $d", instr->data.udest.var_float,
|
|
*(int *) (&instr->data.usrc.value_float));
|
|
break;
|
|
case INSTR_SETF_VAR_VAR:
|
|
jitc_add (jitc, "mov eax, [$d]", instr->data.usrc.var_float);
|
|
jitc_add (jitc, "mov [$d], eax", instr->data.udest.var_float);
|
|
break;
|
|
case INSTR_NOP:
|
|
if (instr->nop_label != 0)
|
|
JITC_ADD_LABEL (jitc, instr->nop_label);
|
|
break;
|
|
case INSTR_JUMP:
|
|
JITC_JUMP_LABEL (jitc, instr->jump_label);
|
|
break;
|
|
case INSTR_SETP_VAR_PTR:
|
|
jitc_add (jitc, "mov [$d], $d", instr->data.udest.var_ptr,
|
|
instr->data.usrc.value_ptr);
|
|
break;
|
|
case INSTR_SETP_VAR_VAR:
|
|
jitc_add (jitc, "mov eax, [$d]", instr->data.usrc.var_ptr);
|
|
jitc_add (jitc, "mov [$d], eax", instr->data.udest.var_ptr);
|
|
break;
|
|
case INSTR_SUBI_VAR_INTEGER:
|
|
jitc_add (jitc, "add [$d], $d", instr->data.udest.var_int,
|
|
-instr->data.usrc.value_int);
|
|
break;
|
|
case INSTR_SUBI_VAR_VAR:
|
|
jitc_add (jitc, "mov eax, [$d]", instr->data.udest.var_int);
|
|
jitc_add (jitc, "sub eax, [$d]", instr->data.usrc.var_int);
|
|
jitc_add (jitc, "mov [$d], eax", instr->data.udest.var_int);
|
|
break;
|
|
case INSTR_SUBF_VAR_FLOAT:
|
|
printf ("NOT IMPLEMENTED : %d\n", instr->id);
|
|
break;
|
|
case INSTR_SUBF_VAR_VAR:
|
|
printf ("NOT IMPLEMENTED : %d\n", instr->id);
|
|
break;
|
|
case INSTR_ISLOWERF_VAR_VAR:
|
|
printf ("NOT IMPLEMENTED : %d\n", instr->id);
|
|
break;
|
|
case INSTR_ISLOWERF_VAR_FLOAT:
|
|
printf ("NOT IMPLEMENTED : %d\n", instr->id);
|
|
break;
|
|
case INSTR_ISLOWERI_VAR_VAR:
|
|
jitc_add (jitc, "mov edx, [$d]", instr->data.udest.var_int);
|
|
jitc_add (jitc, "sub edx, [$d]", instr->data.usrc.var_int);
|
|
jitc_add (jitc, "shr edx, $d", 31);
|
|
break;
|
|
case INSTR_ISLOWERI_VAR_INTEGER:
|
|
jitc_add (jitc, "mov edx, [$d]", instr->data.udest.var_int);
|
|
jitc_add (jitc, "sub edx, $d", instr->data.usrc.value_int);
|
|
jitc_add (jitc, "shr edx, $d", 31);
|
|
break;
|
|
case INSTR_ADDI_VAR_INTEGER:
|
|
jitc_add (jitc, "add [$d], $d", instr->data.udest.var_int,
|
|
instr->data.usrc.value_int);
|
|
break;
|
|
case INSTR_ADDI_VAR_VAR:
|
|
jitc_add (jitc, "mov eax, [$d]", instr->data.udest.var_int);
|
|
jitc_add (jitc, "add eax, [$d]", instr->data.usrc.var_int);
|
|
jitc_add (jitc, "mov [$d], eax", instr->data.udest.var_int);
|
|
break;
|
|
case INSTR_ADDF_VAR_FLOAT:
|
|
printf ("NOT IMPLEMENTED : %d\n", instr->id);
|
|
break;
|
|
case INSTR_ADDF_VAR_VAR:
|
|
printf ("NOT IMPLEMENTED : %d\n", instr->id);
|
|
break;
|
|
case INSTR_MULI_VAR_INTEGER:
|
|
if (instr->data.usrc.value_int != 1) {
|
|
int po2 = powerOfTwo (instr->data.usrc.value_int);
|
|
|
|
if (po2) {
|
|
/* performs (V / 2^n) by doing V >> n */
|
|
jitc_add (jitc, "mov eax, [$d]", instr->data.udest.var_int);
|
|
jitc_add (jitc, "sal eax, $d", po2);
|
|
jitc_add (jitc, "mov [$d], eax", instr->data.udest.var_int);
|
|
} else {
|
|
jitc_add (jitc, "mov eax, [$d]", instr->data.udest.var_int);
|
|
jitc_add (jitc, "imul eax, $d", instr->data.usrc.value_int);
|
|
jitc_add (jitc, "mov [$d], eax", instr->data.udest.var_int);
|
|
}
|
|
}
|
|
break;
|
|
case INSTR_MULI_VAR_VAR:
|
|
jitc_add (jitc, "mov eax, [$d]", instr->data.udest.var_int);
|
|
jitc_add (jitc, "imul eax, [$d]", instr->data.usrc.var_int);
|
|
jitc_add (jitc, "mov [$d], eax", instr->data.udest.var_int);
|
|
break;
|
|
case INSTR_MULF_VAR_FLOAT:
|
|
printf ("NOT IMPLEMENTED : %d\n", instr->id);
|
|
break;
|
|
case INSTR_MULF_VAR_VAR:
|
|
printf ("NOT IMPLEMENTED : %d\n", instr->id);
|
|
break;
|
|
case INSTR_DIVI_VAR_INTEGER:
|
|
if ((instr->data.usrc.value_int != 1)
|
|
&& (instr->data.usrc.value_int != 0)) {
|
|
int po2 = powerOfTwo (instr->data.usrc.value_int);
|
|
|
|
if (po2) {
|
|
/* performs (V / 2^n) by doing V >> n */
|
|
jitc_add (jitc, "mov eax, [$d]", instr->data.udest.var_int);
|
|
jitc_add (jitc, "sar eax, $d", po2);
|
|
jitc_add (jitc, "mov [$d], eax", instr->data.udest.var_int);
|
|
} else {
|
|
/* performs (V/n) by doing (V*(32^2/n)) */
|
|
long coef;
|
|
double dcoef =
|
|
(double) 4294967296.0 / (double) instr->data.usrc.value_int;
|
|
if (dcoef < 0.0)
|
|
dcoef = -dcoef;
|
|
coef = (long) floor (dcoef);
|
|
dcoef -= floor (dcoef);
|
|
if (dcoef < 0.5)
|
|
coef += 1;
|
|
|
|
jitc_add (jitc, "mov eax, [$d]", instr->data.udest.var_int);
|
|
jitc_add (jitc, "mov edx, $d", coef);
|
|
jitc_add (jitc, "imul edx");
|
|
if (instr->data.usrc.value_int < 0)
|
|
jitc_add (jitc, "neg edx");
|
|
jitc_add (jitc, "mov [$d], edx", instr->data.udest.var_int);
|
|
}
|
|
}
|
|
break;
|
|
case INSTR_DIVI_VAR_VAR:
|
|
jitc_add (jitc, "mov eax, [$d]", instr->data.udest.var_int);
|
|
jitc_add (jitc, "cdq"); /* sign extend eax into edx */
|
|
jitc_add (jitc, "idiv [$d]", instr->data.usrc.var_int);
|
|
jitc_add (jitc, "mov [$d], eax", instr->data.udest.var_int);
|
|
break;
|
|
case INSTR_DIVF_VAR_FLOAT:
|
|
printf ("NOT IMPLEMENTED : %d\n", instr->id);
|
|
break;
|
|
case INSTR_DIVF_VAR_VAR:
|
|
printf ("NOT IMPLEMENTED : %d\n", instr->id);
|
|
break;
|
|
case INSTR_JZERO:
|
|
jitc_add (jitc, "cmp edx, $d", 0);
|
|
jitc_add (jitc, "je $s", instr->jump_label);
|
|
break;
|
|
case INSTR_ISEQUALP_VAR_VAR:
|
|
jitc_add (jitc, "mov eax, [$d]", instr->data.udest.var_ptr);
|
|
jitc_add (jitc, "mov edx, $d", 0);
|
|
jitc_add (jitc, "cmp eax, [$d]", instr->data.usrc.var_ptr);
|
|
jitc_add (jitc, "jne $d", 1);
|
|
jitc_add (jitc, "inc edx");
|
|
break;
|
|
case INSTR_ISEQUALP_VAR_PTR:
|
|
jitc_add (jitc, "mov eax, [$d]", instr->data.udest.var_ptr);
|
|
jitc_add (jitc, "mov edx, $d", 0);
|
|
jitc_add (jitc, "cmp eax, $d", instr->data.usrc.value_ptr);
|
|
jitc_add (jitc, "jne $d", 1);
|
|
jitc_add (jitc, "inc edx");
|
|
break;
|
|
case INSTR_ISEQUALI_VAR_VAR:
|
|
jitc_add (jitc, "mov eax, [$d]", instr->data.udest.var_int);
|
|
jitc_add (jitc, "mov edx, $d", 0);
|
|
jitc_add (jitc, "cmp eax, [$d]", instr->data.usrc.var_int);
|
|
jitc_add (jitc, "jne $d", 1);
|
|
jitc_add (jitc, "inc edx");
|
|
break;
|
|
case INSTR_ISEQUALI_VAR_INTEGER:
|
|
jitc_add (jitc, "mov eax, [$d]", instr->data.udest.var_int);
|
|
jitc_add (jitc, "mov edx, $d", 0);
|
|
jitc_add (jitc, "cmp eax, $d", instr->data.usrc.value_int);
|
|
jitc_add (jitc, "jne $d", 1);
|
|
jitc_add (jitc, "inc edx");
|
|
break;
|
|
case INSTR_ISEQUALF_VAR_VAR:
|
|
printf ("NOT IMPLEMENTED : %d\n", instr->id);
|
|
break;
|
|
case INSTR_ISEQUALF_VAR_FLOAT:
|
|
printf ("NOT IMPLEMENTED : %d\n", instr->id);
|
|
break;
|
|
case INSTR_CALL:
|
|
jitc_add (jitc, "call $s", instr->jump_label);
|
|
break;
|
|
case INSTR_RET:
|
|
jitc_add (jitc, "ret");
|
|
break;
|
|
case INSTR_EXT_CALL:
|
|
jitc_add (jitc, "mov eax, [$d]",
|
|
&(instr->data.udest.external_function->vars));
|
|
jitc_add (jitc, "push eax");
|
|
jitc_add (jitc, "mov edx, [$d]", &(currentGoomSL->vars));
|
|
jitc_add (jitc, "push edx");
|
|
jitc_add (jitc, "mov eax, [$d]", &(currentGoomSL));
|
|
jitc_add (jitc, "push eax");
|
|
|
|
jitc_add (jitc, "mov eax, [$d]",
|
|
&(instr->data.udest.external_function));
|
|
jitc_add (jitc, "mov eax, [eax]");
|
|
jitc_add (jitc, "call [eax]");
|
|
jitc_add (jitc, "add esp, $d", 12);
|
|
break;
|
|
case INSTR_NOT_VAR:
|
|
jitc_add (jitc, "mov eax, edx");
|
|
jitc_add (jitc, "mov edx, $d", 1);
|
|
jitc_add (jitc, "sub edx, eax");
|
|
break;
|
|
case INSTR_JNZERO:
|
|
jitc_add (jitc, "cmp edx, $d", 0);
|
|
jitc_add (jitc, "jne $s", instr->jump_label);
|
|
break;
|
|
case INSTR_SETS_VAR_VAR:
|
|
{
|
|
int loop = DEST_STRUCT_SIZE / sizeof (int);
|
|
int dst = (int) pDEST_VAR;
|
|
int src = (int) pSRC_VAR;
|
|
|
|
while (loop--) {
|
|
jitc_add (jitc, "mov eax, [$d]", src);
|
|
jitc_add (jitc, "mov [$d], eax", dst);
|
|
src += 4;
|
|
dst += 4;
|
|
}
|
|
}
|
|
break;
|
|
case INSTR_ISEQUALS_VAR_VAR:
|
|
break;
|
|
case INSTR_ADDS_VAR_VAR:
|
|
{
|
|
/* process integers */
|
|
int i = 0;
|
|
|
|
while (DEST_STRUCT_IBLOCK (i).size > 0) {
|
|
int j = DEST_STRUCT_IBLOCK (i).size;
|
|
|
|
while (j--) { /* TODO interlace 2 */
|
|
jitc_add (jitc, "mov eax, [$d]", &DEST_STRUCT_IBLOCK_VAR (i, j));
|
|
jitc_add (jitc, "add eax, [$d]", &SRC_STRUCT_IBLOCK_VAR (i, j));
|
|
jitc_add (jitc, "mov [$d], eax", &DEST_STRUCT_IBLOCK_VAR (i, j));
|
|
}
|
|
++i;
|
|
}
|
|
/* process floats */
|
|
i = 0;
|
|
while (DEST_STRUCT_FBLOCK (i).size > 0) {
|
|
int j = DEST_STRUCT_FBLOCK (i).size;
|
|
|
|
while (j--) {
|
|
/* DEST_STRUCT_FBLOCK_VAR(i,j) += SRC_STRUCT_FBLOCK_VAR(i,j); */
|
|
/* TODO */
|
|
}
|
|
++i;
|
|
}
|
|
break;
|
|
}
|
|
case INSTR_SUBS_VAR_VAR:
|
|
{
|
|
/* process integers */
|
|
int i = 0;
|
|
|
|
while (DEST_STRUCT_IBLOCK (i).size > 0) {
|
|
int j = DEST_STRUCT_IBLOCK (i).size;
|
|
|
|
while (j--) {
|
|
jitc_add (jitc, "mov eax, [$d]", &DEST_STRUCT_IBLOCK_VAR (i, j));
|
|
jitc_add (jitc, "sub eax, [$d]", &SRC_STRUCT_IBLOCK_VAR (i, j));
|
|
jitc_add (jitc, "mov [$d], eax", &DEST_STRUCT_IBLOCK_VAR (i, j));
|
|
}
|
|
++i;
|
|
}
|
|
break;
|
|
}
|
|
case INSTR_MULS_VAR_VAR:
|
|
{
|
|
/* process integers */
|
|
int i = 0;
|
|
|
|
while (DEST_STRUCT_IBLOCK (i).size > 0) {
|
|
int j = DEST_STRUCT_IBLOCK (i).size;
|
|
|
|
while (j--) {
|
|
jitc_add (jitc, "mov eax, [$d]", &DEST_STRUCT_IBLOCK_VAR (i, j));
|
|
jitc_add (jitc, "imul eax, [$d]", &SRC_STRUCT_IBLOCK_VAR (i, j));
|
|
jitc_add (jitc, "mov [$d], eax", &DEST_STRUCT_IBLOCK_VAR (i, j));
|
|
}
|
|
++i;
|
|
}
|
|
break;
|
|
}
|
|
case INSTR_DIVS_VAR_VAR:
|
|
{
|
|
/* process integers */
|
|
int i = 0;
|
|
|
|
while (DEST_STRUCT_IBLOCK (i).size > 0) {
|
|
int j = DEST_STRUCT_IBLOCK (i).size;
|
|
|
|
while (j--) {
|
|
jitc_add (jitc, "mov eax, [$d]", &DEST_STRUCT_IBLOCK_VAR (i, j));
|
|
jitc_add (jitc, "cdq");
|
|
jitc_add (jitc, "idiv [$d]", &SRC_STRUCT_IBLOCK_VAR (i, j));
|
|
jitc_add (jitc, "mov [$d], eax", &DEST_STRUCT_IBLOCK_VAR (i, j));
|
|
}
|
|
++i;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
JITC_ADD_LABEL (jitc, "__very_end__");
|
|
jitc_add (jitc, "call $s", "__very_start__");
|
|
jitc_add (jitc, "mov eax, $d", 0);
|
|
jitc_validate_func (jitc);
|
|
#else
|
|
InstructionFlow *iflow = currentGoomSL->iflow;
|
|
FastInstructionFlow *fastiflow =
|
|
(FastInstructionFlow *) malloc (sizeof (FastInstructionFlow));
|
|
fastiflow->mallocedInstr = calloc (number * 16, sizeof (FastInstruction));
|
|
/* fastiflow->instr = (FastInstruction*)(((int)fastiflow->mallocedInstr) + 16 - (((int)fastiflow->mallocedInstr)%16)); */
|
|
fastiflow->instr = (FastInstruction *) fastiflow->mallocedInstr;
|
|
fastiflow->number = number;
|
|
for (i = 0; i < number; ++i) {
|
|
fastiflow->instr[i].id = iflow->instr[i]->id;
|
|
fastiflow->instr[i].data = iflow->instr[i]->data;
|
|
fastiflow->instr[i].proto = iflow->instr[i];
|
|
}
|
|
currentGoomSL->fastiflow = fastiflow;
|
|
#endif
|
|
} /* }}} */
|
|
|
|
void yy_scan_string (const char *str);
|
|
void yyparse (void);
|
|
|
|
GoomHash *
|
|
gsl_globals (GoomSL * _this)
|
|
{
|
|
return _this->vars;
|
|
}
|
|
|
|
|
|
/**
|
|
* Some native external functions
|
|
*/
|
|
static void
|
|
ext_charAt (GoomSL * gsl, GoomHash * global, GoomHash * local)
|
|
{
|
|
char *string = GSL_LOCAL_PTR (gsl, local, "value");
|
|
int index = GSL_LOCAL_INT (gsl, local, "index");
|
|
|
|
GSL_GLOBAL_INT (gsl, "charAt") = 0;
|
|
if (string == NULL) {
|
|
return;
|
|
}
|
|
if (index < strlen (string))
|
|
GSL_GLOBAL_INT (gsl, "charAt") = string[index];
|
|
}
|
|
|
|
static void
|
|
ext_i2f (GoomSL * gsl, GoomHash * global, GoomHash * local)
|
|
{
|
|
int i = GSL_LOCAL_INT (gsl, local, "value");
|
|
|
|
GSL_GLOBAL_FLOAT (gsl, "i2f") = i;
|
|
}
|
|
|
|
static void
|
|
ext_f2i (GoomSL * gsl, GoomHash * global, GoomHash * local)
|
|
{
|
|
float f = GSL_LOCAL_FLOAT (gsl, local, "value");
|
|
|
|
GSL_GLOBAL_INT (gsl, "f2i") = f;
|
|
}
|
|
|
|
/**
|
|
*
|
|
*/
|
|
void
|
|
gsl_compile (GoomSL * _currentGoomSL, const char *script)
|
|
{ /* {{{ */
|
|
char *script_and_externals;
|
|
static const char *sBinds =
|
|
"external <charAt: string value, int index> : int\n"
|
|
"external <f2i: float value> : int\n"
|
|
"external <i2f: int value> : float\n";
|
|
|
|
#ifdef VERBOSE
|
|
printf ("\n=== Starting Compilation ===\n");
|
|
#endif
|
|
|
|
script_and_externals = malloc (strlen (script) + strlen (sBinds) + 2);
|
|
strcpy (script_and_externals, sBinds);
|
|
strcat (script_and_externals, script);
|
|
|
|
/* 0- reset */
|
|
currentGoomSL = _currentGoomSL;
|
|
reset_scanner (currentGoomSL);
|
|
|
|
/* 1- create the syntaxic tree */
|
|
yy_scan_string (script_and_externals);
|
|
yyparse ();
|
|
|
|
/* 2- generate code */
|
|
gsl_commit_compilation ();
|
|
|
|
/* 3- resolve symbols */
|
|
calculate_labels (currentGoomSL->iflow);
|
|
|
|
/* 4- optimize code */
|
|
gsl_create_fast_iflow ();
|
|
|
|
/* 5- bind a few internal functions */
|
|
gsl_bind_function (currentGoomSL, "charAt", ext_charAt);
|
|
gsl_bind_function (currentGoomSL, "f2i", ext_f2i);
|
|
gsl_bind_function (currentGoomSL, "i2f", ext_i2f);
|
|
free (script_and_externals);
|
|
|
|
#ifdef VERBOSE
|
|
printf ("=== Compilation done. # of lines: %d. # of instr: %d ===\n",
|
|
currentGoomSL->num_lines, currentGoomSL->iflow->number);
|
|
#endif
|
|
} /* }}} */
|
|
|
|
void
|
|
gsl_execute (GoomSL * scanner)
|
|
{ /* {{{ */
|
|
if (scanner->compilationOK) {
|
|
#if USE_JITC_X86
|
|
scanner->jitc_func ();
|
|
#else
|
|
iflow_execute (scanner->fastiflow, scanner);
|
|
#endif
|
|
}
|
|
} /* }}} */
|
|
|
|
GoomSL *
|
|
gsl_new (void)
|
|
{ /* {{{ */
|
|
GoomSL *gss = (GoomSL *) malloc (sizeof (GoomSL));
|
|
|
|
gss->iflow = iflow_new ();
|
|
gss->vars = goom_hash_new ();
|
|
gss->functions = goom_hash_new ();
|
|
gss->nbStructID = 0;
|
|
gss->structIDS = goom_hash_new ();
|
|
gss->gsl_struct_size = 32;
|
|
gss->gsl_struct =
|
|
(GSL_Struct **) malloc (gss->gsl_struct_size * sizeof (GSL_Struct *));
|
|
gss->currentNS = 0;
|
|
gss->namespaces[0] = gss->vars;
|
|
gss->data_heap = goom_heap_new ();
|
|
|
|
reset_scanner (gss);
|
|
|
|
gss->compilationOK = 0;
|
|
gss->nbPtr = 0;
|
|
gss->ptrArraySize = 256;
|
|
gss->ptrArray = (void **) malloc (gss->ptrArraySize * sizeof (void *));
|
|
#ifdef USE_JITC_X86
|
|
gss->jitc = NULL;
|
|
#endif
|
|
return gss;
|
|
} /* }}} */
|
|
|
|
void
|
|
gsl_bind_function (GoomSL * gss, const char *fname,
|
|
GoomSL_ExternalFunction func)
|
|
{ /* {{{ */
|
|
HashValue *val = goom_hash_get (gss->functions, fname);
|
|
|
|
if (val) {
|
|
ExternalFunctionStruct *gef = (ExternalFunctionStruct *) val->ptr;
|
|
|
|
gef->function = func;
|
|
} else
|
|
fprintf (stderr, "Unable to bind function %s\n", fname);
|
|
} /* }}} */
|
|
|
|
int
|
|
gsl_is_compiled (GoomSL * gss)
|
|
{ /* {{{ */
|
|
return gss->compilationOK;
|
|
} /* }}} */
|
|
|
|
void
|
|
gsl_free (GoomSL * gss)
|
|
{ /* {{{ */
|
|
iflow_free (gss->iflow);
|
|
free (gss->vars);
|
|
free (gss->functions);
|
|
free (gss);
|
|
} /* }}} */
|
|
|
|
|
|
static int gsl_nb_import;
|
|
static char gsl_already_imported[256][256];
|
|
|
|
char *
|
|
gsl_init_buffer (const char *fname)
|
|
{
|
|
char *fbuffer;
|
|
|
|
fbuffer = (char *) malloc (512);
|
|
fbuffer[0] = 0;
|
|
gsl_nb_import = 0;
|
|
if (fname)
|
|
gsl_append_file_to_buffer (fname, &fbuffer);
|
|
return fbuffer;
|
|
}
|
|
|
|
static char *
|
|
gsl_read_file (const char *fname)
|
|
{
|
|
FILE *f;
|
|
char *buffer;
|
|
int fsize;
|
|
|
|
f = fopen (fname, "rt");
|
|
if (!f) {
|
|
fprintf (stderr, "ERROR: Could not load file %s\n", fname);
|
|
exit (1);
|
|
}
|
|
fseek (f, 0, SEEK_END);
|
|
fsize = ftell (f);
|
|
rewind (f);
|
|
buffer = (char *) malloc (fsize + 512);
|
|
if (fread (buffer, 1, fsize, f) != fsize) {
|
|
buffer[0] = '\0';
|
|
}
|
|
fclose (f);
|
|
buffer[fsize] = 0;
|
|
return buffer;
|
|
}
|
|
|
|
void
|
|
gsl_append_file_to_buffer (const char *fname, char **buffer)
|
|
{
|
|
char *fbuffer;
|
|
int size, fsize, i = 0;
|
|
char reset_msg[256];
|
|
|
|
/* look if the file have not been already imported */
|
|
for (i = 0; i < gsl_nb_import; ++i) {
|
|
if (strcmp (gsl_already_imported[i], fname) == 0)
|
|
return;
|
|
}
|
|
|
|
/* add fname to the already imported files. */
|
|
strcpy (gsl_already_imported[gsl_nb_import++], fname);
|
|
|
|
/* load the file */
|
|
fbuffer = gsl_read_file (fname);
|
|
fsize = strlen (fbuffer);
|
|
|
|
/* look for #import */
|
|
while (fbuffer[i]) {
|
|
if ((fbuffer[i] == '#') && (fbuffer[i + 1] == 'i')) {
|
|
char impName[256];
|
|
int j;
|
|
|
|
while (fbuffer[i] && (fbuffer[i] != ' '))
|
|
i++;
|
|
i++;
|
|
j = 0;
|
|
while (fbuffer[i] && (fbuffer[i] != '\n'))
|
|
impName[j++] = fbuffer[i++];
|
|
impName[j++] = 0;
|
|
gsl_append_file_to_buffer (impName, buffer);
|
|
}
|
|
i++;
|
|
}
|
|
|
|
sprintf (reset_msg, "\n#FILE %s#\n#RST_LINE#\n", fname);
|
|
strcat (*buffer, reset_msg);
|
|
size = strlen (*buffer);
|
|
*buffer = (char *) realloc (*buffer, size + fsize + 256);
|
|
strcat ((*buffer) + size, fbuffer);
|
|
free (fbuffer);
|
|
}
|