X-Git-Url: https://git.xonotic.org/?a=blobdiff_plain;f=ast.c;h=7061f1eff909e5ab63d30d5647398499d69d4a78;hb=e25e83b14c87f8b5aad10c308e98fff91656d931;hp=b04acc6fce783e9f9761505415d61cc48e058f6e;hpb=ebc6954bf566a1e7f66eee8be5f4d9b06fb05212;p=xonotic%2Fgmqcc.git diff --git a/ast.c b/ast.c index b04acc6..7061f1e 100644 --- a/ast.c +++ b/ast.c @@ -47,6 +47,7 @@ static void asterror(lex_ctx ctx, const char *msg, ...) /* It must not be possible to get here. */ static GMQCC_NORETURN void _ast_node_destroy(ast_node *self) { + (void)self; con_err("ast node missing destroy()\n"); abort(); } @@ -651,7 +652,11 @@ ast_ternary* ast_ternary_new(lex_ctx ctx, ast_expression *cond, ast_expression * self->cond = cond; self->on_true = ontrue; self->on_false = onfalse; - self->phi_out = NULL; + + if (!ast_type_adopt(self, ontrue)) { + ast_ternary_delete(self); + return NULL; + } return self; } @@ -784,8 +789,12 @@ bool ast_call_check_types(ast_call *self) for (i = 0; i < count; ++i) { if (!ast_compare_type(self->params[i], (ast_expression*)(func->expression.params[i]))) { - asterror(ast_ctx(self), "invalid type for parameter %u in function call", - (unsigned int)(i+1)); + char texp[1024]; + char tgot[1024]; + ast_type_to_string(self->params[i], tgot, sizeof(tgot)); + ast_type_to_string((ast_expression*)func->expression.params[i], texp, sizeof(texp)); + asterror(ast_ctx(self), "invalid type for parameter %u in function call: expected %s, got %s", + (unsigned int)(i+1), texp, tgot); /* we don't immediately return */ retval = false; } @@ -932,7 +941,7 @@ const char* ast_function_label(ast_function *self, const char *prefix) size_t len; char *from; - if (!opts_dump) + if (!opts_dump && !opts_dumpfin) return NULL; id = (self->labelcount++); @@ -958,6 +967,8 @@ const char* ast_function_label(ast_function *self, const char *prefix) bool ast_value_codegen(ast_value *self, ast_function *func, bool lvalue, ir_value **out) { + (void)func; + (void)lvalue; /* NOTE: This is the codegen for a variable used in an expression. * It is not the codegen to generate the value. For this purpose, * ast_local_codegen and ast_global_codegen are to be used before this @@ -1282,6 +1293,8 @@ bool ast_function_codegen(ast_function *self, ir_builder *ir) ast_expression_common *ec; size_t i; + (void)ir; + irf = self->ir_func; if (!irf) { asterror(ast_ctx(self), "ast_function's related ast_value was not generated yet"); @@ -1404,10 +1417,11 @@ bool ast_block_codegen(ast_block *self, ast_function *func, bool lvalue, ir_valu bool ast_store_codegen(ast_store *self, ast_function *func, bool lvalue, ir_value **out) { ast_expression_codegen *cgen; - ir_value *left, *right; + ir_value *left = NULL; + ir_value *right = NULL; ast_value *arr; - ast_value *idx; + ast_value *idx = 0; ast_array_index *ai = NULL; if (lvalue && self->expression.outl) { @@ -1532,23 +1546,27 @@ bool ast_binary_codegen(ast_binary *self, ast_function *func, bool lvalue, ir_va * but we translate this to (!(!a ? !a : !b)) */ - merge_id = vec_size(func->blocks); + merge_id = vec_size(func->ir_func->blocks); merge = ir_function_create_block(func->ir_func, ast_function_label(func, "sce_merge")); cgen = self->left->expression.codegen; if (!(*cgen)((ast_expression*)(self->left), func, false, &left)) return false; - notop = type_not_instr[left->vtype]; - if (notop == AINSTR_END) { - asterror(ast_ctx(self), "don't know how to cast to bool..."); - return false; + if (!OPTS_FLAG(PERL_LOGIC)) { + notop = type_not_instr[left->vtype]; + if (notop == AINSTR_END) { + asterror(ast_ctx(self), "don't know how to cast to bool..."); + return false; + } + left = ir_block_create_unary(func->curblock, + ast_function_label(func, "sce_not"), + notop, + left); } - left = ir_block_create_unary(func->curblock, ast_function_label(func, "sce_not"), notop, left); - from_left = func->curblock; other = ir_function_create_block(func->ir_func, ast_function_label(func, "sce_other")); - if (self->op == INSTR_OR) { + if ( !(self->op == INSTR_OR) != !OPTS_FLAG(PERL_LOGIC) ) { if (!ir_block_create_if(func->curblock, left, other, merge)) return false; } else { @@ -1562,12 +1580,17 @@ bool ast_binary_codegen(ast_binary *self, ast_function *func, bool lvalue, ir_va cgen = self->right->expression.codegen; if (!(*cgen)((ast_expression*)(self->right), func, false, &right)) return false; - notop = type_not_instr[right->vtype]; - if (notop == AINSTR_END) { - asterror(ast_ctx(self), "don't know how to cast to bool..."); - return false; + if (!OPTS_FLAG(PERL_LOGIC)) { + notop = type_not_instr[right->vtype]; + if (notop == AINSTR_END) { + asterror(ast_ctx(self), "don't know how to cast to bool..."); + return false; + } + right = ir_block_create_unary(func->curblock, + ast_function_label(func, "sce_not"), + notop, + right); } - right = ir_block_create_unary(func->curblock, ast_function_label(func, "sce_not"), notop, right); from_right = func->curblock; if (!ir_block_create_jump(func->curblock, merge)) @@ -1581,12 +1604,19 @@ bool ast_binary_codegen(ast_binary *self, ast_function *func, bool lvalue, ir_va ir_phi_add(phi, from_left, left); ir_phi_add(phi, from_right, right); *out = ir_phi_value(phi); - notop = type_not_instr[(*out)->vtype]; - if (notop == AINSTR_END) { - asterror(ast_ctx(self), "don't know how to cast to bool..."); - return false; + if (!OPTS_FLAG(PERL_LOGIC)) { + notop = type_not_instr[(*out)->vtype]; + if (notop == AINSTR_END) { + asterror(ast_ctx(self), "don't know how to cast to bool..."); + return false; + } + *out = ir_block_create_unary(func->curblock, + ast_function_label(func, "sce_final_not"), + notop, + *out); } - *out = ir_block_create_unary(func->curblock, ast_function_label(func, "sce_final_not"), notop, *out); + if (!*out) + return false; self->expression.outr = *out; return true; } @@ -1611,7 +1641,12 @@ bool ast_binary_codegen(ast_binary *self, ast_function *func, bool lvalue, ir_va bool ast_binstore_codegen(ast_binstore *self, ast_function *func, bool lvalue, ir_value **out) { ast_expression_codegen *cgen; - ir_value *leftl, *leftr, *right, *bin; + ir_value *leftl = NULL, *leftr, *right, *bin; + + ast_value *arr; + ast_value *idx = 0; + ast_array_index *ai = NULL; + ir_value *iridx = NULL; if (lvalue && self->expression.outl) { *out = self->expression.outl; @@ -1623,8 +1658,23 @@ bool ast_binstore_codegen(ast_binstore *self, ast_function *func, bool lvalue, i return true; } + if (ast_istype(self->dest, ast_array_index)) + { + + ai = (ast_array_index*)self->dest; + idx = (ast_value*)ai->index; + + if (ast_istype(ai->index, ast_value) && idx->isconst) + ai = NULL; + } + /* for a binstore we need both an lvalue and an rvalue for the left side */ /* rvalue of destination! */ + if (ai) { + cgen = idx->expression.codegen; + if (!(*cgen)((ast_expression*)(idx), func, false, &iridx)) + return false; + } cgen = self->dest->expression.codegen; if (!(*cgen)((ast_expression*)(self->dest), func, false, &leftr)) return false; @@ -1639,16 +1689,45 @@ bool ast_binstore_codegen(ast_binstore *self, ast_function *func, bool lvalue, i self->opbin, leftr, right); self->expression.outr = bin; - /* now store them */ - cgen = self->dest->expression.codegen; - /* lvalue of destination */ - if (!(*cgen)((ast_expression*)(self->dest), func, true, &leftl)) - return false; - self->expression.outl = leftl; - if (!ir_block_create_store_op(func->curblock, self->opstore, leftl, bin)) - return false; - self->expression.outr = bin; + if (ai) { + /* we need to call the setter */ + ir_value *funval; + ir_instr *call; + + if (lvalue) { + asterror(ast_ctx(self), "array-subscript assignment cannot produce lvalues"); + return false; + } + + arr = (ast_value*)ai->array; + if (!ast_istype(ai->array, ast_value) || !arr->setter) { + asterror(ast_ctx(self), "value has no setter (%s)", arr->name); + return false; + } + + cgen = arr->setter->expression.codegen; + if (!(*cgen)((ast_expression*)(arr->setter), func, true, &funval)) + return false; + + call = ir_block_create_call(func->curblock, ast_function_label(func, "store"), funval); + if (!call) + return false; + ir_call_param(call, iridx); + ir_call_param(call, bin); + self->expression.outr = bin; + } else { + /* now store them */ + cgen = self->dest->expression.codegen; + /* lvalue of destination */ + if (!(*cgen)((ast_expression*)(self->dest), func, true, &leftl)) + return false; + self->expression.outl = leftl; + + if (!ir_block_create_store_op(func->curblock, self->opstore, leftl, bin)) + return false; + self->expression.outr = bin; + } /* Theoretically, an assinment returns its left side as an * lvalue, if we don't need an lvalue though, we return @@ -1697,6 +1776,8 @@ bool ast_return_codegen(ast_return *self, ast_function *func, bool lvalue, ir_va ast_expression_codegen *cgen; ir_value *operand; + *out = NULL; + /* In the context of a return operation, we don't actually return * anything... */ @@ -1902,10 +1983,11 @@ bool ast_ifthen_codegen(ast_ifthen *self, ast_function *func, bool lvalue, ir_va self->expression.outr = (ir_value*)1; /* generate the condition */ - func->curblock = cond; cgen = self->cond->expression.codegen; if (!(*cgen)((ast_expression*)(self->cond), func, false, &condval)) return false; + /* update the block which will get the jump - because short-logic or ternaries may have changed this */ + cond = func->curblock; /* on-true path */ @@ -1952,7 +2034,6 @@ bool ast_ifthen_codegen(ast_ifthen *self, ast_function *func, bool lvalue, ir_va merge = ir_function_create_block(func->ir_func, ast_function_label(func, "endif")); if (!merge) return false; - /* add jumps ot the merge block */ if (ontrue && !ontrue_endblock->final && !ir_block_create_jump(ontrue_endblock, merge)) return false; @@ -1996,8 +2077,8 @@ bool ast_ternary_codegen(ast_ternary *self, ast_function *func, bool lvalue, ir_ * may still happen, thus we remember a created ir_value and simply return one * if it already exists. */ - if (self->phi_out) { - *out = self->phi_out; + if (self->expression.outr) { + *out = self->expression.outr; return true; } @@ -2071,8 +2152,8 @@ bool ast_ternary_codegen(ast_ternary *self, ast_function *func, bool lvalue, ir_ ir_phi_add(phi, ontrue, trueval); ir_phi_add(phi, onfalse, falseval); - self->phi_out = ir_phi_value(phi); - *out = self->phi_out; + self->expression.outr = ir_phi_value(phi); + *out = self->expression.outr; return true; } @@ -2311,6 +2392,8 @@ bool ast_breakcont_codegen(ast_breakcont *self, ast_function *func, bool lvalue, { ir_block *target; + *out = NULL; + if (lvalue) { asterror(ast_ctx(self), "break/continue expression is not an l-value"); return false;