gambas-source-code/main/gbc/gbc_jit.c
gambas 23be942b6a Work continues on the new JIT system.
[BENCHMARKS]
* NEW: Little meaningless changes.

[INTERPRETER]
* NEW: JIT: Support for FOR EACH loops.
* BUG: JIT: Handle function values that are put on stack before calling them.

[COMPILER]
* NEW: JIT: Optimization of mathematic functions.
* NEW: JIT: Support for FOR EACH loops.
* NEW: JIT: Remove successive POP_x() / PUSH_x().
* NEW: JIT: Optimization of DIV and MOD.
* NEW: JIT: Support of internal control local variables used by SELECT and FOR EACH.
* NEW: JIT: Support for SWAP.

[GB.JIT]
* NEW: Optimization of mathematic functions.
* NEW: Variants management.
* NEW: All conversions are handled now.
* NEW: FOR EACH loops are implemented.
2018-06-05 11:43:39 +02:00

365 lines
7.1 KiB
C

/***************************************************************************
gbc_jit.c
(c) 2000-2018 Benoît Minisini <g4mba5@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301, USA.
***************************************************************************/
#define __GBC_JIT_C
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <errno.h>
#include "gb_file.h"
#include "gb_str.h"
#include "gb_error.h"
#include "gbc_compile.h"
#include "gbc_chown.h"
#include "gbc_class.h"
#include "gbc_jit.h"
typedef
struct {
const char *name;
char type;
}
CLASS_TYPE;
char *JIT_prefix;
static FILE *_file = NULL;
static const CLASS_TYPE _class_type[] = {
{ "Boolean[]", T_BOOLEAN },
{ "Byte[]", T_BYTE },
{ "Short[]", T_SHORT },
{ "Integer[]", T_INTEGER },
{ "Long[]", T_LONG },
{ "Single[]", T_SINGLE },
{ "Float[]", T_FLOAT },
{ "Date[]", T_DATE },
{ "String[]", T_STRING },
{ "Pointer[]", T_POINTER },
{ "Object[]", T_OBJECT },
{ "Variant[]", T_VARIANT },
{ NULL, 0 }
};
static const char *_type_name[] =
{
"V" , "b", "c", "h", "i", "l", "g", "f",
"d", "s", "t", "p", "v", "A", "S", "n",
"o", "u", "C"
};
static const char *_gtype_name[] =
{
"GB_T_VOID" , "GB_T_BOOLEAN", "GB_T_BYTE", "GB_T_SHORT", "GB_T_INTEGER", "GB_T_LONG", "GB_T_SINGLE", "GB_T_FLOAT",
"GB_T_DATE", "GB_T_CSTRING", "GB_T_STRING", "GB_T_POINTER", "GB_T_VARIANT", "?", "?", "?",
"GB_T_OBJECT"
};
static const char *_ctype_name[] =
{
"void" , "char", "uchar", "short", "int", "int64_t", "float", "double",
"GB_DATE", "GB_STRING", "GB_STRING", "intptr_t", "GB_VARIANT", "?", "?", "?",
"GB_OBJECT", "GB_VALUE", "?"
};
const char *JIT_get_type(TYPE type)
{
int index = TYPE_get_id(type);
//if (index <= 0 || index > 18) THROW("Unknown type");
return _type_name[index];
}
const char *JIT_get_gtype(TYPE type)
{
return _gtype_name[TYPE_get_id(type)];
}
const char *JIT_get_ctype(TYPE type)
{
return _ctype_name[TYPE_get_id(type)];
}
static TYPE get_array_type(SYMBOL *sym)
{
const CLASS_TYPE *p;
for(p = _class_type; p->name; p++)
{
if (SYMBOL_compare_ignore_case(sym, p->name) == 0)
return TYPE_make_simple(p->type);
}
return (TYPE)0;
}
void JIT_begin(bool has_fast)
{
const char *path;
int i;
CLASS_REF *cr;
SYMBOL *sym;
JIT_prefix = STR_lower(JOB->class->name);
path = FILE_cat(".jit", JIT_prefix, NULL);
path = FILE_set_ext(path, "c");
if (!has_fast)
{
FILE_unlink(path);
return;
}
if (mkdir(".jit", 0777) == 0)
FILE_set_owner(".jit", COMP_project);
_file = fopen(path, "w");
if (!_file)
THROW("Cannot create file: &1", path);
// detect classes for optimizations
for (i = 0; i < ARRAY_count(JOB->class->class); i++)
{
cr = &JOB->class->class[i];
if (!TYPE_is_null(cr->type))
continue;
sym = (SYMBOL *)CLASS_get_symbol(JOB->class, cr->index);
if (SYMBOL_compare_ignore_case(sym, "Collection") == 0)
{
cr->is_collection = TRUE;
continue;
}
cr->type = get_array_type(sym);
}
}
void JIT_end(void)
{
STR_free(JIT_prefix);
if (_file)
{
fclose(_file);
_file = NULL;
}
}
static void declare_implementation(FUNCTION *func, int index)
{
int i;
int nopt;
int opt;
JIT_print("static %s jit_%s_%d_(", JIT_get_ctype(func->type), JIT_prefix, index);
for (i = 0; i < func->npmin; i++)
{
if (i) JIT_print(", ");
JIT_print("%s p%d", JIT_get_ctype(func->param[i].type), i);
}
if (i < func->nparam)
{
opt = nopt = 0;
for (; i < func->nparam; i++)
{
if (nopt == 0)
{
JIT_print(", uchar _o%d", opt);
opt++;
}
JIT_print(", %s p%d", JIT_get_ctype(func->param[i].type), i);
nopt++;
if (nopt >= 8)
nopt = 0;
}
}
JIT_print(")");
}
void JIT_declare_func(FUNCTION *func, int index)
{
JIT_print("void jit_%s_%d(uchar n);\n", JIT_prefix, index);
declare_implementation(func, index);
JIT_print(";\n");
}
void JIT_translate_func(FUNCTION *func, int index)
{
const char *fname = TABLE_get_symbol_name(JOB->class->table, func->name);
int i;
TYPE type;
int nopt;
JIT_section(fname);
JIT_print("void jit_%s_%d(uchar n)\n{\n", JIT_prefix, index);
if (func->nparam)
JIT_print(" VALUE *sp = *(JIT.sp);\n");
JIT_print(" ");
if (!TYPE_is_void(func->type))
JIT_print("RETURN_%s(", JIT_get_type(func->type));
JIT_print("jit_%s_%d_(", JIT_prefix, index);
for (i = 0; i < func->npmin; i++)
{
if (i) JIT_print(", ");
JIT_print("PARAM_%s(%d)", JIT_get_type(func->param[i].type), i);
}
if (i < func->nparam)
{
nopt = 0;
for (; i < func->nparam; i++)
{
if (nopt == 0)
JIT_print(", OPT(%d,%d)", i, Min(func->nparam, i + 8) - i);
JIT_print(", PARAM_OPT_%s(%d)", JIT_get_type(func->param[i].type), i);
nopt++;
if (nopt >= 8)
nopt == 0;
}
}
if (func->vararg)
THROW("Not supported");
if (!TYPE_is_void(func->type))
JIT_print(")");
JIT_print(");\n");
JIT_print("}\n\n");
declare_implementation(func, index);
JIT_print("\n{\n");
for (i = -1; i < func->nlocal; i++)
{
if (i < 0)
{
if (TYPE_is_void(func->type))
continue;
type = func->type;
JIT_print(" %s r = ", JIT_get_ctype(type));
}
else
{
type = func->local[func->nparam + i].type;
JIT_print(" %s l%d = ", JIT_get_ctype(type), i);
}
switch(TYPE_get_id(type))
{
case T_DATE: JIT_print("{GB_T_DATE}"); break;
case T_STRING: JIT_print("{GB_T_STRING}"); break;
case T_OBJECT: JIT_print("{GB_T_NULL}"); break;
case T_VARIANT: JIT_print("{GB_T_VARIANT,{GB_T_NULL}}"); break;
default: JIT_print("0");
}
JIT_print(";\n");
}
if (func->nlocal)
JIT_print("\n");
JIT_translate_body(func, index);
if (func->nlocal)
{
for (i = 0; i < func->nlocal; i++)
{
type = func->local[func->nparam + i].type;
switch(TYPE_get_id(type))
{
case T_STRING:
case T_OBJECT:
case T_VARIANT:
JIT_print(" RELEASE_FAST_%s(l%d);\n", JIT_get_type(type), i);
break;
}
}
}
if (!TYPE_is_void(func->type))
{
switch(TYPE_get_id(func->type))
{
case T_STRING:
case T_OBJECT:
case T_VARIANT:
JIT_print(" JIT.unborrow((GB_VALUE *)&r);\n");
break;
}
JIT_print(" return r;\n");
}
else
JIT_print(" return;\n");
JIT_print("}\n");
}
void JIT_vprint(const char *str, va_list args)
{
vprintf(str, args);
}
void JIT_print(const char *str, ...)
{
va_list args;
va_list copy;
va_start(args, str);
if (JOB->verbose)
{
va_copy(copy, args);
vprintf(str, copy);
va_end(copy);
}
vfprintf(_file, str, args);
va_end(args);
}
void JIT_section(const char *str)
{
JIT_print("\n// %s\n\n", str);
}