self->expression.outl = NULL;
self->expression.outr = NULL;
self->expression.variadic = false;
- MEM_VECTOR_INIT(&self->expression, params);
+ self->expression.params = NULL;
}
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) {
+ for (i = 0; i < vec_size(self->expression.params); ++i) {
ast_delete(self->expression.params[i]);
}
- MEM_VECTOR_CLEAR(&self->expression, params);
+ vec_free(self->expression.params);
}
static void ast_expression_delete_full(ast_expression *self)
mem_d(self);
}
-MEM_VEC_FUNCTIONS(ast_expression_common, ast_value*, params)
-
ast_value* ast_value_copy(const ast_value *self)
{
size_t i;
fromex = &self->expression;
selfex = &cp->expression;
selfex->variadic = fromex->variadic;
- for (i = 0; i < fromex->params_count; ++i) {
+ for (i = 0; i < vec_size(fromex->params); ++i) {
ast_value *v = ast_value_copy(fromex->params[i]);
- if (!v || !ast_expression_common_params_add(selfex, v)) {
+ if (!v) {
ast_value_delete(cp);
return NULL;
}
+ vec_push(selfex->params, v);
}
return cp;
}
fromex = &other->expression;
selfex = &self->expression;
selfex->variadic = fromex->variadic;
- for (i = 0; i < fromex->params_count; ++i) {
+ for (i = 0; i < vec_size(fromex->params); ++i) {
ast_value *v = ast_value_copy(fromex->params[i]);
- if (!v || !ast_expression_common_params_add(selfex, v))
+ if (!v)
return false;
+ vec_push(selfex->params, v);
}
return true;
}
selfex->next = NULL;
selfex->variadic = fromex->variadic;
- for (i = 0; i < fromex->params_count; ++i) {
+ for (i = 0; i < vec_size(fromex->params); ++i) {
ast_value *v = ast_value_copy(fromex->params[i]);
- if (!v || !ast_expression_common_params_add(selfex, v)) {
+ if (!v) {
ast_expression_delete_full(self);
return NULL;
}
+ vec_push(selfex->params, v);
}
return self;
return false;
if (!a->expression.next != !b->expression.next)
return false;
- if (a->expression.params_count != b->expression.params_count)
+ if (vec_size(a->expression.params) != vec_size(b->expression.params))
return false;
if (a->expression.variadic != b->expression.variadic)
return false;
- if (a->expression.params_count) {
+ if (vec_size(a->expression.params)) {
size_t i;
- for (i = 0; i < a->expression.params_count; ++i) {
+ for (i = 0; i < vec_size(a->expression.params); ++i) {
if (!ast_compare_type((ast_expression*)a->expression.params[i],
(ast_expression*)b->expression.params[i]))
return false;
pos = ast_type_to_string_impl(e->expression.next, buf, bufsize, pos);
if (pos + 2 >= bufsize)
goto full;
- if (e->expression.params_count == 0) {
+ if (!vec_size(e->expression.params)) {
buf[pos++] = '(';
buf[pos++] = ')';
return pos;
}
buf[pos++] = '(';
pos = ast_type_to_string_impl((ast_expression*)(e->expression.params[0]), buf, bufsize, pos);
- for (i = 1; i < e->expression.params_count; ++i) {
+ for (i = 1; i < vec_size(e->expression.params); ++i) {
if (pos + 2 >= bufsize)
goto full;
buf[pos++] = ',';
mem_d(self);
}
-bool GMQCC_WARN ast_value_params_add(ast_value *self, ast_value *p)
+void ast_value_params_add(ast_value *self, ast_value *p)
{
- return ast_expression_common_params_add(&self->expression, p);
+ vec_push(self->expression.params, p);
}
bool ast_value_set_name(ast_value *self, const char *name)
mem_d(self);
}
+ast_breakcont* ast_breakcont_new(lex_ctx ctx, bool iscont)
+{
+ ast_instantiate(ast_breakcont, ctx, ast_breakcont_delete);
+ ast_expression_init((ast_expression*)self, (ast_expression_codegen*)&ast_breakcont_codegen);
+
+ self->is_continue = iscont;
+
+ return self;
+}
+
+void ast_breakcont_delete(ast_breakcont *self)
+{
+ ast_expression_delete((ast_expression*)self);
+ mem_d(self);
+}
+
+ast_switch* ast_switch_new(lex_ctx ctx, ast_expression *op)
+{
+ ast_instantiate(ast_switch, ctx, ast_switch_delete);
+ ast_expression_init((ast_expression*)self, (ast_expression_codegen*)&ast_switch_codegen);
+
+ self->operand = op;
+ self->cases = NULL;
+
+ return self;
+}
+
+void ast_switch_delete(ast_switch *self)
+{
+ size_t i;
+ ast_unref(self->operand);
+
+ for (i = 0; i < vec_size(self->cases); ++i) {
+ if (self->cases[i].value)
+ ast_unref(self->cases[i].value);
+ ast_unref(self->cases[i].code);
+ }
+ vec_free(self->cases);
+
+ ast_expression_delete((ast_expression*)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;
+ self->params = NULL;
+ self->func = funcexpr;
self->expression.vtype = funcexpr->expression.next->expression.vtype;
if (funcexpr->expression.next->expression.next)
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)
+ for (i = 0; i < vec_size(self->params); ++i)
ast_unref(self->params[i]);
- MEM_VECTOR_CLEAR(self, params);
+ vec_free(self->params);
if (self->func)
ast_unref(self->func);
size_t i;
bool retval = true;
const ast_expression *func = self->func;
- size_t count = self->params_count;
- if (count > func->expression.params_count)
- count = func->expression.params_count;
+ size_t count = vec_size(self->params);
+ if (count > vec_size(func->expression.params))
+ count = vec_size(func->expression.params);
for (i = 0; i < count; ++i) {
if (!ast_compare_type(self->params[i], (ast_expression*)(func->expression.params[i]))) {
ast_expression_init((ast_expression*)self,
(ast_expression_codegen*)&ast_block_codegen);
- MEM_VECTOR_INIT(self, locals);
- MEM_VECTOR_INIT(self, exprs);
- MEM_VECTOR_INIT(self, collect);
+ self->locals = NULL;
+ self->exprs = NULL;
+ self->collect = NULL;
return self;
}
-MEM_VEC_FUNCTIONS(ast_block, ast_value*, locals)
-MEM_VEC_FUNCTIONS(ast_block, ast_expression*, exprs)
-MEM_VEC_FUNCTIONS(ast_block, ast_expression*, collect)
-bool ast_block_collect(ast_block *self, ast_expression *expr)
+void ast_block_collect(ast_block *self, ast_expression *expr)
{
- if (!ast_block_collect_add(self, expr))
- return false;
+ vec_push(self->collect, expr);
expr->expression.node.keep = true;
- return true;
}
void ast_block_delete(ast_block *self)
{
size_t i;
- for (i = 0; i < self->exprs_count; ++i)
+ for (i = 0; i < vec_size(self->exprs); ++i)
ast_unref(self->exprs[i]);
- MEM_VECTOR_CLEAR(self, exprs);
- for (i = 0; i < self->locals_count; ++i)
+ vec_free(self->exprs);
+ for (i = 0; i < vec_size(self->locals); ++i)
ast_delete(self->locals[i]);
- MEM_VECTOR_CLEAR(self, locals);
- for (i = 0; i < self->collect_count; ++i)
+ vec_free(self->locals);
+ for (i = 0; i < vec_size(self->collect); ++i)
ast_delete(self->collect[i]);
- MEM_VECTOR_CLEAR(self, collect);
+ vec_free(self->collect);
ast_expression_delete((ast_expression*)self);
mem_d(self);
}
return NULL;
}
- self->vtype = vtype;
- self->name = name ? util_strdup(name) : NULL;
- MEM_VECTOR_INIT(self, blocks);
+ self->vtype = vtype;
+ self->name = name ? util_strdup(name) : NULL;
+ self->blocks = NULL;
self->labelcount = 0;
self->builtin = 0;
return self;
}
-MEM_VEC_FUNCTIONS(ast_function, ast_block*, blocks)
-
void ast_function_delete(ast_function *self)
{
size_t i;
*/
ast_unref(self->vtype);
}
- for (i = 0; i < self->blocks_count; ++i)
+ for (i = 0; i < vec_size(self->blocks); ++i)
ast_delete(self->blocks[i]);
- MEM_VECTOR_CLEAR(self, blocks);
+ vec_free(self->blocks);
mem_d(self);
}
/* fill the parameter list */
ec = &self->vtype->expression;
- for (i = 0; i < ec->params_count; ++i)
+ for (i = 0; i < vec_size(ec->params); ++i)
{
- if (!ir_function_params_add(irf, ec->params[i]->expression.vtype))
- return false;
+ vec_push(irf->params, ec->params[i]->expression.vtype);
if (!self->builtin) {
if (!ast_local_codegen(ec->params[i], self->ir_func, true))
return false;
return true;
}
- if (!self->blocks_count) {
+ if (!vec_size(self->blocks)) {
asterror(ast_ctx(self), "function `%s` has no body", self->name);
return false;
}
return false;
}
- for (i = 0; i < self->blocks_count; ++i) {
+ for (i = 0; i < vec_size(self->blocks); ++i) {
ast_expression_codegen *gen = self->blocks[i]->expression.codegen;
if (!(*gen)((ast_expression*)self->blocks[i], self, false, &dummy))
return false;
*out = NULL;
/* generate locals */
- for (i = 0; i < self->locals_count; ++i)
+ for (i = 0; i < vec_size(self->locals); ++i)
{
if (!ast_local_codegen(self->locals[i], func->ir_func, false)) {
if (opts_debug)
}
}
- for (i = 0; i < self->exprs_count; ++i)
+ for (i = 0; i < vec_size(self->exprs); ++i)
{
ast_expression_codegen *gen = self->exprs[i]->expression.codegen;
+ if (func->curblock->final) {
+ asterror(ast_ctx(self->exprs[i]), "unreachable statement");
+ return false;
+ }
if (!(*gen)(self->exprs[i], func, false, out))
return false;
}
call = ir_block_create_call(func->curblock, ast_function_label(func, "store"), funval);
if (!call)
return false;
- if (!ir_call_param(call, iridx))
- return false;
- if (!ir_call_param(call, right))
- return false;
+ ir_call_param(call, iridx);
+ ir_call_param(call, right);
self->expression.outr = right;
}
else
return true;
}
+ if (OPTS_FLAG(SHORT_LOGIC) &&
+ (self->op == INSTR_AND || self->op == INSTR_OR))
+ {
+ /* short circuit evaluation */
+ ir_block *other, *merge;
+ ir_block *from_left, *from_right;
+ ir_instr *phi;
+ size_t merge_id;
+
+ merge_id = vec_size(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;
+
+ from_left = func->curblock;
+ other = ir_function_create_block(func->ir_func, ast_function_label(func, "sce_other"));
+ if (self->op == INSTR_AND) {
+ if (!ir_block_create_if(func->curblock, left, other, merge))
+ return false;
+ } else {
+ if (!ir_block_create_if(func->curblock, left, merge, other))
+ return false;
+ }
+ /* use the unlikely flag */
+ vec_last(func->curblock->instr)->likely = false;
+
+ func->curblock = other;
+ cgen = self->right->expression.codegen;
+ if (!(*cgen)((ast_expression*)(self->right), func, false, &right))
+ return false;
+ from_right = func->curblock;
+
+ if (!ir_block_create_jump(func->curblock, merge))
+ return false;
+
+ vec_remove(func->ir_func->blocks, merge_id, 1);
+ vec_push(func->ir_func->blocks, merge);
+
+ func->curblock = merge;
+ phi = ir_block_create_phi(func->curblock, ast_function_label(func, "sce_value"), TYPE_FLOAT);
+ ir_phi_add(phi, from_left, left);
+ ir_phi_add(phi, from_right, right);
+ *out = ir_phi_value(phi);
+ self->expression.outr = *out;
+ return true;
+ }
+
cgen = self->left->expression.codegen;
- /* lvalue! */
if (!(*cgen)((ast_expression*)(self->left), func, false, &left))
return false;
cgen = self->right->expression.codegen;
- /* rvalue! */
if (!(*cgen)((ast_expression*)(self->right), func, false, &right))
return false;
call = ir_block_create_call(func->curblock, ast_function_label(func, "fetch"), funval);
if (!call)
return false;
- if (!ir_call_param(call, iridx))
- return false;
+ ir_call_param(call, iridx);
*out = ir_call_value(call);
self->expression.outr = *out;
/* create PHI */
phi = ir_block_create_phi(merge, ast_function_label(func, "phi"), trueval->vtype);
- if (!phi ||
- !ir_phi_add(phi, ontrue, trueval) ||
- !ir_phi_add(phi, onfalse, falseval))
- {
+ if (!phi)
return false;
- }
+ ir_phi_add(phi, ontrue, trueval);
+ ir_phi_add(phi, onfalse, falseval);
self->phi_out = ir_phi_value(phi);
*out = self->phi_out;
bpostcond = end_bpostcond = NULL;
}
- bout_id = func->ir_func->blocks_count;
+ bout_id = vec_size(func->ir_func->blocks);
bout = ir_function_create_block(func->ir_func, ast_function_label(func, "after_loop"));
if (!bout)
return false;
}
/* Move 'bout' to the end */
- if (!ir_function_blocks_remove(func->ir_func, bout_id) ||
- !ir_function_blocks_add(func->ir_func, bout))
- {
- ir_block_delete(bout);
+ vec_remove(func->ir_func->blocks, bout_id, 1);
+ vec_push(func->ir_func->blocks, bout);
+
+ return true;
+}
+
+bool ast_breakcont_codegen(ast_breakcont *self, ast_function *func, bool lvalue, ir_value **out)
+{
+ ir_block *target;
+
+ if (lvalue) {
+ asterror(ast_ctx(self), "break/continue expression is not an l-value");
return false;
}
+ if (self->expression.outr) {
+ asterror(ast_ctx(self), "internal error: ast_breakcont cannot be reused!");
+ return false;
+ }
+ self->expression.outr = (ir_value*)1;
+
+ if (self->is_continue)
+ target = func->continueblock;
+ else
+ target = func->breakblock;
+
+ if (!ir_block_create_jump(func->curblock, target))
+ return false;
+ return true;
+}
+
+bool ast_switch_codegen(ast_switch *self, ast_function *func, bool lvalue, ir_value **out)
+{
+ ast_expression_codegen *cgen;
+
+ ast_switch_case *def_case = NULL;
+ ir_block *def_bfall = NULL;
+
+ ir_value *dummy = NULL;
+ ir_value *irop = NULL;
+ ir_block *old_break = NULL;
+ ir_block *bout = NULL;
+ ir_block *bfall = NULL;
+ size_t bout_id;
+ size_t c;
+
+ char typestr[1024];
+ uint16_t cmpinstr;
+
+ if (lvalue) {
+ asterror(ast_ctx(self), "switch expression is not an l-value");
+ return false;
+ }
+
+ if (self->expression.outr) {
+ asterror(ast_ctx(self), "internal error: ast_switch cannot be reused!");
+ return false;
+ }
+ self->expression.outr = (ir_value*)1;
+
+ (void)lvalue;
+ (void)out;
+
+ cgen = self->operand->expression.codegen;
+ if (!(*cgen)((ast_expression*)(self->operand), func, false, &irop))
+ return false;
+
+ if (!vec_size(self->cases))
+ return true;
+
+ cmpinstr = type_eq_instr[irop->vtype];
+ if (cmpinstr >= AINSTR_END) {
+ ast_type_to_string(self->operand, typestr, sizeof(typestr));
+ asterror(ast_ctx(self), "invalid type to perform a switch on: %s", typestr);
+ return false;
+ }
+
+ bout_id = vec_size(func->ir_func->blocks);
+ bout = ir_function_create_block(func->ir_func, ast_function_label(func, "after_switch"));
+ if (!bout)
+ return false;
+
+ /* setup the break block */
+ old_break = func->breakblock;
+ func->breakblock = bout;
+
+ /* Now create all cases */
+ for (c = 0; c < vec_size(self->cases); ++c) {
+ ir_value *cond, *val;
+ ir_block *bcase, *bnot;
+ size_t bnot_id;
+
+ ast_switch_case *swcase = &self->cases[c];
+
+ if (swcase->value) {
+ /* A regular case */
+ /* generate the condition operand */
+ cgen = swcase->value->expression.codegen;
+ if (!(*cgen)((ast_expression*)(swcase->value), func, false, &val))
+ return false;
+ /* generate the condition */
+ cond = ir_block_create_binop(func->curblock, ast_function_label(func, "switch_eq"), cmpinstr, irop, val);
+ if (!cond)
+ return false;
+
+ bcase = ir_function_create_block(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"));
+ if (!bcase || !bnot)
+ return false;
+ if (!ir_block_create_if(func->curblock, cond, bcase, bnot))
+ return false;
+
+ /* Make the previous case-end fall through */
+ if (bfall && !bfall->final) {
+ if (!ir_block_create_jump(bfall, bcase))
+ return false;
+ }
+
+ /* enter the case */
+ func->curblock = bcase;
+ cgen = swcase->code->expression.codegen;
+ if (!(*cgen)((ast_expression*)swcase->code, func, false, &dummy))
+ return false;
+
+ /* remember this block to fall through from */
+ bfall = func->curblock;
+
+ /* enter the else and move it down */
+ func->curblock = bnot;
+ vec_remove(func->ir_func->blocks, bnot_id, 1);
+ vec_push(func->ir_func->blocks, bnot);
+ } else {
+ /* The default case */
+ /* Remember where to fall through from: */
+ def_bfall = bfall;
+ bfall = NULL;
+ /* remember which case it was */
+ def_case = swcase;
+ }
+ }
+
+ /* Jump from the last bnot to bout */
+ if (bfall && !bfall->final && !ir_block_create_jump(bfall, bout)) {
+ /*
+ astwarning(ast_ctx(bfall), WARN_???, "missing break after last case");
+ */
+ return false;
+ }
+
+ /* If there was a default case, put it down here */
+ if (def_case) {
+ ir_block *bcase;
+
+ /* No need to create an extra block */
+ bcase = func->curblock;
+
+ /* Insert the fallthrough jump */
+ if (def_bfall && !def_bfall->final) {
+ if (!ir_block_create_jump(def_bfall, bcase))
+ return false;
+ }
+
+ /* Now generate the default code */
+ cgen = def_case->code->expression.codegen;
+ if (!(*cgen)((ast_expression*)def_case->code, func, false, &dummy))
+ return false;
+ }
+
+ /* Jump from the last bnot to bout */
+ if (!func->curblock->final && !ir_block_create_jump(func->curblock, bout))
+ return false;
+ /* enter the outgoing block */
+ func->curblock = bout;
+
+ /* restore the break block */
+ func->breakblock = old_break;
+
+ /* Move 'bout' to the end, it's nicer */
+ vec_remove(func->ir_func->blocks, bout_id, 1);
+ vec_push(func->ir_func->blocks, bout);
+
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_value **params;
ir_instr *callinstr;
size_t i;
if (!funval)
return false;
- MEM_VECTOR_INIT(¶ms, v);
+ params = NULL;
/* parameters */
- for (i = 0; i < self->params_count; ++i)
+ for (i = 0; i < vec_size(self->params); ++i)
{
ir_value *param;
ast_expression *expr = self->params[i];
goto error;
if (!param)
goto error;
- if (!ir_value_vector_v_add(¶ms, param))
- goto error;
+ vec_push(params, param);
}
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;
+ for (i = 0; i < vec_size(params); ++i) {
+ ir_call_param(callinstr, params[i]);
}
*out = ir_call_value(callinstr);
self->expression.outr = *out;
- MEM_VECTOR_CLEAR(¶ms, v);
+ vec_free(params);
return true;
error:
- MEM_VECTOR_CLEAR(¶ms, v);
+ vec_free(params);
return false;
}