diff --git a/ast.c b/ast.c index 49446a1..61b89e4 100644 --- a/ast.c +++ b/ast.c @@ -57,12 +57,18 @@ static void ast_expression_init(ast_expression *self, self->expression.codegen = codegen; self->expression.vtype = TYPE_VOID; self->expression.next = NULL; + MEM_VECTOR_INIT(&self->expression, params); } static void ast_expression_delete(ast_expression *self) { + size_t i; if (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) @@ -71,9 +77,26 @@ static void ast_expression_delete_full(ast_expression *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) { - const ast_expression_common *cpex; + size_t i; + const ast_expression_common *fromex; ast_expression_common *selfex; 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); - cpex = &ex->expression; + fromex = &ex->expression; selfex = &self->expression; - selfex->vtype = cpex->vtype; - if (cpex->next) + /* This may never be codegen()d */ + 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) { - mem_d(self); + ast_expression_delete_full(self); return NULL; } } else selfex->next = NULL; - /* This may never be codegen()d */ - selfex->codegen = NULL; + for (i = 0; i < fromex->params_count; ++i) { + 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; } } @@ -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->expression.vtype = t; self->expression.next = NULL; - MEM_VECTOR_INIT(self, params); self->isconst = false; 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; } -MEM_VEC_FUNCTIONS(ast_value, ast_value*, params) void ast_value_delete(ast_value* self) { - size_t i; if (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) { switch (self->expression.vtype) { @@ -152,6 +178,11 @@ void ast_value_delete(ast_value* 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) { if (self->name) @@ -181,6 +212,42 @@ void ast_binary_delete(ast_binary *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) { const ast_expression *outtype; @@ -308,6 +375,34 @@ void ast_loop_delete(ast_loop *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_value *dest, ast_expression *source) { @@ -356,6 +451,19 @@ void ast_block_delete(ast_block *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_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); self->labelcount = 0; + self->builtin = 0; self->ir_func = 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 * on all the globals. */ - if (!self->ir_v) + if (!self->ir_v) { + printf("ast_value used before generated (%s)\n", self->name); return false; + } *out = self->ir_v; return true; } @@ -468,11 +579,12 @@ bool ast_global_codegen(ast_value *self, ir_builder *ir) ir_value *v = NULL; 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) return false; self->constval.vfunc->ir_func = func; + self->ir_v = func->value; /* The function is filled later on ast_function_codegen... */ return true; } @@ -497,10 +609,11 @@ bool ast_global_codegen(ast_value *self, ir_builder *ir) goto error; break; case TYPE_FUNCTION: + printf("global of type function not properly generated\n"); + goto error; /* Cannot generate an IR value for a function, * need a pointer pointing to a function rather. */ - goto error; default: printf("TODO: global constant type %i\n", self->expression.vtype); break; @@ -516,7 +629,7 @@ error: /* clean up */ 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; if (self->isconst && self->expression.vtype == TYPE_FUNCTION) @@ -527,7 +640,7 @@ bool ast_local_codegen(ast_value *self, ir_function *func) 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) return false; @@ -568,6 +681,7 @@ bool ast_function_codegen(ast_function *self, ir_builder *ir) { ir_function *irf; ir_value *dummy; + ast_expression_common *ec; size_t i; irf = self->ir_func; @@ -576,6 +690,23 @@ bool ast_function_codegen(ast_function *self, ir_builder *ir) 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"); if (!self->curblock) return false; @@ -591,7 +722,9 @@ bool ast_function_codegen(ast_function *self, ir_builder *ir) { if (!self->vtype->expression.next || self->vtype->expression.next->expression.vtype == TYPE_VOID) + { return ir_block_create_return(self->curblock, NULL); + } else { /* error("missing return"); */ @@ -628,7 +761,7 @@ bool ast_block_codegen(ast_block *self, ast_function *func, bool lvalue, ir_valu /* generate locals */ 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; } @@ -700,6 +833,50 @@ bool ast_binary_codegen(ast_binary *self, ast_function *func, bool lvalue, ir_va 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) { ast_expression_codegen *cgen; @@ -1148,3 +1325,56 @@ bool ast_loop_codegen(ast_loop *self, ast_function *func, bool lvalue, ir_value 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(¶ms, 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, ¶m)) + goto error; + if (!param) + goto error; + if (!ir_value_vector_v_add(¶ms, 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(¶ms, v); + return true; +error: + MEM_VECTOR_CLEAR(¶ms, v); + return false; +} diff --git a/ast.h b/ast.h index d0ce67a..187ec88 100644 --- a/ast.h +++ b/ast.h @@ -40,6 +40,9 @@ typedef struct ast_entfield_s ast_entfield; typedef struct ast_ifthen_s ast_ifthen; typedef struct ast_ternary_s ast_ternary; 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 */ @@ -78,7 +81,9 @@ typedef struct ast_expression_codegen *codegen; int vtype; ast_expression *next; + MEM_VECTOR_MAKE(ast_value*, params); } ast_expression_common; +MEM_VECTOR_PROTO(ast_expression_common, ast_value*, params); /* Value * @@ -109,12 +114,8 @@ struct ast_value_s } constval; 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); /* This will NOT delete an underlying ast_function */ 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_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 GMQCC_WARN ast_value_params_add(ast_value*, ast_value*); + /* Binary * * 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**); +/* 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 * * 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**); +/* 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 * */ @@ -296,6 +357,7 @@ struct ast_block_s }; ast_block* ast_block_new(lex_ctx ctx); 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_expression*, exprs); @@ -319,6 +381,8 @@ struct ast_function_s ast_value *vtype; const char *name; + int builtin; + ir_function *ir_func; ir_block *curblock; ir_block *breakblock; diff --git a/gmqcc.h b/gmqcc.h index e9e153e..90d1e05 100644 --- a/gmqcc.h +++ b/gmqcc.h @@ -77,7 +77,7 @@ * This is a hack to silent clang regarding empty * 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 @@ -371,6 +371,13 @@ enum { }; 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 { uint32_t offset; /* Offset in file of where data begins */ @@ -605,7 +612,7 @@ static const struct { { "EQ_V" , 0, 4 }, { "EQ_S" , 0, 4 }, { "EQ_E" , 0, 4 }, - { "ES_FNC" , 0, 6 }, + { "EQ_FNC" , 0, 6 }, { "NE_F" , 0, 4 }, { "NE_V" , 0, 4 }, { "NE_S" , 0, 4 }, @@ -694,7 +701,7 @@ extern int opts_compiler; size_t name##_count; \ 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) \ { \ Twhat *reall; \ @@ -716,7 +723,7 @@ bool GMQCC_WARN Tself##_##mem##_add(Tself *self, Twhat f) \ 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) \ { \ size_t i; \ @@ -741,7 +748,7 @@ bool GMQCC_WARN Tself##_##mem##_remove(Tself *self, size_t idx) \ 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) \ { \ size_t i; \ @@ -756,7 +763,7 @@ bool GMQCC_WARN Tself##_##mem##_find(Tself *self, Twhat obj, size_t *idx) \ 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) \ { \ Twhat *reall; \ @@ -782,7 +789,7 @@ bool GMQCC_WARN Tself##_##mem##_append(Tself *s, Twhat *p, size_t c) \ 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) \ { \ Twhat *reall; \ @@ -806,7 +813,7 @@ bool GMQCC_WARN Tself##_##mem##_resize(Tself *s, size_t c) \ return true; \ } -#define _MEM_VEC_FUN_CLEAR(Tself, mem) \ +#define MEM_VEC_FUN_CLEAR(Tself, mem) \ void Tself##_##mem##_clear(Tself *self) \ { \ if (!self->mem) \ @@ -832,18 +839,20 @@ void Tself##_##mem##_clear(Tself *self) \ } #define MEM_VEC_FUNCTIONS(Tself, Twhat, mem) \ -_MEM_VEC_FUN_REMOVE(Tself, Twhat, mem) \ -_MEM_VEC_FUN_ADD(Tself, Twhat, mem) +MEM_VEC_FUN_REMOVE(Tself, Twhat, mem) \ +MEM_VEC_FUN_ADD(Tself, Twhat, mem) #define MEM_VEC_FUNCTIONS_ALL(Tself, Twhat, mem) \ MEM_VEC_FUNCTIONS(Tself, Twhat, mem) \ -_MEM_VEC_FUN_CLEAR(Tself, mem) \ -_MEM_VEC_FUN_FIND(Tself, Twhat, mem) +MEM_VEC_FUN_CLEAR(Tself, mem) \ +MEM_VEC_FUN_FIND(Tself, Twhat, mem) enum store_types { store_global, 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 { diff --git a/ir.c b/ir.c index d81cdce..f32f9d4 100644 --- a/ir.c +++ b/ir.c @@ -44,6 +44,38 @@ size_t type_sizeof[TYPE_COUNT] = { 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 */ @@ -108,20 +140,32 @@ ir_function* ir_builder_get_function(ir_builder *self, const char *name) 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); if (fn) { return NULL; } - fn = ir_function_new(self); + fn = ir_function_new(self, outtype); if (!ir_function_set_name(fn, name) || !ir_builder_functions_add(self, fn) ) { ir_function_delete(fn); 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; } @@ -159,7 +203,7 @@ void ir_function_enumerate(ir_function*); bool ir_function_calculate_liferanges(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; self = (ir_function*)mem_a(sizeof(*self)); @@ -175,7 +219,9 @@ ir_function* ir_function_new(ir_builder* owner) self->owner = owner; self->context.file = "<@no context>"; 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, blocks); 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_block*, blocks) 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) { @@ -215,6 +262,8 @@ void ir_function_delete(ir_function *self) ir_value_delete(self->locals[i]); MEM_VECTOR_CLEAR(self, locals); + /* self->value is deleted by the builder */ + 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) { + if (self->builtin) + return true; + if (!ir_function_naive_phi(self)) return false; @@ -259,14 +311,21 @@ ir_value* ir_function_get_local(ir_function *self, const char *name) 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); if (ve) { 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)) { ir_value_delete(ve); return NULL; @@ -356,11 +415,13 @@ ir_instr* ir_instr_new(ir_block* owner, int op) self->bops[0] = NULL; self->bops[1] = NULL; MEM_VECTOR_INIT(self, phi); + MEM_VECTOR_INIT(self, params); self->eid = 0; return self; } 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) { @@ -374,14 +435,22 @@ void ir_instr_delete(ir_instr *self) for (i = 0; i < self->phi_count; ++i) { size_t 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_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); - if (ir_instr_op(self, 0, NULL, false)) GMQCC_SUPRESS_EMPTY_BODY; - if (ir_instr_op(self, 1, NULL, false)) GMQCC_SUPRESS_EMPTY_BODY; - if (ir_instr_op(self, 2, NULL, false)) GMQCC_SUPRESS_EMPTY_BODY; + for (i = 0; i < self->params_count; ++i) { + size_t idx; + 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); } @@ -423,6 +492,7 @@ ir_value* ir_value_var(const char *name, int storetype, int vtype) self = (ir_value*)mem_a(sizeof(*self)); self->vtype = vtype; self->fieldtype = TYPE_VOID; + self->outtype = TYPE_VOID; self->store = storetype; MEM_VECTOR_INIT(self, reads); MEM_VECTOR_INIT(self, writes); @@ -486,6 +556,15 @@ bool ir_value_set_float(ir_value *self, float f) 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) { if (self->vtype != TYPE_VECTOR) @@ -773,46 +852,14 @@ bool ir_block_create_store(ir_block *self, ir_value *target, ir_value *what) else vtype = target->vtype; - switch (vtype) { - case TYPE_FLOAT: #if 0 - if (what->vtype == TYPE_INTEGER) - op = INSTR_CONV_ITOF; - else + if (vtype == TYPE_FLOAT && what->vtype == TYPE_INTEGER) + op = INSTR_CONV_ITOF; + else if (vtype == TYPE_INTEGER && what->vtype == TYPE_FLOAT) + op = INSTR_CONV_FTOI; #endif - op = INSTR_STORE_F; - 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; - } + op = type_store_instr[vtype]; + 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; - switch (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; - } + op = type_storep_instr[vtype]; + 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); } +/* 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 */ 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); } +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, 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) 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 * there as welli @@ -1565,6 +1656,9 @@ bool ir_function_allocate_locals(ir_function *self) function_allocator alloc; + if (!self->locals_count) + return true; + MEM_VECTOR_INIT(&alloc, locals); MEM_VECTOR_INIT(&alloc, sizes); MEM_VECTOR_INIT(&alloc, positions); @@ -1611,6 +1705,10 @@ bool ir_function_allocate_locals(ir_function *self) if (!function_allocator_positions_add(&alloc, 0)) goto error; + if (alloc.sizes_count) + pos = alloc.positions[0] + alloc.sizes[0]; + else + pos = 0; for (i = 1; i < alloc.sizes_count; ++i) { 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]; /* We only care about locals */ + /* we also calculate parameter liferanges so that locals + * can take up parameter slots */ if (value->store != store_value && - value->store != store_local) + value->store != store_local && + value->store != store_param) continue; /* read operands */ @@ -2109,8 +2210,56 @@ tailcall: } if (instr->opcode >= INSTR_CALL0 && instr->opcode <= INSTR_CALL8) { - printf("TODO: call instruction\n"); - return false; + /* Trivial call translation: + * 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) { @@ -2138,10 +2287,8 @@ tailcall: stmt.o1.u1 = stmt.o3.u1; stmt.o3.u1 = 0; } - else if ((stmt.opcode >= INSTR_STORE_F && - stmt.opcode <= INSTR_STORE_FNC) || - (stmt.opcode >= INSTR_NOT_F && - stmt.opcode <= INSTR_NOT_FNC)) + else if (stmt.opcode >= INSTR_STORE_F && + stmt.opcode <= INSTR_STORE_FNC) { /* 2-operand instructions with A -> B */ stmt.o2.u1 = stmt.o3.u1; @@ -2157,6 +2304,7 @@ tailcall: static bool gen_function_code(ir_function *self) { ir_block *block; + prog_section_statement stmt; /* Starting from entry point, we generate blocks "as they come" * 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); 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; } @@ -2185,8 +2341,7 @@ static bool gen_global_function(ir_builder *ir, ir_value *global) size_t i; size_t local_var_end; - if (!global->isconst || - !global->constval.vfunc) + if (!global->isconst || (!global->constval.vfunc)) { printf("Invalid state of function-global: not constant: %s\n", global->name); return false; @@ -2202,10 +2357,8 @@ static bool gen_global_function(ir_builder *ir, ir_value *global) for (i = 0;i < 8; ++i) { if (i >= fun.nargs) fun.argsize[i] = 0; - else if (irfun->params[i] == TYPE_VECTOR) - fun.argsize[i] = 3; else - fun.argsize[i] = 1; + fun.argsize[i] = type_sizeof[irfun->params[i]]; } fun.firstlocal = code_globals_elements; @@ -2234,10 +2387,14 @@ static bool gen_global_function(ir_builder *ir, ir_value *global) code_globals_add(0); } - fun.entry = code_statements_elements; - if (!gen_function_code(irfun)) { - printf("Failed to generate code for function %s\n", irfun->name); - return false; + if (irfun->builtin) + fun.entry = irfun->builtin; + else { + 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); @@ -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) { + size_t i; int32_t *iptr; prog_section_def def; @@ -2289,31 +2447,43 @@ static bool ir_builder_gen_global(ir_builder *self, ir_value *global) } case TYPE_VECTOR: { + size_t d; if (code_defs_add(def) < 0) return false; if (global->isconst) { iptr = (int32_t*)&global->constval.vvec; 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; + for (d = 1; d < type_sizeof[global->vtype]; ++d) + { + if (code_globals_add(iptr[d]) < 0) + return false; + } } else { 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; + for (d = 1; d < type_sizeof[global->vtype]; ++d) + { + if (code_globals_add(0) < 0) + return false; + } } return global->code.globaladdr >= 0; } case TYPE_FUNCTION: if (code_defs_add(def) < 0) return false; + global->code.globaladdr = code_globals_elements; code_globals_add(code_functions_elements); return gen_global_function(self, global); case TYPE_VARIANT: /* assume biggest type */ global->code.globaladdr = code_globals_add(0); - code_globals_add(0); - code_globals_add(0); + for (i = 1; i < type_sizeof[TYPE_VARIANT]; ++i) + code_globals_add(0); return true; default: /* 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(); - /* 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) { 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*, ...)) { 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); strncat(ind, "\t", IND_BUFSZ); if (f->locals_count) diff --git a/ir.h b/ir.h index a611dba..9eab51f 100644 --- a/ir.h +++ b/ir.h @@ -40,6 +40,8 @@ typedef struct ir_value_s { lex_ctx context; /* even the IR knows the subtype of a field */ 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*, 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); bool GMQCC_WARN ir_value_set_float(ir_value*, float f); +bool GMQCC_WARN ir_value_set_func(ir_value*, int f); #if 0 bool GMQCC_WARN ir_value_set_int(ir_value*, int i); #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_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 { ir_value *value; @@ -115,6 +125,7 @@ typedef struct ir_instr_s struct ir_block_s* (bops[2]); MEM_VECTOR_MAKE(ir_phi_entry_t, phi); + MEM_VECTOR_MAKE(ir_value*, params); /* For the temp-allocation */ size_t eid; @@ -128,6 +139,8 @@ void ir_instr_delete(ir_instr*); 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); +MEM_VECTOR_PROTO(ir_value, ir_value*, params); + void ir_instr_dump(ir_instr* in, char *ind, int (*oprintf)(const char*,...)); /* 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 *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(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_value* ir_phi_value(ir_instr*); 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); @@ -209,10 +227,14 @@ void ir_block_dump(ir_block*, char *ind, int (*oprintf)(const char*,...)); typedef struct ir_function_s { char *name; - int retype; + int outtype; MEM_VECTOR_MAKE(int, params); MEM_VECTOR_MAKE(ir_block*, blocks); + int builtin; + + ir_value *value; + /* values generated from operations * which might get optimized away, so anything * in there needs to be deleted in the dtor. @@ -235,7 +257,7 @@ typedef struct ir_function_s struct ir_builder_s *owner; } 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*); 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); 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*); /* @@ -275,7 +297,7 @@ MEM_VECTOR_PROTO(ir_builder, ir_function*, functions); MEM_VECTOR_PROTO(ir_builder, ir_value*, globals); 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_create_global(ir_builder*, const char *name, int vtype); diff --git a/test/ast-macros.h b/test/ast-macros.h index d4ed607..c17b753 100644 --- a/test/ast-macros.h +++ b/test/ast-macros.h @@ -28,6 +28,13 @@ do { \ MKGLOBAL(name); \ } while(0) +#define MKCONSTSTRING(name, value) \ +do { \ + name->isconst = true; \ + name->constval.vstring = util_strdup(value); \ + MKGLOBAL(name); \ +} while(0) + #define STATE(a) \ do { \ ast_expression *exp = (ast_expression*)(a); \ @@ -40,6 +47,17 @@ do { \ #define BIN(op, a, 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) \ do { \ ast_expression *wh_cond = (ast_expression*)(cond); \ @@ -56,18 +74,51 @@ do { \ STATE(loop); \ } while(0) -#define FUNCTION(name) \ -do { \ - ast_function *func_##name; \ - ast_block *my_funcblock; \ - DEFVAR(var_##name); \ - VARnamed(TYPE_FUNCTION, var_##name, name); \ - MKGLOBAL(var_##name); \ - func_##name = ast_function_new(ctx, #name, var_##name); \ - assert(functions_add(func_##name) >= 0); \ - my_funcblock = ast_block_new(ctx); \ - assert(my_funcblock); \ - assert(ast_function_blocks_add(func_##name, my_funcblock)); \ +#define BUILTIN(name, outtype, number) \ +do { \ + ast_function *func_##name; \ + ast_value *thisfuncval; \ + ast_function *thisfunc; \ + DEFVAR(return_##name); \ + VARnamed(TYPE_FUNCTION, name, name); \ + VARnamed(outtype, return_##name, "#returntype"); \ + name->expression.next = (ast_expression*)return_##name; \ + MKGLOBAL(name); \ + func_##name = ast_function_new(ctx, #name, name); \ + 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; #define MKLOCAL(var) \ diff --git a/test/ast-test.c b/test/ast-test.c index 792ad77..c57e436 100644 --- a/test/ast-test.c +++ b/test/ast-test.c @@ -27,28 +27,45 @@ int main() DEFVAR(f0); DEFVAR(f1); DEFVAR(f5); + DEFVAR(sHello); + DEFVAR(print); + + /* opts_debug = true; */ + +BUILTIN(print, TYPE_VOID, -1); +PARAM(TYPE_STRING, text); +ENDBUILTIN(); TESTINIT(); VAR(TYPE_FLOAT, f0); VAR(TYPE_FLOAT, f1); VAR(TYPE_FLOAT, f5); +VAR(TYPE_STRING, sHello); MKCONSTFLOAT(f0, 0.0); MKCONSTFLOAT(f1, 1.0); MKCONSTFLOAT(f5, 5.0); +MKCONSTSTRING(sHello, "Hello, World\n"); -FUNCTION(main); +FUNCTION(foo, TYPE_VOID); +ENDFUNCTION(foo); -VAR(TYPE_FLOAT, vi); -VAR(TYPE_FLOAT, vx); +FUNCTION(main, TYPE_VOID); -MKLOCAL(vi); -MKLOCAL(vx); + VAR(TYPE_FLOAT, vi); + VAR(TYPE_FLOAT, vx); -STATE(ASSIGN(STORE_F, vi, f0)); -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(); + MKLOCAL(vi); + MKLOCAL(vx); + + STATE(ASSIGN(STORE_F, vi, f0)); + 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);