X-Git-Url: https://git.xonotic.org/?a=blobdiff_plain;f=ast.c;h=a622db649953e4c540844ace93e3c7abb5b4fd6a;hb=ca52ecc20af641a20b3d3cdb0921f55c27541491;hp=58987b9c29f164fcec39556fd70047d2c8deb523;hpb=ca033e5acd2c69ee2b4a96046605e0e41f5f597b;p=xonotic%2Fgmqcc.git diff --git a/ast.c b/ast.c index 58987b9..a622db6 100644 --- a/ast.c +++ b/ast.c @@ -331,7 +331,8 @@ 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; - self->isconst = false; + self->constant = false; + self->hasvalue = false; self->uses = 0; memset(&self->constval, 0, sizeof(self->constval)); @@ -349,7 +350,7 @@ void ast_value_delete(ast_value* self) { if (self->name) mem_d((void*)self->name); - if (self->isconst) { + if (self->hasvalue) { switch (self->expression.vtype) { case TYPE_STRING: @@ -434,6 +435,8 @@ ast_binstore* ast_binstore_new(lex_ctx ctx, int storop, int op, self->dest = left; self->source = right; + self->keep_dest = false; + self->expression.vtype = left->expression.vtype; if (left->expression.next) { self->expression.next = ast_type_copy(ctx, left); @@ -450,7 +453,8 @@ ast_binstore* ast_binstore_new(lex_ctx ctx, int storop, int op, void ast_binstore_delete(ast_binstore *self) { - ast_unref(self->dest); + if (!self->keep_dest) + ast_unref(self->dest); ast_unref(self->source); ast_expression_delete((ast_expression*)self); mem_d(self); @@ -799,6 +803,55 @@ void ast_switch_delete(ast_switch *self) mem_d(self); } +ast_label* ast_label_new(lex_ctx ctx, const char *name) +{ + ast_instantiate(ast_label, ctx, ast_label_delete); + ast_expression_init((ast_expression*)self, (ast_expression_codegen*)&ast_label_codegen); + + self->name = util_strdup(name); + self->irblock = NULL; + self->gotos = NULL; + + return self; +} + +void ast_label_delete(ast_label *self) +{ + mem_d((void*)self->name); + vec_free(self->gotos); + ast_expression_delete((ast_expression*)self); + mem_d(self); +} + +void ast_label_register_goto(ast_label *self, ast_goto *g) +{ + vec_push(self->gotos, g); +} + +ast_goto* ast_goto_new(lex_ctx ctx, const char *name) +{ + ast_instantiate(ast_goto, ctx, ast_goto_delete); + ast_expression_init((ast_expression*)self, (ast_expression_codegen*)&ast_goto_codegen); + + self->name = util_strdup(name); + self->target = NULL; + self->irblock_from = NULL; + + return self; +} + +void ast_goto_delete(ast_goto *self) +{ + mem_d((void*)self->name); + ast_expression_delete((ast_expression*)self); + mem_d(self); +} + +void ast_goto_set_label(ast_goto *self, ast_label *label) +{ + self->target = label; +} + ast_call* ast_call_new(lex_ctx ctx, ast_expression *funcexpr) { @@ -950,12 +1003,12 @@ ast_function* ast_function_new(lex_ctx ctx, const char *name, ast_value *vtype) ast_instantiate(ast_function, ctx, ast_function_delete); if (!vtype || - vtype->isconst || + vtype->hasvalue || vtype->expression.vtype != TYPE_FUNCTION) { asterror(ast_ctx(self), "internal error: ast_function_new condition %i %i type=%i", (int)!vtype, - (int)vtype->isconst, + (int)vtype->hasvalue, vtype->expression.vtype); mem_d(self); return NULL; @@ -974,7 +1027,7 @@ ast_function* ast_function_new(lex_ctx ctx, const char *name, ast_value *vtype) self->breakblock = NULL; self->continueblock = NULL; - vtype->isconst = true; + vtype->hasvalue = true; vtype->constval.vfunc = self; return self; @@ -987,7 +1040,7 @@ void ast_function_delete(ast_function *self) mem_d((void*)self->name); if (self->vtype) { /* ast_value_delete(self->vtype); */ - self->vtype->isconst = false; + self->vtype->hasvalue = false; self->vtype->constval.vfunc = NULL; /* We use unref - if it was stored in a global table it is supposed * to be deleted from *there* @@ -1055,7 +1108,7 @@ bool ast_global_codegen(ast_value *self, ir_builder *ir, bool isfield) { ir_value *v = NULL; - if (self->isconst && self->expression.vtype == TYPE_FUNCTION) + if (self->hasvalue && self->expression.vtype == TYPE_FUNCTION) { ir_function *func = ir_builder_create_function(ir, self->name, self->expression.next->expression.vtype); if (!func) @@ -1072,7 +1125,7 @@ bool ast_global_codegen(ast_value *self, ir_builder *ir, bool isfield) if (isfield && self->expression.vtype == TYPE_FIELD) { ast_expression *fieldtype = self->expression.next; - if (self->isconst) { + if (self->hasvalue) { asterror(ast_ctx(self), "TODO: constant field pointers with value"); goto error; } @@ -1100,7 +1153,7 @@ bool ast_global_codegen(ast_value *self, ir_builder *ir, bool isfield) v = ir_builder_create_field(ir, self->name, vtype); if (!v) { - asterror(ast_ctx(self), "ir_builder_create_global failed"); + asterror(ast_ctx(self), "ir_builder_create_global failed on `%s`", self->name); return false; } if (vtype == TYPE_FIELD) @@ -1119,7 +1172,7 @@ bool ast_global_codegen(ast_value *self, ir_builder *ir, bool isfield) array->ir_values[ai] = ir_builder_create_field(ir, name, vtype); if (!array->ir_values[ai]) { mem_d(name); - asterror(ast_ctx(self), "ir_builder_create_global failed"); + asterror(ast_ctx(self), "ir_builder_create_global failed on `%s`", name); return false; } if (vtype == TYPE_FIELD) @@ -1153,7 +1206,7 @@ bool ast_global_codegen(ast_value *self, ir_builder *ir, bool isfield) v = ir_builder_create_global(ir, self->name, vtype); if (!v) { - asterror(ast_ctx(self), "ir_builder_create_global failed"); + asterror(ast_ctx(self), "ir_builder_create_global failed `%s`", self->name); return false; } if (vtype == TYPE_FIELD) @@ -1171,7 +1224,7 @@ bool ast_global_codegen(ast_value *self, ir_builder *ir, bool isfield) self->ir_values[ai] = ir_builder_create_global(ir, name, vtype); if (!self->ir_values[ai]) { mem_d(name); - asterror(ast_ctx(self), "ir_builder_create_global failed"); + asterror(ast_ctx(self), "ir_builder_create_global failed `%s`", name); return false; } if (vtype == TYPE_FIELD) @@ -1187,7 +1240,7 @@ bool ast_global_codegen(ast_value *self, ir_builder *ir, bool isfield) */ v = ir_builder_create_global(ir, self->name, self->expression.vtype); if (!v) { - asterror(ast_ctx(self), "ir_builder_create_global failed"); + asterror(ast_ctx(self), "ir_builder_create_global failed on `%s`", self->name); return false; } if (self->expression.vtype == TYPE_FIELD) @@ -1195,7 +1248,7 @@ bool ast_global_codegen(ast_value *self, ir_builder *ir, bool isfield) v->context = ast_ctx(self); } - if (self->isconst) { + if (self->hasvalue) { switch (self->expression.vtype) { case TYPE_FLOAT: @@ -1237,7 +1290,7 @@ error: /* clean up */ bool ast_local_codegen(ast_value *self, ir_function *func, bool param) { ir_value *v = NULL; - if (self->isconst && self->expression.vtype == TYPE_FUNCTION) + if (self->hasvalue && self->expression.vtype == TYPE_FUNCTION) { /* Do we allow local functions? I think not... * this is NOT a function pointer atm. @@ -1287,7 +1340,7 @@ bool ast_local_codegen(ast_value *self, ir_function *func, bool param) snprintf(name + namelen, 16, "[%u]", (unsigned int)ai); self->ir_values[ai] = ir_function_create_local(func, name, vtype, param); if (!self->ir_values[ai]) { - asterror(ast_ctx(self), "ir_builder_create_global failed"); + asterror(ast_ctx(self), "ir_builder_create_global failed on `%s`", name); return false; } if (vtype == TYPE_FIELD) @@ -1308,7 +1361,7 @@ bool ast_local_codegen(ast_value *self, ir_function *func, bool param) /* A constant local... hmmm... * I suppose the IR will have to deal with this */ - if (self->isconst) { + if (self->hasvalue) { switch (self->expression.vtype) { case TYPE_FLOAT: @@ -1387,7 +1440,7 @@ bool ast_function_codegen(ast_function *self, ir_builder *ir) return false; } - self->curblock = ir_function_create_block(irf, "entry"); + self->curblock = ir_function_create_block(ast_ctx(self), irf, "entry"); if (!self->curblock) { asterror(ast_ctx(self), "failed to allocate entry block for `%s`", self->name); return false; @@ -1466,7 +1519,7 @@ bool ast_block_codegen(ast_block *self, ast_function *func, bool lvalue, ir_valu for (i = 0; i < vec_size(self->exprs); ++i) { ast_expression_codegen *gen = self->exprs[i]->expression.codegen; - if (func->curblock->final) { + if (func->curblock->final && !ast_istype(self->exprs[i], ast_label)) { asterror(ast_ctx(self->exprs[i]), "unreachable statement"); return false; } @@ -1505,7 +1558,7 @@ bool ast_store_codegen(ast_store *self, ast_function *func, bool lvalue, ir_valu ai = (ast_array_index*)self->dest; idx = (ast_value*)ai->index; - if (ast_istype(ai->index, ast_value) && idx->isconst) + if (ast_istype(ai->index, ast_value) && idx->hasvalue) ai = NULL; } @@ -1612,7 +1665,7 @@ bool ast_binary_codegen(ast_binary *self, ast_function *func, bool lvalue, ir_va */ merge_id = vec_size(func->ir_func->blocks); - merge = ir_function_create_block(func->ir_func, ast_function_label(func, "sce_merge")); + merge = ir_function_create_block(ast_ctx(self), func->ir_func, ast_function_label(func, "sce_merge")); cgen = self->left->expression.codegen; if (!(*cgen)((ast_expression*)(self->left), func, false, &left)) @@ -1630,7 +1683,7 @@ bool ast_binary_codegen(ast_binary *self, ast_function *func, bool lvalue, ir_va } from_left = func->curblock; - other = ir_function_create_block(func->ir_func, ast_function_label(func, "sce_other")); + other = ir_function_create_block(ast_ctx(self), func->ir_func, ast_function_label(func, "sce_other")); if ( !(self->op == INSTR_OR) != !OPTS_FLAG(PERL_LOGIC) ) { if (!ir_block_create_if(func->curblock, left, other, merge)) return false; @@ -1729,7 +1782,7 @@ bool ast_binstore_codegen(ast_binstore *self, ast_function *func, bool lvalue, i ai = (ast_array_index*)self->dest; idx = (ast_value*)ai->index; - if (ast_istype(ai->index, ast_value) && idx->isconst) + if (ast_istype(ai->index, ast_value) && idx->hasvalue) ai = NULL; } @@ -1978,7 +2031,7 @@ bool ast_array_index_codegen(ast_array_index *self, ast_function *func, bool lva arr = (ast_value*)self->array; idx = (ast_value*)self->index; - if (!ast_istype(self->index, ast_value) || !idx->isconst) { + if (!ast_istype(self->index, ast_value) || !idx->hasvalue) { /* Time to use accessor functions */ ast_expression_codegen *cgen; ir_value *iridx, *funval; @@ -1995,7 +2048,7 @@ bool ast_array_index_codegen(ast_array_index *self, ast_function *func, bool lva } cgen = self->index->expression.codegen; - if (!(*cgen)((ast_expression*)(self->index), func, true, &iridx)) + if (!(*cgen)((ast_expression*)(self->index), func, false, &iridx)) return false; cgen = arr->getter->expression.codegen; @@ -2058,7 +2111,7 @@ bool ast_ifthen_codegen(ast_ifthen *self, ast_function *func, bool lvalue, ir_va if (self->on_true) { /* create on-true block */ - ontrue = ir_function_create_block(func->ir_func, ast_function_label(func, "ontrue")); + ontrue = ir_function_create_block(ast_ctx(self), func->ir_func, ast_function_label(func, "ontrue")); if (!ontrue) return false; @@ -2078,7 +2131,7 @@ bool ast_ifthen_codegen(ast_ifthen *self, ast_function *func, bool lvalue, ir_va /* on-false path */ if (self->on_false) { /* create on-false block */ - onfalse = ir_function_create_block(func->ir_func, ast_function_label(func, "onfalse")); + onfalse = ir_function_create_block(ast_ctx(self), func->ir_func, ast_function_label(func, "onfalse")); if (!onfalse) return false; @@ -2096,7 +2149,7 @@ bool ast_ifthen_codegen(ast_ifthen *self, ast_function *func, bool lvalue, ir_va onfalse = NULL; /* Merge block were they all merge in to */ - merge = ir_function_create_block(func->ir_func, ast_function_label(func, "endif")); + merge = ir_function_create_block(ast_ctx(self), func->ir_func, ast_function_label(func, "endif")); if (!merge) return false; /* add jumps ot the merge block */ @@ -2129,8 +2182,9 @@ bool ast_ternary_codegen(ast_ternary *self, ast_function *func, bool lvalue, ir_ ir_instr *phi; ir_block *cond = func->curblock; - ir_block *ontrue; - ir_block *onfalse; + ir_block *cond_out = NULL; + ir_block *ontrue, *ontrue_out = NULL; + ir_block *onfalse, *onfalse_out = NULL; ir_block *merge; /* Ternary can never create an lvalue... */ @@ -2154,9 +2208,10 @@ bool ast_ternary_codegen(ast_ternary *self, ast_function *func, bool lvalue, ir_ cgen = self->cond->expression.codegen; if (!(*cgen)((ast_expression*)(self->cond), func, false, &condval)) return false; + cond_out = func->curblock; /* create on-true block */ - ontrue = ir_function_create_block(func->ir_func, ast_function_label(func, "tern_T")); + ontrue = ir_function_create_block(ast_ctx(self), func->ir_func, ast_function_label(func, "tern_T")); if (!ontrue) return false; else @@ -2168,10 +2223,12 @@ bool ast_ternary_codegen(ast_ternary *self, ast_function *func, bool lvalue, ir_ cgen = self->on_true->expression.codegen; if (!(*cgen)((ast_expression*)(self->on_true), func, false, &trueval)) return false; + + ontrue_out = func->curblock; } /* create on-false block */ - onfalse = ir_function_create_block(func->ir_func, ast_function_label(func, "tern_F")); + onfalse = ir_function_create_block(ast_ctx(self), func->ir_func, ast_function_label(func, "tern_F")); if (!onfalse) return false; else @@ -2183,20 +2240,22 @@ bool ast_ternary_codegen(ast_ternary *self, ast_function *func, bool lvalue, ir_ cgen = self->on_false->expression.codegen; if (!(*cgen)((ast_expression*)(self->on_false), func, false, &falseval)) return false; + + onfalse_out = func->curblock; } /* create merge block */ - merge = ir_function_create_block(func->ir_func, ast_function_label(func, "tern_out")); + merge = ir_function_create_block(ast_ctx(self), func->ir_func, ast_function_label(func, "tern_out")); if (!merge) return false; /* jump to merge block */ - if (!ir_block_create_jump(ontrue, merge)) + if (!ir_block_create_jump(ontrue_out, merge)) return false; - if (!ir_block_create_jump(onfalse, merge)) + if (!ir_block_create_jump(onfalse_out, merge)) return false; /* create if instruction */ - if (!ir_block_create_if(cond, condval, ontrue, onfalse)) + if (!ir_block_create_if(cond_out, condval, ontrue, onfalse)) return false; /* Now enter the merge block */ @@ -2214,8 +2273,8 @@ bool ast_ternary_codegen(ast_ternary *self, ast_function *func, bool lvalue, ir_ phi = ir_block_create_phi(merge, ast_function_label(func, "phi"), trueval->vtype); if (!phi) return false; - ir_phi_add(phi, ontrue, trueval); - ir_phi_add(phi, onfalse, falseval); + ir_phi_add(phi, ontrue_out, trueval); + ir_phi_add(phi, onfalse_out, falseval); self->expression.outr = ir_phi_value(phi); *out = self->expression.outr; @@ -2286,7 +2345,7 @@ bool ast_loop_codegen(ast_loop *self, ast_function *func, bool lvalue, ir_value */ if (self->precond) { - bprecond = ir_function_create_block(func->ir_func, ast_function_label(func, "pre_loop_cond")); + bprecond = ir_function_create_block(ast_ctx(self), func->ir_func, ast_function_label(func, "pre_loop_cond")); if (!bprecond) return false; @@ -2310,7 +2369,7 @@ bool ast_loop_codegen(ast_loop *self, ast_function *func, bool lvalue, ir_value * generate them this early for 'break' and 'continue'. */ if (self->increment) { - bincrement = ir_function_create_block(func->ir_func, ast_function_label(func, "loop_increment")); + bincrement = ir_function_create_block(ast_ctx(self), func->ir_func, ast_function_label(func, "loop_increment")); if (!bincrement) return false; bcontinue = bincrement; /* increment comes before the pre-loop-condition */ @@ -2319,7 +2378,7 @@ bool ast_loop_codegen(ast_loop *self, ast_function *func, bool lvalue, ir_value } if (self->postcond) { - bpostcond = ir_function_create_block(func->ir_func, ast_function_label(func, "post_loop_cond")); + bpostcond = ir_function_create_block(ast_ctx(self), func->ir_func, ast_function_label(func, "post_loop_cond")); if (!bpostcond) return false; bcontinue = bpostcond; /* postcond comes before the increment */ @@ -2328,7 +2387,7 @@ bool ast_loop_codegen(ast_loop *self, ast_function *func, bool lvalue, ir_value } bout_id = vec_size(func->ir_func->blocks); - bout = ir_function_create_block(func->ir_func, ast_function_label(func, "after_loop")); + bout = ir_function_create_block(ast_ctx(self), func->ir_func, ast_function_label(func, "after_loop")); if (!bout) return false; bbreak = bout; @@ -2336,7 +2395,7 @@ bool ast_loop_codegen(ast_loop *self, ast_function *func, bool lvalue, ir_value /* The loop body... */ if (self->body) { - bbody = ir_function_create_block(func->ir_func, ast_function_label(func, "loop_body")); + bbody = ir_function_create_block(ast_ctx(self), func->ir_func, ast_function_label(func, "loop_body")); if (!bbody) return false; @@ -2347,6 +2406,8 @@ bool ast_loop_codegen(ast_loop *self, ast_function *func, bool lvalue, ir_value old_bcontinue = func->continueblock; func->breakblock = bbreak; func->continueblock = bcontinue; + if (!func->continueblock) + func->continueblock = bbody; /* generate */ cgen = self->body->expression.codegen; @@ -2475,6 +2536,11 @@ bool ast_breakcont_codegen(ast_breakcont *self, ast_function *func, bool lvalue, else target = func->breakblock; + if (!target) { + asterror(ast_ctx(self), "%s is lacking a target block", (self->is_continue ? "continue" : "break")); + return false; + } + if (!ir_block_create_jump(func->curblock, target)) return false; return true; @@ -2527,7 +2593,7 @@ bool ast_switch_codegen(ast_switch *self, ast_function *func, bool lvalue, ir_va } bout_id = vec_size(func->ir_func->blocks); - bout = ir_function_create_block(func->ir_func, ast_function_label(func, "after_switch")); + bout = ir_function_create_block(ast_ctx(self), func->ir_func, ast_function_label(func, "after_switch")); if (!bout) return false; @@ -2554,9 +2620,9 @@ bool ast_switch_codegen(ast_switch *self, ast_function *func, bool lvalue, ir_va if (!cond) return false; - bcase = ir_function_create_block(func->ir_func, ast_function_label(func, "case")); + bcase = ir_function_create_block(ast_ctx(self), func->ir_func, ast_function_label(func, "case")); bnot_id = vec_size(func->ir_func->blocks); - bnot = ir_function_create_block(func->ir_func, ast_function_label(func, "not_case")); + bnot = ir_function_create_block(ast_ctx(self), func->ir_func, ast_function_label(func, "not_case")); if (!bcase || !bnot) return false; if (!ir_block_create_if(func->curblock, cond, bcase, bnot)) @@ -2634,6 +2700,78 @@ bool ast_switch_codegen(ast_switch *self, ast_function *func, bool lvalue, ir_va return true; } +bool ast_label_codegen(ast_label *self, ast_function *func, bool lvalue, ir_value **out) +{ + size_t i; + ir_value *dummy; + + *out = NULL; + if (lvalue) { + asterror(ast_ctx(self), "internal error: ast_label cannot be an lvalue"); + return false; + } + + /* simply create a new block and jump to it */ + self->irblock = ir_function_create_block(ast_ctx(self), func->ir_func, self->name); + if (!self->irblock) { + asterror(ast_ctx(self), "failed to allocate label block `%s`", self->name); + return false; + } + if (!func->curblock->final) { + if (!ir_block_create_jump(func->curblock, self->irblock)) + return false; + } + + /* enter the new block */ + func->curblock = self->irblock; + + /* Generate all the leftover gotos */ + for (i = 0; i < vec_size(self->gotos); ++i) { + if (!ast_goto_codegen(self->gotos[i], func, false, &dummy)) + return false; + } + + return true; +} + +bool ast_goto_codegen(ast_goto *self, ast_function *func, bool lvalue, ir_value **out) +{ + *out = NULL; + if (lvalue) { + asterror(ast_ctx(self), "internal error: ast_goto cannot be an lvalue"); + return false; + } + + if (self->target->irblock) { + if (self->irblock_from) { + /* we already tried once, this is the callback */ + self->irblock_from->final = false; + if (!ir_block_create_jump(self->irblock_from, self->target->irblock)) { + asterror(ast_ctx(self), "failed to generate goto to `%s`", self->name); + return false; + } + } + else + { + if (!ir_block_create_jump(func->curblock, self->target->irblock)) { + asterror(ast_ctx(self), "failed to generate goto to `%s`", self->name); + return false; + } + } + } + else + { + /* the target has not yet been created... + * close this block in a sneaky way: + */ + func->curblock->final = true; + self->irblock_from = func->curblock; + ast_label_register_goto(self->target, self); + } + + return true; +} + bool ast_call_codegen(ast_call *self, ast_function *func, bool lvalue, ir_value **out) { ast_expression_codegen *cgen;