Merging master and adapting _MEM_* on new mem-vector functions

This commit is contained in:
Wolfgang Bumiller 2012-07-27 19:13:03 +02:00
commit f8b3081c44
7 changed files with 734 additions and 182 deletions

270
ast.c
View file

@ -57,12 +57,18 @@ static void ast_expression_init(ast_expression *self,
self->expression.codegen = codegen; self->expression.codegen = codegen;
self->expression.vtype = TYPE_VOID; self->expression.vtype = TYPE_VOID;
self->expression.next = NULL; self->expression.next = NULL;
MEM_VECTOR_INIT(&self->expression, params);
} }
static void ast_expression_delete(ast_expression *self) static void ast_expression_delete(ast_expression *self)
{ {
size_t i;
if (self->expression.next) if (self->expression.next)
ast_delete(self->expression.next); ast_delete(self->expression.next);
for (i = 0; i < self->expression.params_count; ++i) {
ast_delete(self->expression.params[i]);
}
MEM_VECTOR_CLEAR(&self->expression, params);
} }
static void ast_expression_delete_full(ast_expression *self) static void ast_expression_delete_full(ast_expression *self)
@ -71,9 +77,26 @@ static void ast_expression_delete_full(ast_expression *self)
mem_d(self); mem_d(self);
} }
MEM_VEC_FUNCTIONS(ast_expression_common, ast_value*, params)
static ast_expression* ast_type_copy(lex_ctx ctx, const ast_expression *ex);
static ast_value* ast_value_copy(const ast_value *self)
{
ast_value *cp = ast_value_new(self->expression.node.context, self->name, self->expression.vtype);
if (self->expression.next) {
cp->expression.next = ast_type_copy(self->expression.node.context, self->expression.next);
if (!cp->expression.next) {
ast_value_delete(cp);
return NULL;
}
}
return cp;
}
static ast_expression* ast_type_copy(lex_ctx ctx, const ast_expression *ex) static ast_expression* ast_type_copy(lex_ctx ctx, const ast_expression *ex)
{ {
const ast_expression_common *cpex; size_t i;
const ast_expression_common *fromex;
ast_expression_common *selfex; ast_expression_common *selfex;
if (!ex) if (!ex)
@ -82,23 +105,32 @@ static ast_expression* ast_type_copy(lex_ctx ctx, const ast_expression *ex)
{ {
ast_instantiate(ast_expression, ctx, ast_expression_delete_full); ast_instantiate(ast_expression, ctx, ast_expression_delete_full);
cpex = &ex->expression; fromex = &ex->expression;
selfex = &self->expression; selfex = &self->expression;
selfex->vtype = cpex->vtype; /* This may never be codegen()d */
if (cpex->next) selfex->codegen = NULL;
selfex->vtype = fromex->vtype;
if (fromex->next)
{ {
selfex->next = ast_type_copy(ctx, cpex->next); selfex->next = ast_type_copy(ctx, fromex->next);
if (!selfex->next) { if (!selfex->next) {
mem_d(self); ast_expression_delete_full(self);
return NULL; return NULL;
} }
} }
else else
selfex->next = NULL; selfex->next = NULL;
/* This may never be codegen()d */ for (i = 0; i < fromex->params_count; ++i) {
selfex->codegen = NULL; ast_value *v = ast_value_copy(fromex->params[i]);
if (!v || !ast_expression_common_params_add(selfex, v)) {
ast_expression_delete_full(self);
return NULL;
}
}
return self; return self;
} }
} }
@ -113,7 +145,6 @@ ast_value* ast_value_new(lex_ctx ctx, const char *name, int t)
self->name = name ? util_strdup(name) : NULL; self->name = name ? util_strdup(name) : NULL;
self->expression.vtype = t; self->expression.vtype = t;
self->expression.next = NULL; self->expression.next = NULL;
MEM_VECTOR_INIT(self, params);
self->isconst = false; self->isconst = false;
memset(&self->constval, 0, sizeof(self->constval)); memset(&self->constval, 0, sizeof(self->constval));
@ -121,16 +152,11 @@ ast_value* ast_value_new(lex_ctx ctx, const char *name, int t)
return self; return self;
} }
MEM_VEC_FUNCTIONS(ast_value, ast_value*, params)
void ast_value_delete(ast_value* self) void ast_value_delete(ast_value* self)
{ {
size_t i;
if (self->name) if (self->name)
mem_d((void*)self->name); mem_d((void*)self->name);
for (i = 0; i < self->params_count; ++i)
ast_value_delete(self->params[i]); /* delete, the ast_function is expected to die first */
MEM_VECTOR_CLEAR(self, params);
if (self->isconst) { if (self->isconst) {
switch (self->expression.vtype) switch (self->expression.vtype)
{ {
@ -152,6 +178,11 @@ void ast_value_delete(ast_value* self)
mem_d(self); mem_d(self);
} }
bool GMQCC_WARN ast_value_params_add(ast_value *self, ast_value *p)
{
return ast_expression_common_params_add(&self->expression, p);
}
bool ast_value_set_name(ast_value *self, const char *name) bool ast_value_set_name(ast_value *self, const char *name)
{ {
if (self->name) if (self->name)
@ -181,6 +212,42 @@ void ast_binary_delete(ast_binary *self)
mem_d(self); mem_d(self);
} }
ast_unary* ast_unary_new(lex_ctx ctx, int op,
ast_expression *expr)
{
ast_instantiate(ast_unary, ctx, ast_unary_delete);
ast_expression_init((ast_expression*)self, (ast_expression_codegen*)&ast_unary_codegen);
self->op = op;
self->operand = expr;
return self;
}
void ast_unary_delete(ast_unary *self)
{
ast_unref(self->operand);
ast_expression_delete((ast_expression*)self);
mem_d(self);
}
ast_return* ast_return_new(lex_ctx ctx, ast_expression *expr)
{
ast_instantiate(ast_return, ctx, ast_return_delete);
ast_expression_init((ast_expression*)self, (ast_expression_codegen*)&ast_return_codegen);
self->operand = expr;
return self;
}
void ast_return_delete(ast_return *self)
{
ast_unref(self->operand);
ast_expression_delete((ast_expression*)self);
mem_d(self);
}
ast_entfield* ast_entfield_new(lex_ctx ctx, ast_expression *entity, ast_expression *field) ast_entfield* ast_entfield_new(lex_ctx ctx, ast_expression *entity, ast_expression *field)
{ {
const ast_expression *outtype; const ast_expression *outtype;
@ -308,6 +375,34 @@ void ast_loop_delete(ast_loop *self)
mem_d(self); mem_d(self);
} }
ast_call* ast_call_new(lex_ctx ctx,
ast_expression *funcexpr)
{
ast_instantiate(ast_call, ctx, ast_call_delete);
ast_expression_init((ast_expression*)self, (ast_expression_codegen*)&ast_call_codegen);
MEM_VECTOR_INIT(self, params);
self->func = funcexpr;
return self;
}
MEM_VEC_FUNCTIONS(ast_call, ast_expression*, params)
void ast_call_delete(ast_call *self)
{
size_t i;
for (i = 0; i < self->params_count; ++i)
ast_unref(self->params[i]);
MEM_VECTOR_CLEAR(self, params);
if (self->func)
ast_unref(self->func);
ast_expression_delete((ast_expression*)self);
mem_d(self);
}
ast_store* ast_store_new(lex_ctx ctx, int op, ast_store* ast_store_new(lex_ctx ctx, int op,
ast_value *dest, ast_expression *source) ast_value *dest, ast_expression *source)
{ {
@ -356,6 +451,19 @@ void ast_block_delete(ast_block *self)
mem_d(self); mem_d(self);
} }
bool ast_block_set_type(ast_block *self, ast_expression *from)
{
if (self->expression.next)
ast_delete(self->expression.next);
self->expression.vtype = from->expression.vtype;
if (from->expression.next) {
self->expression.next = ast_type_copy(self->expression.node.context, from->expression.next);
if (!self->expression.next)
return false;
}
return true;
}
ast_function* ast_function_new(lex_ctx ctx, const char *name, ast_value *vtype) ast_function* ast_function_new(lex_ctx ctx, const char *name, ast_value *vtype)
{ {
ast_instantiate(ast_function, ctx, ast_function_delete); ast_instantiate(ast_function, ctx, ast_function_delete);
@ -373,6 +481,7 @@ ast_function* ast_function_new(lex_ctx ctx, const char *name, ast_value *vtype)
MEM_VECTOR_INIT(self, blocks); MEM_VECTOR_INIT(self, blocks);
self->labelcount = 0; self->labelcount = 0;
self->builtin = 0;
self->ir_func = NULL; self->ir_func = NULL;
self->curblock = NULL; self->curblock = NULL;
@ -457,8 +566,10 @@ bool ast_value_codegen(ast_value *self, ast_function *func, bool lvalue, ir_valu
* and the ast-user should take care of ast_global_codegen to be used * and the ast-user should take care of ast_global_codegen to be used
* on all the globals. * on all the globals.
*/ */
if (!self->ir_v) if (!self->ir_v) {
printf("ast_value used before generated (%s)\n", self->name);
return false; return false;
}
*out = self->ir_v; *out = self->ir_v;
return true; return true;
} }
@ -468,11 +579,12 @@ bool ast_global_codegen(ast_value *self, ir_builder *ir)
ir_value *v = NULL; ir_value *v = NULL;
if (self->isconst && self->expression.vtype == TYPE_FUNCTION) if (self->isconst && self->expression.vtype == TYPE_FUNCTION)
{ {
ir_function *func = ir_builder_create_function(ir, self->name); ir_function *func = ir_builder_create_function(ir, self->name, self->expression.next->expression.vtype);
if (!func) if (!func)
return false; return false;
self->constval.vfunc->ir_func = func; self->constval.vfunc->ir_func = func;
self->ir_v = func->value;
/* The function is filled later on ast_function_codegen... */ /* The function is filled later on ast_function_codegen... */
return true; return true;
} }
@ -497,10 +609,11 @@ bool ast_global_codegen(ast_value *self, ir_builder *ir)
goto error; goto error;
break; break;
case TYPE_FUNCTION: case TYPE_FUNCTION:
printf("global of type function not properly generated\n");
goto error;
/* Cannot generate an IR value for a function, /* Cannot generate an IR value for a function,
* need a pointer pointing to a function rather. * need a pointer pointing to a function rather.
*/ */
goto error;
default: default:
printf("TODO: global constant type %i\n", self->expression.vtype); printf("TODO: global constant type %i\n", self->expression.vtype);
break; break;
@ -516,7 +629,7 @@ error: /* clean up */
return false; return false;
} }
bool ast_local_codegen(ast_value *self, ir_function *func) bool ast_local_codegen(ast_value *self, ir_function *func, bool param)
{ {
ir_value *v = NULL; ir_value *v = NULL;
if (self->isconst && self->expression.vtype == TYPE_FUNCTION) if (self->isconst && self->expression.vtype == TYPE_FUNCTION)
@ -527,7 +640,7 @@ bool ast_local_codegen(ast_value *self, ir_function *func)
return false; return false;
} }
v = ir_function_create_local(func, self->name, self->expression.vtype); v = ir_function_create_local(func, self->name, self->expression.vtype, param);
if (!v) if (!v)
return false; return false;
@ -568,6 +681,7 @@ bool ast_function_codegen(ast_function *self, ir_builder *ir)
{ {
ir_function *irf; ir_function *irf;
ir_value *dummy; ir_value *dummy;
ast_expression_common *ec;
size_t i; size_t i;
irf = self->ir_func; irf = self->ir_func;
@ -576,6 +690,23 @@ bool ast_function_codegen(ast_function *self, ir_builder *ir)
return false; return false;
} }
/* fill the parameter list */
ec = &self->vtype->expression;
for (i = 0; i < ec->params_count; ++i)
{
if (!ir_function_params_add(irf, ec->params[i]->expression.vtype))
return false;
if (!self->builtin) {
if (!ast_local_codegen(ec->params[i], self->ir_func, true))
return false;
}
}
if (self->builtin) {
irf->builtin = self->builtin;
return true;
}
self->curblock = ir_function_create_block(irf, "entry"); self->curblock = ir_function_create_block(irf, "entry");
if (!self->curblock) if (!self->curblock)
return false; return false;
@ -591,7 +722,9 @@ bool ast_function_codegen(ast_function *self, ir_builder *ir)
{ {
if (!self->vtype->expression.next || if (!self->vtype->expression.next ||
self->vtype->expression.next->expression.vtype == TYPE_VOID) self->vtype->expression.next->expression.vtype == TYPE_VOID)
{
return ir_block_create_return(self->curblock, NULL); return ir_block_create_return(self->curblock, NULL);
}
else else
{ {
/* error("missing return"); */ /* error("missing return"); */
@ -628,7 +761,7 @@ bool ast_block_codegen(ast_block *self, ast_function *func, bool lvalue, ir_valu
/* generate locals */ /* generate locals */
for (i = 0; i < self->locals_count; ++i) for (i = 0; i < self->locals_count; ++i)
{ {
if (!ast_local_codegen(self->locals[i], func->ir_func)) if (!ast_local_codegen(self->locals[i], func->ir_func, false))
return false; return false;
} }
@ -700,6 +833,50 @@ bool ast_binary_codegen(ast_binary *self, ast_function *func, bool lvalue, ir_va
return true; return true;
} }
bool ast_unary_codegen(ast_unary *self, ast_function *func, bool lvalue, ir_value **out)
{
ast_expression_codegen *cgen;
ir_value *operand;
/* In the context of a unary operation, we can disregard
* the lvalue flag.
*/
(void)lvalue;
cgen = self->operand->expression.codegen;
/* lvalue! */
if (!(*cgen)((ast_expression*)(self->operand), func, false, &operand))
return false;
*out = ir_block_create_unary(func->curblock, ast_function_label(func, "unary"),
self->op, operand);
if (!*out)
return false;
return true;
}
bool ast_return_codegen(ast_return *self, ast_function *func, bool lvalue, ir_value **out)
{
ast_expression_codegen *cgen;
ir_value *operand;
/* In the context of a return operation, we can disregard
* the lvalue flag.
*/
(void)lvalue;
cgen = self->operand->expression.codegen;
/* lvalue! */
if (!(*cgen)((ast_expression*)(self->operand), func, false, &operand))
return false;
if (!ir_block_create_return(func->curblock, operand))
return false;
return true;
}
bool ast_entfield_codegen(ast_entfield *self, ast_function *func, bool lvalue, ir_value **out) bool ast_entfield_codegen(ast_entfield *self, ast_function *func, bool lvalue, ir_value **out)
{ {
ast_expression_codegen *cgen; ast_expression_codegen *cgen;
@ -1148,3 +1325,56 @@ bool ast_loop_codegen(ast_loop *self, ast_function *func, bool lvalue, ir_value
return true; return true;
} }
bool ast_call_codegen(ast_call *self, ast_function *func, bool lvalue, ir_value **out)
{
ast_expression_codegen *cgen;
ir_value_vector params;
ir_instr *callinstr;
size_t i;
ir_value *funval = NULL;
/* return values are never rvalues */
(void)lvalue;
cgen = self->func->expression.codegen;
if (!(*cgen)((ast_expression*)(self->func), func, false, &funval))
return false;
if (!funval)
return false;
MEM_VECTOR_INIT(&params, v);
/* parameters */
for (i = 0; i < self->params_count; ++i)
{
ir_value *param;
ast_expression *expr = self->params[i];
cgen = expr->expression.codegen;
if (!(*cgen)(expr, func, false, &param))
goto error;
if (!param)
goto error;
if (!ir_value_vector_v_add(&params, param))
goto error;
}
callinstr = ir_block_create_call(func->curblock, ast_function_label(func, "call"), funval);
if (!callinstr)
goto error;
for (i = 0; i < params.v_count; ++i) {
if (!ir_call_param(callinstr, params.v[i]))
goto error;
}
*out = ir_call_value(callinstr);
MEM_VECTOR_CLEAR(&params, v);
return true;
error:
MEM_VECTOR_CLEAR(&params, v);
return false;
}

76
ast.h
View file

@ -40,6 +40,9 @@ typedef struct ast_entfield_s ast_entfield;
typedef struct ast_ifthen_s ast_ifthen; typedef struct ast_ifthen_s ast_ifthen;
typedef struct ast_ternary_s ast_ternary; typedef struct ast_ternary_s ast_ternary;
typedef struct ast_loop_s ast_loop; typedef struct ast_loop_s ast_loop;
typedef struct ast_call_s ast_call;
typedef struct ast_unary_s ast_unary;
typedef struct ast_return_s ast_return;
/* Node interface with common components /* Node interface with common components
*/ */
@ -78,7 +81,9 @@ typedef struct
ast_expression_codegen *codegen; ast_expression_codegen *codegen;
int vtype; int vtype;
ast_expression *next; ast_expression *next;
MEM_VECTOR_MAKE(ast_value*, params);
} ast_expression_common; } ast_expression_common;
MEM_VECTOR_PROTO(ast_expression_common, ast_value*, params);
/* Value /* Value
* *
@ -109,12 +114,8 @@ struct ast_value_s
} constval; } constval;
ir_value *ir_v; ir_value *ir_v;
/* if vtype is qc_function, params contain parameters, and
* 'next' the return type.
*/
MEM_VECTOR_MAKE(ast_value*, params);
}; };
ast_value* ast_value_new(lex_ctx ctx, const char *name, int qctype); ast_value* ast_value_new(lex_ctx ctx, const char *name, int qctype);
/* This will NOT delete an underlying ast_function */ /* This will NOT delete an underlying ast_function */
void ast_value_delete(ast_value*); void ast_value_delete(ast_value*);
@ -122,9 +123,11 @@ void ast_value_delete(ast_value*);
bool ast_value_set_name(ast_value*, const char *name); bool ast_value_set_name(ast_value*, const char *name);
bool ast_value_codegen(ast_value*, ast_function*, bool lvalue, ir_value**); bool ast_value_codegen(ast_value*, ast_function*, bool lvalue, ir_value**);
bool ast_local_codegen(ast_value *self, ir_function *func); bool ast_local_codegen(ast_value *self, ir_function *func, bool isparam);
bool ast_global_codegen(ast_value *self, ir_builder *ir); bool ast_global_codegen(ast_value *self, ir_builder *ir);
bool GMQCC_WARN ast_value_params_add(ast_value*, ast_value*);
/* Binary /* Binary
* *
* A value-returning binary expression. * A value-returning binary expression.
@ -145,6 +148,41 @@ void ast_binary_delete(ast_binary*);
bool ast_binary_codegen(ast_binary*, ast_function*, bool lvalue, ir_value**); bool ast_binary_codegen(ast_binary*, ast_function*, bool lvalue, ir_value**);
/* Unary
*
* Regular unary expressions: not,neg
*/
struct ast_unary_s
{
ast_expression_common expression;
int op;
ast_expression *operand;
};
ast_unary* ast_unary_new(lex_ctx ctx,
int op,
ast_expression *expr);
void ast_unary_delete(ast_unary*);
bool ast_unary_codegen(ast_unary*, ast_function*, bool lvalue, ir_value**);
/* Return
*
* Make sure 'return' only happens at the end of a block, otherwise the IR
* will refuse to create further instructions.
* This should be honored by the parser.
*/
struct ast_return_s
{
ast_expression_common expression;
ast_expression *operand;
};
ast_return* ast_return_new(lex_ctx ctx,
ast_expression *expr);
void ast_return_delete(ast_return*);
bool ast_return_codegen(ast_return*, ast_function*, bool lvalue, ir_value**);
/* Entity-field /* Entity-field
* *
* This must do 2 things: * This must do 2 things:
@ -284,6 +322,29 @@ void ast_loop_delete(ast_loop*);
bool ast_loop_codegen(ast_loop*, ast_function*, bool lvalue, ir_value**); bool ast_loop_codegen(ast_loop*, ast_function*, bool lvalue, ir_value**);
/* CALL node
*
* Contains an ast_expression as target, rather than an ast_function/value.
* Since it's how QC works, every ast_function has an ast_value
* associated anyway - in other words, the VM contains function
* pointers for every function anyway. Thus, this node will call
* expression.
* Additionally it contains a list of ast_expressions as parameters.
* Since calls can return values, an ast_call is also an ast_expression.
*/
struct ast_call_s
{
ast_expression_common expression;
ast_expression *func;
MEM_VECTOR_MAKE(ast_expression*, params);
};
ast_call* ast_call_new(lex_ctx ctx,
ast_expression *funcexpr);
void ast_call_delete(ast_call*);
bool ast_call_codegen(ast_call*, ast_function*, bool lvalue, ir_value**);
MEM_VECTOR_PROTO(ast_call, ast_expression*, params);
/* Blocks /* Blocks
* *
*/ */
@ -296,6 +357,7 @@ struct ast_block_s
}; };
ast_block* ast_block_new(lex_ctx ctx); ast_block* ast_block_new(lex_ctx ctx);
void ast_block_delete(ast_block*); void ast_block_delete(ast_block*);
bool ast_block_set_type(ast_block*, ast_expression *from);
MEM_VECTOR_PROTO(ast_block, ast_value*, locals); MEM_VECTOR_PROTO(ast_block, ast_value*, locals);
MEM_VECTOR_PROTO(ast_block, ast_expression*, exprs); MEM_VECTOR_PROTO(ast_block, ast_expression*, exprs);
@ -319,6 +381,8 @@ struct ast_function_s
ast_value *vtype; ast_value *vtype;
const char *name; const char *name;
int builtin;
ir_function *ir_func; ir_function *ir_func;
ir_block *curblock; ir_block *curblock;
ir_block *breakblock; ir_block *breakblock;

35
gmqcc.h
View file

@ -77,7 +77,7 @@
* This is a hack to silent clang regarding empty * This is a hack to silent clang regarding empty
* body if statements. * body if statements.
*/ */
#define GMQCC_SUPRESS_EMPTY_BODY do { } while (0) #define GMQCC_SUPPRESS_EMPTY_BODY do { } while (0)
/* /*
* Inline is not supported in < C90, however some compilers * Inline is not supported in < C90, however some compilers
@ -371,6 +371,13 @@ enum {
}; };
extern size_t type_sizeof[TYPE_COUNT]; extern size_t type_sizeof[TYPE_COUNT];
extern uint16_t type_store_instr[TYPE_COUNT];
/* could use type_store_instr + INSTR_STOREP_F - INSTR_STORE_F
* but this breaks when TYPE_INTEGER is added, since with the enhanced
* instruction set, the old ones are left untouched, thus the _I instructions
* are at a seperate place.
*/
extern uint16_t type_storep_instr[TYPE_COUNT];
typedef struct { typedef struct {
uint32_t offset; /* Offset in file of where data begins */ uint32_t offset; /* Offset in file of where data begins */
@ -605,7 +612,7 @@ static const struct {
{ "EQ_V" , 0, 4 }, { "EQ_V" , 0, 4 },
{ "EQ_S" , 0, 4 }, { "EQ_S" , 0, 4 },
{ "EQ_E" , 0, 4 }, { "EQ_E" , 0, 4 },
{ "ES_FNC" , 0, 6 }, { "EQ_FNC" , 0, 6 },
{ "NE_F" , 0, 4 }, { "NE_F" , 0, 4 },
{ "NE_V" , 0, 4 }, { "NE_V" , 0, 4 },
{ "NE_S" , 0, 4 }, { "NE_S" , 0, 4 },
@ -694,7 +701,7 @@ extern int opts_compiler;
size_t name##_count; \ size_t name##_count; \
size_t name##_alloc size_t name##_alloc
#define _MEM_VEC_FUN_ADD(Tself, Twhat, mem) \ #define MEM_VEC_FUN_ADD(Tself, Twhat, mem) \
bool GMQCC_WARN Tself##_##mem##_add(Tself *self, Twhat f) \ bool GMQCC_WARN Tself##_##mem##_add(Tself *self, Twhat f) \
{ \ { \
Twhat *reall; \ Twhat *reall; \
@ -716,7 +723,7 @@ bool GMQCC_WARN Tself##_##mem##_add(Tself *self, Twhat f) \
return true; \ return true; \
} }
#define _MEM_VEC_FUN_REMOVE(Tself, Twhat, mem) \ #define MEM_VEC_FUN_REMOVE(Tself, Twhat, mem) \
bool GMQCC_WARN Tself##_##mem##_remove(Tself *self, size_t idx) \ bool GMQCC_WARN Tself##_##mem##_remove(Tself *self, size_t idx) \
{ \ { \
size_t i; \ size_t i; \
@ -741,7 +748,7 @@ bool GMQCC_WARN Tself##_##mem##_remove(Tself *self, size_t idx) \
return true; \ return true; \
} }
#define _MEM_VEC_FUN_FIND(Tself, Twhat, mem) \ #define MEM_VEC_FUN_FIND(Tself, Twhat, mem) \
bool GMQCC_WARN Tself##_##mem##_find(Tself *self, Twhat obj, size_t *idx) \ bool GMQCC_WARN Tself##_##mem##_find(Tself *self, Twhat obj, size_t *idx) \
{ \ { \
size_t i; \ size_t i; \
@ -756,7 +763,7 @@ bool GMQCC_WARN Tself##_##mem##_find(Tself *self, Twhat obj, size_t *idx) \
return false; \ return false; \
} }
#define _MEM_VEC_FUN_APPEND(Tself, Twhat, mem) \ #define MEM_VEC_FUN_APPEND(Tself, Twhat, mem) \
bool GMQCC_WARN Tself##_##mem##_append(Tself *s, Twhat *p, size_t c) \ bool GMQCC_WARN Tself##_##mem##_append(Tself *s, Twhat *p, size_t c) \
{ \ { \
Twhat *reall; \ Twhat *reall; \
@ -782,7 +789,7 @@ bool GMQCC_WARN Tself##_##mem##_append(Tself *s, Twhat *p, size_t c) \
return true; \ return true; \
} }
#define _MEM_VEC_FUN_RESIZE(Tself, Twhat, mem) \ #define MEM_VEC_FUN_RESIZE(Tself, Twhat, mem) \
bool GMQCC_WARN Tself##_##mem##_resize(Tself *s, size_t c) \ bool GMQCC_WARN Tself##_##mem##_resize(Tself *s, size_t c) \
{ \ { \
Twhat *reall; \ Twhat *reall; \
@ -806,7 +813,7 @@ bool GMQCC_WARN Tself##_##mem##_resize(Tself *s, size_t c) \
return true; \ return true; \
} }
#define _MEM_VEC_FUN_CLEAR(Tself, mem) \ #define MEM_VEC_FUN_CLEAR(Tself, mem) \
void Tself##_##mem##_clear(Tself *self) \ void Tself##_##mem##_clear(Tself *self) \
{ \ { \
if (!self->mem) \ if (!self->mem) \
@ -832,18 +839,20 @@ void Tself##_##mem##_clear(Tself *self) \
} }
#define MEM_VEC_FUNCTIONS(Tself, Twhat, mem) \ #define MEM_VEC_FUNCTIONS(Tself, Twhat, mem) \
_MEM_VEC_FUN_REMOVE(Tself, Twhat, mem) \ MEM_VEC_FUN_REMOVE(Tself, Twhat, mem) \
_MEM_VEC_FUN_ADD(Tself, Twhat, mem) MEM_VEC_FUN_ADD(Tself, Twhat, mem)
#define MEM_VEC_FUNCTIONS_ALL(Tself, Twhat, mem) \ #define MEM_VEC_FUNCTIONS_ALL(Tself, Twhat, mem) \
MEM_VEC_FUNCTIONS(Tself, Twhat, mem) \ MEM_VEC_FUNCTIONS(Tself, Twhat, mem) \
_MEM_VEC_FUN_CLEAR(Tself, mem) \ MEM_VEC_FUN_CLEAR(Tself, mem) \
_MEM_VEC_FUN_FIND(Tself, Twhat, mem) MEM_VEC_FUN_FIND(Tself, Twhat, mem)
enum store_types { enum store_types {
store_global, store_global,
store_local, /* local, assignable for now, should get promoted later */ store_local, /* local, assignable for now, should get promoted later */
store_value /* unassignable */ store_param, /* parameters, they are locals with a fixed position */
store_value, /* unassignable */
store_return /* unassignable, at OFS_RETURN */
}; };
typedef struct { typedef struct {

393
ir.c
View file

@ -44,6 +44,38 @@ size_t type_sizeof[TYPE_COUNT] = {
3, /* TYPE_VARIANT */ 3, /* TYPE_VARIANT */
}; };
uint16_t type_store_instr[TYPE_COUNT] = {
INSTR_STORE_F, /* should use I when having integer support */
INSTR_STORE_S,
INSTR_STORE_F,
INSTR_STORE_V,
INSTR_STORE_ENT,
INSTR_STORE_FLD,
INSTR_STORE_FNC,
INSTR_STORE_ENT, /* should use I */
#if 0
INSTR_STORE_ENT, /* integer type */
#endif
INSTR_STORE_V, /* variant, should never be accessed */
};
uint16_t type_storep_instr[TYPE_COUNT] = {
INSTR_STOREP_F, /* should use I when having integer support */
INSTR_STOREP_S,
INSTR_STOREP_F,
INSTR_STOREP_V,
INSTR_STOREP_ENT,
INSTR_STOREP_FLD,
INSTR_STOREP_FNC,
INSTR_STOREP_ENT, /* should use I */
#if 0
INSTR_STOREP_ENT, /* integer type */
#endif
INSTR_STOREP_V, /* variant, should never be accessed */
};
MEM_VEC_FUNCTIONS(ir_value_vector, ir_value*, v)
/*********************************************************************** /***********************************************************************
*IR Builder *IR Builder
*/ */
@ -108,20 +140,32 @@ ir_function* ir_builder_get_function(ir_builder *self, const char *name)
return NULL; return NULL;
} }
ir_function* ir_builder_create_function(ir_builder *self, const char *name) ir_function* ir_builder_create_function(ir_builder *self, const char *name, int outtype)
{ {
ir_function *fn = ir_builder_get_function(self, name); ir_function *fn = ir_builder_get_function(self, name);
if (fn) { if (fn) {
return NULL; return NULL;
} }
fn = ir_function_new(self); fn = ir_function_new(self, outtype);
if (!ir_function_set_name(fn, name) || if (!ir_function_set_name(fn, name) ||
!ir_builder_functions_add(self, fn) ) !ir_builder_functions_add(self, fn) )
{ {
ir_function_delete(fn); ir_function_delete(fn);
return NULL; return NULL;
} }
fn->value = ir_builder_create_global(self, fn->name, TYPE_FUNCTION);
if (!fn->value) {
ir_function_delete(fn);
return NULL;
}
fn->value->isconst = true;
fn->value->outtype = outtype;
fn->value->constval.vfunc = fn;
fn->value->context = fn->context;
return fn; return fn;
} }
@ -159,7 +203,7 @@ void ir_function_enumerate(ir_function*);
bool ir_function_calculate_liferanges(ir_function*); bool ir_function_calculate_liferanges(ir_function*);
bool ir_function_allocate_locals(ir_function*); bool ir_function_allocate_locals(ir_function*);
ir_function* ir_function_new(ir_builder* owner) ir_function* ir_function_new(ir_builder* owner, int outtype)
{ {
ir_function *self; ir_function *self;
self = (ir_function*)mem_a(sizeof(*self)); self = (ir_function*)mem_a(sizeof(*self));
@ -175,7 +219,9 @@ ir_function* ir_function_new(ir_builder* owner)
self->owner = owner; self->owner = owner;
self->context.file = "<@no context>"; self->context.file = "<@no context>";
self->context.line = 0; self->context.line = 0;
self->retype = TYPE_VOID; self->outtype = outtype;
self->value = NULL;
self->builtin = 0;
MEM_VECTOR_INIT(self, params); MEM_VECTOR_INIT(self, params);
MEM_VECTOR_INIT(self, blocks); MEM_VECTOR_INIT(self, blocks);
MEM_VECTOR_INIT(self, values); MEM_VECTOR_INIT(self, values);
@ -187,6 +233,7 @@ ir_function* ir_function_new(ir_builder* owner)
MEM_VEC_FUNCTIONS(ir_function, ir_value*, values) MEM_VEC_FUNCTIONS(ir_function, ir_value*, values)
MEM_VEC_FUNCTIONS(ir_function, ir_block*, blocks) MEM_VEC_FUNCTIONS(ir_function, ir_block*, blocks)
MEM_VEC_FUNCTIONS(ir_function, ir_value*, locals) MEM_VEC_FUNCTIONS(ir_function, ir_value*, locals)
MEM_VEC_FUNCTIONS(ir_function, int, params)
bool ir_function_set_name(ir_function *self, const char *name) bool ir_function_set_name(ir_function *self, const char *name)
{ {
@ -215,6 +262,8 @@ void ir_function_delete(ir_function *self)
ir_value_delete(self->locals[i]); ir_value_delete(self->locals[i]);
MEM_VECTOR_CLEAR(self, locals); MEM_VECTOR_CLEAR(self, locals);
/* self->value is deleted by the builder */
mem_d(self); mem_d(self);
} }
@ -236,6 +285,9 @@ ir_block* ir_function_create_block(ir_function *self, const char *label)
bool ir_function_finalize(ir_function *self) bool ir_function_finalize(ir_function *self)
{ {
if (self->builtin)
return true;
if (!ir_function_naive_phi(self)) if (!ir_function_naive_phi(self))
return false; return false;
@ -259,14 +311,21 @@ ir_value* ir_function_get_local(ir_function *self, const char *name)
return NULL; return NULL;
} }
ir_value* ir_function_create_local(ir_function *self, const char *name, int vtype) ir_value* ir_function_create_local(ir_function *self, const char *name, int vtype, bool param)
{ {
ir_value *ve = ir_function_get_local(self, name); ir_value *ve = ir_function_get_local(self, name);
if (ve) { if (ve) {
return NULL; return NULL;
} }
ve = ir_value_var(name, store_local, vtype); if (param &&
self->locals_count &&
self->locals[self->locals_count-1]->store != store_param) {
printf("cannot add parameters after adding locals\n");
return NULL;
}
ve = ir_value_var(name, (param ? store_param : store_local), vtype);
if (!ir_function_locals_add(self, ve)) { if (!ir_function_locals_add(self, ve)) {
ir_value_delete(ve); ir_value_delete(ve);
return NULL; return NULL;
@ -356,11 +415,13 @@ ir_instr* ir_instr_new(ir_block* owner, int op)
self->bops[0] = NULL; self->bops[0] = NULL;
self->bops[1] = NULL; self->bops[1] = NULL;
MEM_VECTOR_INIT(self, phi); MEM_VECTOR_INIT(self, phi);
MEM_VECTOR_INIT(self, params);
self->eid = 0; self->eid = 0;
return self; return self;
} }
MEM_VEC_FUNCTIONS(ir_instr, ir_phi_entry_t, phi) MEM_VEC_FUNCTIONS(ir_instr, ir_phi_entry_t, phi)
MEM_VEC_FUNCTIONS(ir_instr, ir_value*, params)
void ir_instr_delete(ir_instr *self) void ir_instr_delete(ir_instr *self)
{ {
@ -374,14 +435,22 @@ void ir_instr_delete(ir_instr *self)
for (i = 0; i < self->phi_count; ++i) { for (i = 0; i < self->phi_count; ++i) {
size_t idx; size_t idx;
if (ir_value_writes_find(self->phi[i].value, self, &idx)) if (ir_value_writes_find(self->phi[i].value, self, &idx))
if (ir_value_writes_remove(self->phi[i].value, idx)) GMQCC_SUPRESS_EMPTY_BODY; if (ir_value_writes_remove(self->phi[i].value, idx)) GMQCC_SUPPRESS_EMPTY_BODY;
if (ir_value_reads_find(self->phi[i].value, self, &idx)) if (ir_value_reads_find(self->phi[i].value, self, &idx))
if (ir_value_reads_remove (self->phi[i].value, idx)) GMQCC_SUPRESS_EMPTY_BODY; if (ir_value_reads_remove (self->phi[i].value, idx)) GMQCC_SUPPRESS_EMPTY_BODY;
} }
MEM_VECTOR_CLEAR(self, phi); MEM_VECTOR_CLEAR(self, phi);
if (ir_instr_op(self, 0, NULL, false)) GMQCC_SUPRESS_EMPTY_BODY; for (i = 0; i < self->params_count; ++i) {
if (ir_instr_op(self, 1, NULL, false)) GMQCC_SUPRESS_EMPTY_BODY; size_t idx;
if (ir_instr_op(self, 2, NULL, false)) GMQCC_SUPRESS_EMPTY_BODY; if (ir_value_writes_find(self->params[i], self, &idx))
if (ir_value_writes_remove(self->params[i], idx)) GMQCC_SUPPRESS_EMPTY_BODY;
if (ir_value_reads_find(self->params[i], self, &idx))
if (ir_value_reads_remove (self->params[i], idx)) GMQCC_SUPPRESS_EMPTY_BODY;
}
MEM_VECTOR_CLEAR(self, params);
if (ir_instr_op(self, 0, NULL, false)) GMQCC_SUPPRESS_EMPTY_BODY;
if (ir_instr_op(self, 1, NULL, false)) GMQCC_SUPPRESS_EMPTY_BODY;
if (ir_instr_op(self, 2, NULL, false)) GMQCC_SUPPRESS_EMPTY_BODY;
mem_d(self); mem_d(self);
} }
@ -423,6 +492,7 @@ ir_value* ir_value_var(const char *name, int storetype, int vtype)
self = (ir_value*)mem_a(sizeof(*self)); self = (ir_value*)mem_a(sizeof(*self));
self->vtype = vtype; self->vtype = vtype;
self->fieldtype = TYPE_VOID; self->fieldtype = TYPE_VOID;
self->outtype = TYPE_VOID;
self->store = storetype; self->store = storetype;
MEM_VECTOR_INIT(self, reads); MEM_VECTOR_INIT(self, reads);
MEM_VECTOR_INIT(self, writes); MEM_VECTOR_INIT(self, writes);
@ -486,6 +556,15 @@ bool ir_value_set_float(ir_value *self, float f)
return true; return true;
} }
bool ir_value_set_func(ir_value *self, int f)
{
if (self->vtype != TYPE_FUNCTION)
return false;
self->constval.vint = f;
self->isconst = true;
return true;
}
bool ir_value_set_vector(ir_value *self, vector v) bool ir_value_set_vector(ir_value *self, vector v)
{ {
if (self->vtype != TYPE_VECTOR) if (self->vtype != TYPE_VECTOR)
@ -773,46 +852,14 @@ bool ir_block_create_store(ir_block *self, ir_value *target, ir_value *what)
else else
vtype = target->vtype; vtype = target->vtype;
switch (vtype) {
case TYPE_FLOAT:
#if 0 #if 0
if (what->vtype == TYPE_INTEGER) if (vtype == TYPE_FLOAT && what->vtype == TYPE_INTEGER)
op = INSTR_CONV_ITOF; op = INSTR_CONV_ITOF;
else else if (vtype == TYPE_INTEGER && what->vtype == TYPE_FLOAT)
op = INSTR_CONV_FTOI;
#endif #endif
op = INSTR_STORE_F; op = type_store_instr[vtype];
break;
case TYPE_VECTOR:
op = INSTR_STORE_V;
break;
case TYPE_ENTITY:
op = INSTR_STORE_ENT;
break;
case TYPE_STRING:
op = INSTR_STORE_S;
break;
case TYPE_FIELD:
op = INSTR_STORE_FLD;
break;
#if 0
case TYPE_INTEGER:
if (what->vtype == TYPE_INTEGER)
op = INSTR_CONV_FTOI;
else
op = INSTR_STORE_I;
break;
#endif
case TYPE_POINTER:
#if 0
op = INSTR_STORE_I;
#else
op = INSTR_STORE_ENT;
#endif
break;
default:
/* Unknown type */
return false;
}
return ir_block_create_store_op(self, op, target, what); return ir_block_create_store_op(self, op, target, what);
} }
@ -829,38 +876,8 @@ bool ir_block_create_storep(ir_block *self, ir_value *target, ir_value *what)
*/ */
vtype = what->vtype; vtype = what->vtype;
switch (vtype) { op = type_storep_instr[vtype];
case TYPE_FLOAT:
op = INSTR_STOREP_F;
break;
case TYPE_VECTOR:
op = INSTR_STOREP_V;
break;
case TYPE_ENTITY:
op = INSTR_STOREP_ENT;
break;
case TYPE_STRING:
op = INSTR_STOREP_S;
break;
case TYPE_FIELD:
op = INSTR_STOREP_FLD;
break;
#if 0
case TYPE_INTEGER:
op = INSTR_STOREP_I;
break;
#endif
case TYPE_POINTER:
#if 0
op = INSTR_STOREP_I;
#else
op = INSTR_STOREP_ENT;
#endif
break;
default:
/* Unknown type */
return false;
}
return ir_block_create_store_op(self, op, target, what); return ir_block_create_store_op(self, op, target, what);
} }
@ -1017,6 +1034,47 @@ bool ir_phi_add(ir_instr* self, ir_block *b, ir_value *v)
return ir_instr_phi_add(self, pe); return ir_instr_phi_add(self, pe);
} }
/* call related code */
ir_instr* ir_block_create_call(ir_block *self, const char *label, ir_value *func)
{
ir_value *out;
ir_instr *in;
in = ir_instr_new(self, INSTR_CALL0);
if (!in)
return NULL;
out = ir_value_out(self->owner, label, store_return, func->outtype);
if (!out) {
ir_instr_delete(in);
return NULL;
}
if (!ir_instr_op(in, 0, out, true) ||
!ir_instr_op(in, 1, func, false) ||
!ir_block_instr_add(self, in))
{
ir_instr_delete(in);
ir_value_delete(out);
return NULL;
}
return in;
}
ir_value* ir_call_value(ir_instr *self)
{
return self->_ops[0];
}
bool ir_call_param(ir_instr* self, ir_value *v)
{
if (!ir_instr_params_add(self, v))
return false;
if (!ir_value_reads_add(v, self)) {
if (!ir_instr_params_remove(self, self->params_count-1))
GMQCC_SUPPRESS_EMPTY_BODY;
return false;
}
return true;
}
/* binary op related code */ /* binary op related code */
ir_value* ir_block_create_binop(ir_block *self, ir_value* ir_block_create_binop(ir_block *self,
@ -1111,6 +1169,39 @@ ir_value* ir_block_create_binop(ir_block *self,
return ir_block_create_general_instr(self, label, opcode, left, right, ot); return ir_block_create_general_instr(self, label, opcode, left, right, ot);
} }
ir_value* ir_block_create_unary(ir_block *self,
const char *label, int opcode,
ir_value *operand)
{
int ot = TYPE_FLOAT;
switch (opcode) {
case INSTR_NOT_F:
case INSTR_NOT_V:
case INSTR_NOT_S:
case INSTR_NOT_ENT:
case INSTR_NOT_FNC:
#if 0
case INSTR_NOT_I:
#endif
ot = TYPE_FLOAT;
break;
/* QC doesn't have other unary operations. We expect extensions to fill
* the above list, otherwise we assume out-type = in-type, eg for an
* unary minus
*/
default:
ot = operand->vtype;
break;
};
if (ot == TYPE_VOID) {
/* The AST or parser were supposed to check this! */
return NULL;
}
/* let's use the general instruction creator and pass NULL for OPB */
return ir_block_create_general_instr(self, label, opcode, operand, NULL, ot);
}
ir_value* ir_block_create_general_instr(ir_block *self, const char *label, ir_value* ir_block_create_general_instr(ir_block *self, const char *label,
int op, ir_value *a, ir_value *b, int outype) int op, ir_value *a, ir_value *b, int outype)
{ {
@ -1406,7 +1497,7 @@ static bool ir_block_naive_phi(ir_block *self)
if (v->writes[w]->_ops[0] == v) if (v->writes[w]->_ops[0] == v)
v->writes[w]->_ops[0] = instr->_ops[0]; v->writes[w]->_ops[0] = instr->_ops[0];
if (old->store != store_value && old->store != store_local) if (old->store != store_value && old->store != store_local && old->store != store_param)
{ {
/* If it originally wrote to a global we need to store the value /* If it originally wrote to a global we need to store the value
* there as welli * there as welli
@ -1565,6 +1656,9 @@ bool ir_function_allocate_locals(ir_function *self)
function_allocator alloc; function_allocator alloc;
if (!self->locals_count)
return true;
MEM_VECTOR_INIT(&alloc, locals); MEM_VECTOR_INIT(&alloc, locals);
MEM_VECTOR_INIT(&alloc, sizes); MEM_VECTOR_INIT(&alloc, sizes);
MEM_VECTOR_INIT(&alloc, positions); MEM_VECTOR_INIT(&alloc, positions);
@ -1611,6 +1705,10 @@ bool ir_function_allocate_locals(ir_function *self)
if (!function_allocator_positions_add(&alloc, 0)) if (!function_allocator_positions_add(&alloc, 0))
goto error; goto error;
if (alloc.sizes_count)
pos = alloc.positions[0] + alloc.sizes[0];
else
pos = 0;
for (i = 1; i < alloc.sizes_count; ++i) for (i = 1; i < alloc.sizes_count; ++i)
{ {
pos = alloc.positions[i-1] + alloc.sizes[i-1]; pos = alloc.positions[i-1] + alloc.sizes[i-1];
@ -1779,8 +1877,11 @@ static bool ir_block_life_propagate(ir_block *self, ir_block *prev, bool *change
value = instr->_ops[o]; value = instr->_ops[o];
/* We only care about locals */ /* We only care about locals */
/* we also calculate parameter liferanges so that locals
* can take up parameter slots */
if (value->store != store_value && if (value->store != store_value &&
value->store != store_local) value->store != store_local &&
value->store != store_param)
continue; continue;
/* read operands */ /* read operands */
@ -2109,8 +2210,56 @@ tailcall:
} }
if (instr->opcode >= INSTR_CALL0 && instr->opcode <= INSTR_CALL8) { if (instr->opcode >= INSTR_CALL0 && instr->opcode <= INSTR_CALL8) {
printf("TODO: call instruction\n"); /* Trivial call translation:
return false; * copy all params to OFS_PARM*
* if the output's storetype is not store_return,
* add append a STORE instruction!
*
* NOTES on how to do it better without much trouble:
* -) The liferanges!
* Simply check the liferange of all parameters for
* other CALLs. For each param with no CALL in its
* liferange, we can store it in an OFS_PARM at
* generation already. This would even include later
* reuse.... probably... :)
*/
size_t p;
ir_value *retvalue;
for (p = 0; p < instr->params_count; ++p)
{
ir_value *param = instr->params[p];
stmt.opcode = INSTR_STORE_F;
stmt.o3.u1 = 0;
stmt.opcode = type_store_instr[param->vtype];
stmt.o1.u1 = param->code.globaladdr;
stmt.o2.u1 = OFS_PARM0 + 3 * p;
if (code_statements_add(stmt) < 0)
return false;
}
stmt.opcode = INSTR_CALL0 + instr->params_count;
if (stmt.opcode > INSTR_CALL8)
stmt.opcode = INSTR_CALL8;
stmt.o1.u1 = instr->_ops[1]->code.globaladdr;
stmt.o2.u1 = 0;
stmt.o3.u1 = 0;
if (code_statements_add(stmt) < 0)
return false;
retvalue = instr->_ops[0];
if (retvalue && retvalue->store != store_return && retvalue->life_count)
{
/* not to be kept in OFS_RETURN */
stmt.opcode = type_store_instr[retvalue->vtype];
stmt.o1.u1 = OFS_RETURN;
stmt.o2.u1 = retvalue->code.globaladdr;
stmt.o3.u1 = 0;
if (code_statements_add(stmt) < 0)
return false;
}
continue;
} }
if (instr->opcode == INSTR_STATE) { if (instr->opcode == INSTR_STATE) {
@ -2138,10 +2287,8 @@ tailcall:
stmt.o1.u1 = stmt.o3.u1; stmt.o1.u1 = stmt.o3.u1;
stmt.o3.u1 = 0; stmt.o3.u1 = 0;
} }
else if ((stmt.opcode >= INSTR_STORE_F && else if (stmt.opcode >= INSTR_STORE_F &&
stmt.opcode <= INSTR_STORE_FNC) || stmt.opcode <= INSTR_STORE_FNC)
(stmt.opcode >= INSTR_NOT_F &&
stmt.opcode <= INSTR_NOT_FNC))
{ {
/* 2-operand instructions with A -> B */ /* 2-operand instructions with A -> B */
stmt.o2.u1 = stmt.o3.u1; stmt.o2.u1 = stmt.o3.u1;
@ -2157,6 +2304,7 @@ tailcall:
static bool gen_function_code(ir_function *self) static bool gen_function_code(ir_function *self)
{ {
ir_block *block; ir_block *block;
prog_section_statement stmt;
/* Starting from entry point, we generate blocks "as they come" /* Starting from entry point, we generate blocks "as they come"
* for now. Dead blocks will not be translated obviously. * for now. Dead blocks will not be translated obviously.
@ -2174,6 +2322,14 @@ static bool gen_function_code(ir_function *self)
printf("failed to generate blocks for '%s'\n", self->name); printf("failed to generate blocks for '%s'\n", self->name);
return false; return false;
} }
/* otherwise code_write crashes since it debug-prints functions until AINSTR_END */
stmt.opcode = AINSTR_END;
stmt.o1.u1 = 0;
stmt.o2.u1 = 0;
stmt.o3.u1 = 0;
if (code_statements_add(stmt) < 0)
return false;
return true; return true;
} }
@ -2185,8 +2341,7 @@ static bool gen_global_function(ir_builder *ir, ir_value *global)
size_t i; size_t i;
size_t local_var_end; size_t local_var_end;
if (!global->isconst || if (!global->isconst || (!global->constval.vfunc))
!global->constval.vfunc)
{ {
printf("Invalid state of function-global: not constant: %s\n", global->name); printf("Invalid state of function-global: not constant: %s\n", global->name);
return false; return false;
@ -2202,10 +2357,8 @@ static bool gen_global_function(ir_builder *ir, ir_value *global)
for (i = 0;i < 8; ++i) { for (i = 0;i < 8; ++i) {
if (i >= fun.nargs) if (i >= fun.nargs)
fun.argsize[i] = 0; fun.argsize[i] = 0;
else if (irfun->params[i] == TYPE_VECTOR)
fun.argsize[i] = 3;
else else
fun.argsize[i] = 1; fun.argsize[i] = type_sizeof[irfun->params[i]];
} }
fun.firstlocal = code_globals_elements; fun.firstlocal = code_globals_elements;
@ -2234,10 +2387,14 @@ static bool gen_global_function(ir_builder *ir, ir_value *global)
code_globals_add(0); code_globals_add(0);
} }
fun.entry = code_statements_elements; if (irfun->builtin)
if (!gen_function_code(irfun)) { fun.entry = irfun->builtin;
printf("Failed to generate code for function %s\n", irfun->name); else {
return false; fun.entry = code_statements_elements;
if (!gen_function_code(irfun)) {
printf("Failed to generate code for function %s\n", irfun->name);
return false;
}
} }
return (code_functions_add(fun) >= 0); return (code_functions_add(fun) >= 0);
@ -2245,6 +2402,7 @@ static bool gen_global_function(ir_builder *ir, ir_value *global)
static bool ir_builder_gen_global(ir_builder *self, ir_value *global) static bool ir_builder_gen_global(ir_builder *self, ir_value *global)
{ {
size_t i;
int32_t *iptr; int32_t *iptr;
prog_section_def def; prog_section_def def;
@ -2289,31 +2447,43 @@ static bool ir_builder_gen_global(ir_builder *self, ir_value *global)
} }
case TYPE_VECTOR: case TYPE_VECTOR:
{ {
size_t d;
if (code_defs_add(def) < 0) if (code_defs_add(def) < 0)
return false; return false;
if (global->isconst) { if (global->isconst) {
iptr = (int32_t*)&global->constval.vvec; iptr = (int32_t*)&global->constval.vvec;
global->code.globaladdr = code_globals_add(iptr[0]); global->code.globaladdr = code_globals_add(iptr[0]);
if (code_globals_add(iptr[1]) < 0 || code_globals_add(iptr[2]) < 0) if (global->code.globaladdr < 0)
return false; return false;
for (d = 1; d < type_sizeof[global->vtype]; ++d)
{
if (code_globals_add(iptr[d]) < 0)
return false;
}
} else { } else {
global->code.globaladdr = code_globals_add(0); global->code.globaladdr = code_globals_add(0);
if (code_globals_add(0) < 0 || code_globals_add(0) < 0) if (global->code.globaladdr < 0)
return false; return false;
for (d = 1; d < type_sizeof[global->vtype]; ++d)
{
if (code_globals_add(0) < 0)
return false;
}
} }
return global->code.globaladdr >= 0; return global->code.globaladdr >= 0;
} }
case TYPE_FUNCTION: case TYPE_FUNCTION:
if (code_defs_add(def) < 0) if (code_defs_add(def) < 0)
return false; return false;
global->code.globaladdr = code_globals_elements;
code_globals_add(code_functions_elements); code_globals_add(code_functions_elements);
return gen_global_function(self, global); return gen_global_function(self, global);
case TYPE_VARIANT: case TYPE_VARIANT:
/* assume biggest type */ /* assume biggest type */
global->code.globaladdr = code_globals_add(0); global->code.globaladdr = code_globals_add(0);
code_globals_add(0); for (i = 1; i < type_sizeof[TYPE_VARIANT]; ++i)
code_globals_add(0); code_globals_add(0);
return true; return true;
default: default:
/* refuse to create 'void' type or any other fancy business. */ /* refuse to create 'void' type or any other fancy business. */
@ -2328,21 +2498,6 @@ bool ir_builder_generate(ir_builder *self, const char *filename)
code_init(); code_init();
/* FIXME: generate TYPE_FUNCTION globals and link them
* to their ir_function.
*/
for (i = 0; i < self->functions_count; ++i)
{
ir_value *funval;
ir_function *fun = self->functions[i];
funval = ir_builder_create_global(self, fun->name, TYPE_FUNCTION);
funval->isconst = true;
funval->constval.vfunc = fun;
funval->context = fun->context;
}
for (i = 0; i < self->globals_count; ++i) for (i = 0; i < self->globals_count; ++i)
{ {
if (!ir_builder_gen_global(self, self->globals[i])) { if (!ir_builder_gen_global(self, self->globals[i])) {
@ -2398,6 +2553,10 @@ void ir_function_dump(ir_function *f, char *ind,
int (*oprintf)(const char*, ...)) int (*oprintf)(const char*, ...))
{ {
size_t i; size_t i;
if (f->builtin != 0) {
oprintf("%sfunction %s = builtin %i\n", ind, f->name, -f->builtin);
return;
}
oprintf("%sfunction %s\n", ind, f->name); oprintf("%sfunction %s\n", ind, f->name);
strncat(ind, "\t", IND_BUFSZ); strncat(ind, "\t", IND_BUFSZ);
if (f->locals_count) if (f->locals_count)

30
ir.h
View file

@ -40,6 +40,8 @@ typedef struct ir_value_s {
lex_ctx context; lex_ctx context;
/* even the IR knows the subtype of a field */ /* even the IR knows the subtype of a field */
int fieldtype; int fieldtype;
/* and the output type of a function */
int outtype;
MEM_VECTOR_MAKE(struct ir_instr_s*, reads); MEM_VECTOR_MAKE(struct ir_instr_s*, reads);
MEM_VECTOR_MAKE(struct ir_instr_s*, writes); MEM_VECTOR_MAKE(struct ir_instr_s*, writes);
@ -79,6 +81,7 @@ MEM_VECTOR_PROTO_ALL(ir_value, struct ir_instr_s*, reads);
MEM_VECTOR_PROTO_ALL(ir_value, struct ir_instr_s*, writes); MEM_VECTOR_PROTO_ALL(ir_value, struct ir_instr_s*, writes);
bool GMQCC_WARN ir_value_set_float(ir_value*, float f); bool GMQCC_WARN ir_value_set_float(ir_value*, float f);
bool GMQCC_WARN ir_value_set_func(ir_value*, int f);
#if 0 #if 0
bool GMQCC_WARN ir_value_set_int(ir_value*, int i); bool GMQCC_WARN ir_value_set_int(ir_value*, int i);
#endif #endif
@ -100,6 +103,13 @@ bool ir_values_overlap(const ir_value*, const ir_value*);
void ir_value_dump(ir_value*, int (*oprintf)(const char*,...)); void ir_value_dump(ir_value*, int (*oprintf)(const char*,...));
void ir_value_dump_life(ir_value *self, int (*oprintf)(const char*,...)); void ir_value_dump_life(ir_value *self, int (*oprintf)(const char*,...));
/* A vector of IR values */
typedef struct {
MEM_VECTOR_MAKE(ir_value*, v);
} ir_value_vector;
MEM_VECTOR_PROTO(ir_value_vector, ir_value*, v);
/* PHI data */
typedef struct ir_phi_entry_s typedef struct ir_phi_entry_s
{ {
ir_value *value; ir_value *value;
@ -115,6 +125,7 @@ typedef struct ir_instr_s
struct ir_block_s* (bops[2]); struct ir_block_s* (bops[2]);
MEM_VECTOR_MAKE(ir_phi_entry_t, phi); MEM_VECTOR_MAKE(ir_phi_entry_t, phi);
MEM_VECTOR_MAKE(ir_value*, params);
/* For the temp-allocation */ /* For the temp-allocation */
size_t eid; size_t eid;
@ -128,6 +139,8 @@ void ir_instr_delete(ir_instr*);
MEM_VECTOR_PROTO(ir_value, ir_phi_entry_t, phi); MEM_VECTOR_PROTO(ir_value, ir_phi_entry_t, phi);
bool GMQCC_WARN ir_instr_op(ir_instr*, int op, ir_value *value, bool writing); bool GMQCC_WARN ir_instr_op(ir_instr*, int op, ir_value *value, bool writing);
MEM_VECTOR_PROTO(ir_value, ir_value*, params);
void ir_instr_dump(ir_instr* in, char *ind, int (*oprintf)(const char*,...)); void ir_instr_dump(ir_instr* in, char *ind, int (*oprintf)(const char*,...));
/* block */ /* block */
@ -164,6 +177,8 @@ MEM_VECTOR_PROTO_ALL(ir_block, ir_block*, entries);
ir_value* ir_block_create_binop(ir_block*, const char *label, int op, ir_value* ir_block_create_binop(ir_block*, const char *label, int op,
ir_value *left, ir_value *right); ir_value *left, ir_value *right);
ir_value* ir_block_create_unary(ir_block*, const char *label, int op,
ir_value *operand);
bool GMQCC_WARN ir_block_create_store_op(ir_block*, int op, ir_value *target, ir_value *what); bool GMQCC_WARN ir_block_create_store_op(ir_block*, int op, ir_value *target, ir_value *what);
bool GMQCC_WARN ir_block_create_store(ir_block*, ir_value *target, ir_value *what); bool GMQCC_WARN ir_block_create_store(ir_block*, ir_value *target, ir_value *what);
bool GMQCC_WARN ir_block_create_storep(ir_block*, ir_value *target, ir_value *what); bool GMQCC_WARN ir_block_create_storep(ir_block*, ir_value *target, ir_value *what);
@ -186,6 +201,9 @@ ir_value* ir_block_create_div(ir_block*, const char *label, ir_value *l, ir_valu
ir_instr* ir_block_create_phi(ir_block*, const char *label, int vtype); ir_instr* ir_block_create_phi(ir_block*, const char *label, int vtype);
ir_value* ir_phi_value(ir_instr*); ir_value* ir_phi_value(ir_instr*);
bool GMQCC_WARN ir_phi_add(ir_instr*, ir_block *b, ir_value *v); bool GMQCC_WARN ir_phi_add(ir_instr*, ir_block *b, ir_value *v);
ir_instr* ir_block_create_call(ir_block*, const char *label, ir_value *func);
ir_value* ir_call_value(ir_instr*);
bool GMQCC_WARN ir_call_param(ir_instr*, ir_value*);
bool GMQCC_WARN ir_block_create_return(ir_block*, ir_value *opt_value); bool GMQCC_WARN ir_block_create_return(ir_block*, ir_value *opt_value);
@ -209,10 +227,14 @@ void ir_block_dump(ir_block*, char *ind, int (*oprintf)(const char*,...));
typedef struct ir_function_s typedef struct ir_function_s
{ {
char *name; char *name;
int retype; int outtype;
MEM_VECTOR_MAKE(int, params); MEM_VECTOR_MAKE(int, params);
MEM_VECTOR_MAKE(ir_block*, blocks); MEM_VECTOR_MAKE(ir_block*, blocks);
int builtin;
ir_value *value;
/* values generated from operations /* values generated from operations
* which might get optimized away, so anything * which might get optimized away, so anything
* in there needs to be deleted in the dtor. * in there needs to be deleted in the dtor.
@ -235,7 +257,7 @@ typedef struct ir_function_s
struct ir_builder_s *owner; struct ir_builder_s *owner;
} ir_function; } ir_function;
ir_function* ir_function_new(struct ir_builder_s *owner); ir_function* ir_function_new(struct ir_builder_s *owner, int returntype);
void ir_function_delete(ir_function*); void ir_function_delete(ir_function*);
bool GMQCC_WARN ir_function_collect_value(ir_function*, ir_value *value); bool GMQCC_WARN ir_function_collect_value(ir_function*, ir_value *value);
@ -245,7 +267,7 @@ MEM_VECTOR_PROTO(ir_function, int, params);
MEM_VECTOR_PROTO(ir_function, ir_block*, blocks); MEM_VECTOR_PROTO(ir_function, ir_block*, blocks);
ir_value* ir_function_get_local(ir_function *self, const char *name); ir_value* ir_function_get_local(ir_function *self, const char *name);
ir_value* ir_function_create_local(ir_function *self, const char *name, int vtype); ir_value* ir_function_create_local(ir_function *self, const char *name, int vtype, bool param);
bool GMQCC_WARN ir_function_finalize(ir_function*); bool GMQCC_WARN ir_function_finalize(ir_function*);
/* /*
@ -275,7 +297,7 @@ MEM_VECTOR_PROTO(ir_builder, ir_function*, functions);
MEM_VECTOR_PROTO(ir_builder, ir_value*, globals); MEM_VECTOR_PROTO(ir_builder, ir_value*, globals);
ir_function* ir_builder_get_function(ir_builder*, const char *fun); ir_function* ir_builder_get_function(ir_builder*, const char *fun);
ir_function* ir_builder_create_function(ir_builder*, const char *name); ir_function* ir_builder_create_function(ir_builder*, const char *name, int outtype);
ir_value* ir_builder_get_global(ir_builder*, const char *fun); ir_value* ir_builder_get_global(ir_builder*, const char *fun);
ir_value* ir_builder_create_global(ir_builder*, const char *name, int vtype); ir_value* ir_builder_create_global(ir_builder*, const char *name, int vtype);

View file

@ -28,6 +28,13 @@ do { \
MKGLOBAL(name); \ MKGLOBAL(name); \
} while(0) } while(0)
#define MKCONSTSTRING(name, value) \
do { \
name->isconst = true; \
name->constval.vstring = util_strdup(value); \
MKGLOBAL(name); \
} while(0)
#define STATE(a) \ #define STATE(a) \
do { \ do { \
ast_expression *exp = (ast_expression*)(a); \ ast_expression *exp = (ast_expression*)(a); \
@ -40,6 +47,17 @@ do { \
#define BIN(op, a, b) \ #define BIN(op, a, b) \
(ast_expression*)ast_binary_new(ctx, INSTR_##op, (ast_expression*)(a), (ast_expression*)(b)) (ast_expression*)ast_binary_new(ctx, INSTR_##op, (ast_expression*)(a), (ast_expression*)(b))
#define CALL(what) \
do { \
ast_call *call = ast_call_new(ctx, (ast_expression*)what); \
#define CALLPARAM(x) \
assert(ast_call_params_add(call, (ast_expression*)x));
#define ENDCALL() \
STATE(call); \
} while(0)
#define WHILE(cond) \ #define WHILE(cond) \
do { \ do { \
ast_expression *wh_cond = (ast_expression*)(cond); \ ast_expression *wh_cond = (ast_expression*)(cond); \
@ -56,18 +74,51 @@ do { \
STATE(loop); \ STATE(loop); \
} while(0) } while(0)
#define FUNCTION(name) \ #define BUILTIN(name, outtype, number) \
do { \ do { \
ast_function *func_##name; \ ast_function *func_##name; \
ast_block *my_funcblock; \ ast_value *thisfuncval; \
DEFVAR(var_##name); \ ast_function *thisfunc; \
VARnamed(TYPE_FUNCTION, var_##name, name); \ DEFVAR(return_##name); \
MKGLOBAL(var_##name); \ VARnamed(TYPE_FUNCTION, name, name); \
func_##name = ast_function_new(ctx, #name, var_##name); \ VARnamed(outtype, return_##name, "#returntype"); \
assert(functions_add(func_##name) >= 0); \ name->expression.next = (ast_expression*)return_##name; \
my_funcblock = ast_block_new(ctx); \ MKGLOBAL(name); \
assert(my_funcblock); \ func_##name = ast_function_new(ctx, #name, name); \
assert(ast_function_blocks_add(func_##name, my_funcblock)); \ thisfunc = func_##name; \
(void)thisfunc; \
thisfuncval = name; \
(void)thisfuncval; \
assert(functions_add(func_##name) >= 0); \
func_##name->builtin = number;
#define ENDBUILTIN() } while(0)
#define PARAM(ptype, name) \
do { \
DEFVAR(parm); \
VARnamed(ptype, parm, name); \
assert(ast_value_params_add(thisfuncval, parm)); \
} while(0)
#define FUNCTION(name, outtype) \
do { \
ast_function *thisfunc; \
ast_function *func_##name; \
ast_block *my_funcblock; \
DEFVAR(var_##name); \
DEFVAR(return_##name); \
VARnamed(TYPE_FUNCTION, var_##name, name); \
VARnamed(outtype, return_##name, "#returntype"); \
var_##name->expression.next = (ast_expression*)return_##name; \
MKGLOBAL(var_##name); \
func_##name = ast_function_new(ctx, #name, var_##name); \
thisfunc = func_##name; \
(void)thisfunc; \
assert(functions_add(func_##name) >= 0); \
my_funcblock = ast_block_new(ctx); \
assert(my_funcblock); \
assert(ast_function_blocks_add(func_##name, my_funcblock)); \
curblock = my_funcblock; curblock = my_funcblock;
#define MKLOCAL(var) \ #define MKLOCAL(var) \

View file

@ -27,28 +27,45 @@ int main()
DEFVAR(f0); DEFVAR(f0);
DEFVAR(f1); DEFVAR(f1);
DEFVAR(f5); DEFVAR(f5);
DEFVAR(sHello);
DEFVAR(print);
/* opts_debug = true; */
BUILTIN(print, TYPE_VOID, -1);
PARAM(TYPE_STRING, text);
ENDBUILTIN();
TESTINIT(); TESTINIT();
VAR(TYPE_FLOAT, f0); VAR(TYPE_FLOAT, f0);
VAR(TYPE_FLOAT, f1); VAR(TYPE_FLOAT, f1);
VAR(TYPE_FLOAT, f5); VAR(TYPE_FLOAT, f5);
VAR(TYPE_STRING, sHello);
MKCONSTFLOAT(f0, 0.0); MKCONSTFLOAT(f0, 0.0);
MKCONSTFLOAT(f1, 1.0); MKCONSTFLOAT(f1, 1.0);
MKCONSTFLOAT(f5, 5.0); MKCONSTFLOAT(f5, 5.0);
MKCONSTSTRING(sHello, "Hello, World\n");
FUNCTION(main); FUNCTION(foo, TYPE_VOID);
ENDFUNCTION(foo);
VAR(TYPE_FLOAT, vi); FUNCTION(main, TYPE_VOID);
VAR(TYPE_FLOAT, vx);
MKLOCAL(vi); VAR(TYPE_FLOAT, vi);
MKLOCAL(vx); VAR(TYPE_FLOAT, vx);
STATE(ASSIGN(STORE_F, vi, f0)); MKLOCAL(vi);
WHILE(BIN(LT, vi, f5)); MKLOCAL(vx);
STATE(ASSIGN(STORE_F, vx, BIN(MUL_F, vi, f5)));
STATE(ASSIGN(STORE_F, vi, BIN(ADD_F, vi, f1))); STATE(ASSIGN(STORE_F, vi, f0));
ENDWHILE(); WHILE(BIN(LT, vi, f5));
STATE(ASSIGN(STORE_F, vx, BIN(MUL_F, vi, f5)));
STATE(ASSIGN(STORE_F, vi, BIN(ADD_F, vi, f1)));
ENDWHILE();
CALL(print)
CALLPARAM(sHello)
ENDCALL();
ENDFUNCTION(main); ENDFUNCTION(main);