self->expression.next = NULL;
self->expression.outl = NULL;
self->expression.outr = NULL;
- self->expression.variadic = false;
self->expression.params = NULL;
+ self->expression.count = 0;
+ self->expression.flags = 0;
}
static void ast_expression_delete(ast_expression *self)
}
fromex = &self->expression;
selfex = &cp->expression;
- selfex->variadic = fromex->variadic;
+ selfex->count = fromex->count;
+ selfex->flags = fromex->flags;
for (i = 0; i < vec_size(fromex->params); ++i) {
ast_value *v = ast_value_copy(fromex->params[i]);
if (!v) {
}
fromex = &other->expression;
selfex = &self->expression;
- selfex->variadic = fromex->variadic;
+ selfex->count = fromex->count;
+ selfex->flags = fromex->flags;
for (i = 0; i < vec_size(fromex->params); ++i) {
ast_value *v = ast_value_copy(fromex->params[i]);
if (!v)
else
selfex->next = NULL;
- selfex->variadic = fromex->variadic;
+ selfex->count = fromex->count;
+ selfex->flags = fromex->flags;
for (i = 0; i < vec_size(fromex->params); ++i) {
ast_value *v = ast_value_copy(fromex->params[i]);
if (!v) {
return false;
if (vec_size(a->expression.params) != vec_size(b->expression.params))
return false;
- if (a->expression.variadic != b->expression.variadic)
+ if (a->expression.flags != b->expression.flags)
return false;
if (vec_size(a->expression.params)) {
size_t i;
self->name = name ? util_strdup(name) : NULL;
self->expression.vtype = t;
self->expression.next = NULL;
+ self->isfield = false;
self->cvq = CV_NONE;
self->hasvalue = false;
self->uses = 0;
if (op >= INSTR_EQ_F && op <= INSTR_GT)
self->expression.vtype = TYPE_FLOAT;
- else if (op == INSTR_AND || op == INSTR_OR ||
- op == INSTR_BITAND || op == INSTR_BITOR)
+ else if (op == INSTR_AND || op == INSTR_OR) {
+ if (OPTS_FLAG(PERL_LOGIC))
+ ast_type_adopt(self, right);
+ else
+ self->expression.vtype = TYPE_FLOAT;
+ }
+ else if (op == INSTR_BITAND || op == INSTR_BITOR)
self->expression.vtype = TYPE_FLOAT;
else if (op == INSTR_MUL_VF || op == INSTR_MUL_FV)
self->expression.vtype = TYPE_VECTOR;
self->keep_dest = false;
- self->expression.vtype = left->expression.vtype;
- if (left->expression.next) {
- self->expression.next = ast_type_copy(ctx, left);
- if (!self->expression.next) {
- ast_delete(self);
- return NULL;
- }
+ if (!ast_type_adopt(self, left)) {
+ ast_delete(self);
+ return NULL;
}
- else
- self->expression.next = NULL;
return self;
}
self->params = NULL;
self->func = funcexpr;
- self->expression.vtype = funcexpr->expression.next->expression.vtype;
- if (funcexpr->expression.next->expression.next)
- self->expression.next = ast_type_copy(ctx, funcexpr->expression.next->expression.next);
+ ast_type_adopt(self, funcexpr->expression.next);
return self;
}
self->dest = dest;
self->source = source;
- self->expression.vtype = dest->expression.vtype;
- if (dest->expression.next) {
- self->expression.next = ast_type_copy(ctx, dest);
- if (!self->expression.next) {
- ast_delete(self);
- return NULL;
- }
+ if (!ast_type_adopt(self, dest)) {
+ ast_delete(self);
+ return NULL;
}
- else
- self->expression.next = NULL;
return self;
}
return self;
}
-void ast_block_add_expr(ast_block *self, ast_expression *e)
+bool ast_block_add_expr(ast_block *self, ast_expression *e)
{
ast_propagate_effects(self, e);
vec_push(self->exprs, e);
+ if (self->expression.next) {
+ ast_delete(self->expression.next);
+ self->expression.next = NULL;
+ }
+ if (!ast_type_adopt(self, e)) {
+ compile_error(ast_ctx(self), "internal error: failed to adopt type");
+ return false;
+ }
+ return true;
}
void ast_block_collect(ast_block *self, ast_expression *expr)
{
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;
- }
- else
- self->expression.next = NULL;
+ if (!ast_type_adopt(self, from))
+ return false;
return true;
}
vtype->hasvalue ||
vtype->expression.vtype != TYPE_FUNCTION)
{
- compile_error(ast_ctx(self), "internal error: ast_function_new condition %i %i type=%i",
+ compile_error(ast_ctx(self), "internal error: ast_function_new condition %i %i type=%i (probably 2 bodies?)",
(int)!vtype,
(int)vtype->hasvalue,
vtype->expression.vtype);
size_t len;
char *from;
- if (!opts_dump && !opts_dumpfin)
+ if (!opts.dump && !opts.dumpfin && !opts.debug)
return NULL;
id = (self->labelcount++);
* But I can't imagine a pituation where the output is truly unnecessary.
*/
+void _ast_codegen_output_type(ast_expression_common *self, ir_value *out)
+{
+ if (out->vtype == TYPE_FIELD)
+ out->fieldtype = self->next->expression.vtype;
+ if (out->vtype == TYPE_FUNCTION)
+ out->outtype = self->next->expression.vtype;
+}
+
+#define codegen_output_type(a,o) (_ast_codegen_output_type(&((a)->expression),(o)))
+#define codegen_output_type_expr(a,o) (_ast_codegen_output_type(a,(o)))
+
bool ast_value_codegen(ast_value *self, ast_function *func, bool lvalue, ir_value **out)
{
(void)func;
}
/* we are lame now - considering the way QC works we won't tolerate arrays > 1024 elements */
- if (!array->expression.count || array->expression.count > opts_max_array_size)
+ if (!array->expression.count || array->expression.count > opts.max_array_size)
compile_error(ast_ctx(self), "Invalid array of size %lu", (unsigned long)array->expression.count);
elemtype = &array->expression.next->expression;
compile_error(ast_ctx(self), "ir_builder_create_global failed on `%s`", self->name);
return false;
}
- if (vtype == TYPE_FIELD)
- v->fieldtype = elemtype->next->expression.vtype;
v->context = ast_ctx(self);
+ v->unique_life = true;
array->ir_v = self->ir_v = v;
namelen = strlen(self->name);
compile_error(ast_ctx(self), "ir_builder_create_global failed on `%s`", name);
return false;
}
- if (vtype == TYPE_FIELD)
- array->ir_values[ai]->fieldtype = elemtype->next->expression.vtype;
array->ir_values[ai]->context = ast_ctx(self);
+ array->ir_values[ai]->unique_life = true;
}
mem_d(name);
}
int vtype = elemtype->vtype;
/* same as with field arrays */
- if (!self->expression.count || self->expression.count > opts_max_array_size)
+ if (!self->expression.count || self->expression.count > opts.max_array_size)
compile_error(ast_ctx(self), "Invalid array of size %lu", (unsigned long)self->expression.count);
v = ir_builder_create_global(ir, self->name, vtype);
compile_error(ast_ctx(self), "ir_builder_create_global failed `%s`", self->name);
return false;
}
- if (vtype == TYPE_FIELD)
- v->fieldtype = elemtype->next->expression.vtype;
v->context = ast_ctx(self);
+ v->unique_life = true;
namelen = strlen(self->name);
name = (char*)mem_a(namelen + 16);
compile_error(ast_ctx(self), "ir_builder_create_global failed `%s`", name);
return false;
}
- if (vtype == TYPE_FIELD)
- self->ir_values[ai]->fieldtype = elemtype->next->expression.vtype;
self->ir_values[ai]->context = ast_ctx(self);
+ self->ir_values[ai]->unique_life = true;
}
mem_d(name);
}
compile_error(ast_ctx(self), "ir_builder_create_global failed on `%s`", self->name);
return false;
}
- if (self->expression.vtype == TYPE_FIELD)
- v->fieldtype = self->expression.next->expression.vtype;
+ codegen_output_type(self, v);
v->context = ast_ctx(self);
}
/* Cannot generate an IR value for a function,
* need a pointer pointing to a function rather.
*/
+ case TYPE_FIELD:
+ if (!self->constval.vfield) {
+ compile_error(ast_ctx(self), "field constant without vfield set");
+ goto error;
+ }
+ if (!self->constval.vfield->ir_v) {
+ compile_error(ast_ctx(self), "field constant generated before its field");
+ goto error;
+ }
+ if (!ir_value_set_field(v, self->constval.vfield->ir_v))
+ goto error;
+ break;
default:
compile_error(ast_ctx(self), "TODO: global constant type %i", self->expression.vtype);
break;
}
/* we are lame now - considering the way QC works we won't tolerate arrays > 1024 elements */
- if (!self->expression.count || self->expression.count > opts_max_array_size) {
+ if (!self->expression.count || self->expression.count > opts.max_array_size) {
compile_error(ast_ctx(self), "Invalid array of size %lu", (unsigned long)self->expression.count);
}
compile_error(ast_ctx(self), "ir_function_create_local failed");
return false;
}
- if (vtype == TYPE_FIELD)
- v->fieldtype = elemtype->next->expression.vtype;
v->context = ast_ctx(self);
+ v->unique_life = true;
namelen = strlen(self->name);
name = (char*)mem_a(namelen + 16);
compile_error(ast_ctx(self), "ir_builder_create_global failed on `%s`", name);
return false;
}
- if (vtype == TYPE_FIELD)
- self->ir_values[ai]->fieldtype = elemtype->next->expression.vtype;
self->ir_values[ai]->context = ast_ctx(self);
+ self->ir_values[ai]->unique_life = true;
}
}
else
v = ir_function_create_local(func, self->name, self->expression.vtype, param);
if (!v)
return false;
- if (self->expression.vtype == TYPE_FIELD)
- v->fieldtype = self->expression.next->expression.vtype;
+ codegen_output_type(self, v);
v->context = ast_ctx(self);
}
v->cvq = self->cvq;
self->ir_v = v;
+ if (!ast_generate_accessors(self, func->owner))
+ return false;
+ return true;
+
+error: /* clean up */
+ ir_value_delete(v);
+ return false;
+}
+
+bool ast_generate_accessors(ast_value *self, ir_builder *ir)
+{
+ size_t i;
+ bool warn = OPTS_WARN(WARN_USED_UNINITIALIZED);
+ if (!self->setter || !self->getter)
+ return true;
+ for (i = 0; i < self->expression.count; ++i) {
+ if (!self->ir_values) {
+ compile_error(ast_ctx(self), "internal error: no array values generated for `%s`", self->name);
+ return false;
+ }
+ if (!self->ir_values[i]) {
+ compile_error(ast_ctx(self), "internal error: not all array values have been generated for `%s`", self->name);
+ return false;
+ }
+ if (self->ir_values[i]->life) {
+ compile_error(ast_ctx(self), "internal error: function containing `%s` already generated", self->name);
+ return false;
+ }
+ }
+
+ opts_set(opts.warn, WARN_USED_UNINITIALIZED, false);
if (self->setter) {
- if (!ast_global_codegen(self->setter, func->owner, false) ||
- !ast_function_codegen(self->setter->constval.vfunc, func->owner) ||
+ if (!ast_global_codegen (self->setter, ir, false) ||
+ !ast_function_codegen(self->setter->constval.vfunc, ir) ||
!ir_function_finalize(self->setter->constval.vfunc->ir_func))
+ {
+ compile_error(ast_ctx(self), "internal error: failed to generate setter for `%s`", self->name);
+ opts_set(opts.warn, WARN_USED_UNINITIALIZED, warn);
return false;
+ }
}
if (self->getter) {
- if (!ast_global_codegen(self->getter, func->owner, false) ||
- !ast_function_codegen(self->getter->constval.vfunc, func->owner) ||
+ if (!ast_global_codegen (self->getter, ir, false) ||
+ !ast_function_codegen(self->getter->constval.vfunc, ir) ||
!ir_function_finalize(self->getter->constval.vfunc->ir_func))
+ {
+ compile_error(ast_ctx(self), "internal error: failed to generate getter for `%s`", self->name);
+ opts_set(opts.warn, WARN_USED_UNINITIALIZED, warn);
return false;
+ }
+ }
+ for (i = 0; i < self->expression.count; ++i) {
+ vec_free(self->ir_values[i]->life);
}
+ opts_set(opts.warn, WARN_USED_UNINITIALIZED, warn);
return true;
-
-error: /* clean up */
- ir_value_delete(v);
- return false;
}
bool ast_function_codegen(ast_function *self, ir_builder *ir)
ec = &self->vtype->expression;
for (i = 0; i < vec_size(ec->params); ++i)
{
- vec_push(irf->params, ec->params[i]->expression.vtype);
+ if (ec->params[i]->expression.vtype == TYPE_FIELD)
+ vec_push(irf->params, ec->params[i]->expression.next->expression.vtype);
+ else
+ 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;
if (!self->vtype->expression.next ||
self->vtype->expression.next->expression.vtype == TYPE_VOID)
{
- return ir_block_create_return(self->curblock, NULL);
+ return ir_block_create_return(self->curblock, ast_ctx(self), NULL);
}
else if (vec_size(self->curblock->entries))
{
{
return false;
}
- return ir_block_create_return(self->curblock, NULL);
+ return ir_block_create_return(self->curblock, ast_ctx(self), NULL);
}
}
return true;
for (i = 0; i < vec_size(self->locals); ++i)
{
if (!ast_local_codegen(self->locals[i], func->ir_func, false)) {
- if (opts_debug)
+ if (opts.debug)
compile_error(ast_ctx(self), "failed to generate local `%s`", self->locals[i]->name);
return false;
}
for (i = 0; i < vec_size(self->exprs); ++i)
{
- ast_expression_codegen *gen = self->exprs[i]->expression.codegen;
+ ast_expression_codegen *gen;
if (func->curblock->final && !ast_istype(self->exprs[i], ast_label)) {
- compile_error(ast_ctx(self->exprs[i]), "unreachable statement");
- return false;
+ if (compile_warning(ast_ctx(self->exprs[i]), WARN_UNREACHABLE_CODE, "unreachable statement"))
+ return false;
+ continue;
}
+ gen = self->exprs[i]->expression.codegen;
if (!(*gen)(self->exprs[i], func, false, out))
return false;
}
ai = (ast_array_index*)self->dest;
idx = (ast_value*)ai->index;
- if (ast_istype(ai->index, ast_value) && idx->hasvalue)
+ if (ast_istype(ai->index, ast_value) && idx->hasvalue && idx->cvq == CV_CONST)
ai = NULL;
}
if (!(*cgen)((ast_expression*)(self->source), func, false, &right))
return false;
- call = ir_block_create_call(func->curblock, ast_function_label(func, "store"), funval);
+ call = ir_block_create_call(func->curblock, ast_ctx(self), ast_function_label(func, "store"), funval, false);
if (!call)
return false;
ir_call_param(call, iridx);
if (!(*cgen)((ast_expression*)(self->source), func, false, &right))
return false;
- if (!ir_block_create_store_op(func->curblock, self->op, left, right))
+ if (!ir_block_create_store_op(func->curblock, ast_ctx(self), self->op, left, right))
return false;
self->expression.outr = right;
}
compile_error(ast_ctx(self), "don't know how to cast to bool...");
return false;
}
- left = ir_block_create_unary(func->curblock,
+ left = ir_block_create_unary(func->curblock, ast_ctx(self),
ast_function_label(func, "sce_not"),
notop,
left);
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))
+ if (!ir_block_create_if(func->curblock, ast_ctx(self), left, other, merge))
return false;
} else {
- if (!ir_block_create_if(func->curblock, left, merge, other))
+ if (!ir_block_create_if(func->curblock, ast_ctx(self), left, merge, other))
return false;
}
/* use the likely flag */
compile_error(ast_ctx(self), "don't know how to cast to bool...");
return false;
}
- right = ir_block_create_unary(func->curblock,
+ right = ir_block_create_unary(func->curblock, ast_ctx(self),
ast_function_label(func, "sce_not"),
notop,
right);
}
from_right = func->curblock;
- if (!ir_block_create_jump(func->curblock, merge))
+ if (!ir_block_create_jump(func->curblock, ast_ctx(self), 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);
+ phi = ir_block_create_phi(func->curblock, ast_ctx(self), 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);
compile_error(ast_ctx(self), "don't know how to cast to bool...");
return false;
}
- *out = ir_block_create_unary(func->curblock,
+ *out = ir_block_create_unary(func->curblock, ast_ctx(self),
ast_function_label(func, "sce_final_not"),
notop,
*out);
if (!(*cgen)((ast_expression*)(self->right), func, false, &right))
return false;
- *out = ir_block_create_binop(func->curblock, ast_function_label(func, "bin"),
+ *out = ir_block_create_binop(func->curblock, ast_ctx(self), ast_function_label(func, "bin"),
self->op, left, right);
if (!*out)
return false;
ai = (ast_array_index*)self->dest;
idx = (ast_value*)ai->index;
- if (ast_istype(ai->index, ast_value) && idx->hasvalue)
+ if (ast_istype(ai->index, ast_value) && idx->hasvalue && idx->cvq == CV_CONST)
ai = NULL;
}
return false;
/* now the binary */
- bin = ir_block_create_binop(func->curblock, ast_function_label(func, "binst"),
+ bin = ir_block_create_binop(func->curblock, ast_ctx(self), ast_function_label(func, "binst"),
self->opbin, leftr, right);
self->expression.outr = bin;
if (!(*cgen)((ast_expression*)(arr->setter), func, true, &funval))
return false;
- call = ir_block_create_call(func->curblock, ast_function_label(func, "store"), funval);
+ call = ir_block_create_call(func->curblock, ast_ctx(self), ast_function_label(func, "store"), funval, false);
if (!call)
return false;
ir_call_param(call, iridx);
return false;
self->expression.outl = leftl;
- if (!ir_block_create_store_op(func->curblock, self->opstore, leftl, bin))
+ if (!ir_block_create_store_op(func->curblock, ast_ctx(self), self->opstore, leftl, bin))
return false;
self->expression.outr = bin;
}
if (!(*cgen)((ast_expression*)(self->operand), func, false, &operand))
return false;
- *out = ir_block_create_unary(func->curblock, ast_function_label(func, "unary"),
+ *out = ir_block_create_unary(func->curblock, ast_ctx(self), ast_function_label(func, "unary"),
self->op, operand);
if (!*out)
return false;
if (!(*cgen)((ast_expression*)(self->operand), func, false, &operand))
return false;
- if (!ir_block_create_return(func->curblock, operand))
+ if (!ir_block_create_return(func->curblock, ast_ctx(self), operand))
return false;
} else {
- if (!ir_block_create_return(func->curblock, NULL))
+ if (!ir_block_create_return(func->curblock, ast_ctx(self), NULL))
return false;
}
if (lvalue) {
/* address! */
- *out = ir_block_create_fieldaddress(func->curblock, ast_function_label(func, "efa"),
+ *out = ir_block_create_fieldaddress(func->curblock, ast_ctx(self), ast_function_label(func, "efa"),
ent, field);
} else {
- *out = ir_block_create_load_from_ent(func->curblock, ast_function_label(func, "efv"),
+ *out = ir_block_create_load_from_ent(func->curblock, ast_ctx(self), ast_function_label(func, "efv"),
ent, field, self->expression.vtype);
+ /* Done AFTER error checking:
+ codegen_output_type(self, *out);
+ */
}
if (!*out) {
compile_error(ast_ctx(self), "failed to create %s instruction (output type %s)",
type_name[self->expression.vtype]);
return false;
}
+ if (!lvalue)
+ codegen_output_type(self, *out);
if (lvalue)
self->expression.outl = *out;
if (!(*cgen)((ast_expression*)(arr->getter), func, true, &funval))
return false;
- call = ir_block_create_call(func->curblock, ast_function_label(func, "fetch"), funval);
+ call = ir_block_create_call(func->curblock, ast_ctx(self), ast_function_label(func, "fetch"), funval, false);
if (!call)
return false;
ir_call_param(call, iridx);
ir_value *condval;
ir_value *dummy;
- ir_block *cond = func->curblock;
+ ir_block *cond;
ir_block *ontrue;
ir_block *onfalse;
ir_block *ontrue_endblock = NULL;
if (!merge)
return false;
/* add jumps ot the merge block */
- if (ontrue && !ontrue_endblock->final && !ir_block_create_jump(ontrue_endblock, merge))
+ if (ontrue && !ontrue_endblock->final && !ir_block_create_jump(ontrue_endblock, ast_ctx(self), merge))
return false;
- if (onfalse && !onfalse_endblock->final && !ir_block_create_jump(onfalse_endblock, merge))
+ if (onfalse && !onfalse_endblock->final && !ir_block_create_jump(onfalse_endblock, ast_ctx(self), merge))
return false;
/* Now enter the merge block */
/* we create the if here, that way all blocks are ordered :)
*/
- if (!ir_block_create_if(cond, condval,
+ if (!ir_block_create_if(cond, ast_ctx(self), condval,
(ontrue ? ontrue : merge),
(onfalse ? onfalse : merge)))
{
if (!merge)
return false;
/* jump to merge block */
- if (!ir_block_create_jump(ontrue_out, merge))
+ if (!ir_block_create_jump(ontrue_out, ast_ctx(self), merge))
return false;
- if (!ir_block_create_jump(onfalse_out, merge))
+ if (!ir_block_create_jump(onfalse_out, ast_ctx(self), merge))
return false;
/* create if instruction */
- if (!ir_block_create_if(cond_out, condval, ontrue, onfalse))
+ if (!ir_block_create_if(cond_out, ast_ctx(self), condval, ontrue, onfalse))
return false;
/* Now enter the merge block */
}
/* create PHI */
- phi = ir_block_create_phi(merge, ast_function_label(func, "phi"), trueval->vtype);
+ phi = ir_block_create_phi(merge, ast_ctx(self), ast_function_label(func, "phi"), trueval->vtype);
if (!phi)
return false;
ir_phi_add(phi, ontrue_out, trueval);
self->expression.outr = ir_phi_value(phi);
*out = self->expression.outr;
+ codegen_output_type(self, *out);
+
return true;
}
bbreak = bout;
/* The loop body... */
- if (self->body)
+ /* if (self->body) */
{
bbody = ir_function_create_block(ast_ctx(self), func->ir_func, ast_function_label(func, "loop_body"));
if (!bbody)
func->continueblock = bbody;
/* generate */
- cgen = self->body->expression.codegen;
- if (!(*cgen)((ast_expression*)(self->body), func, false, &dummy))
- return false;
+ if (self->body) {
+ cgen = self->body->expression.codegen;
+ if (!(*cgen)((ast_expression*)(self->body), func, false, &dummy))
+ return false;
+ }
end_bbody = func->curblock;
func->breakblock = old_bbreak;
else if (bbody) tmpblock = bbody;
else if (bpostcond) tmpblock = bpostcond;
else tmpblock = bout;
- if (!ir_block_create_jump(bin, tmpblock))
+ if (!ir_block_create_jump(bin, ast_ctx(self), tmpblock))
return false;
/* From precond */
else if (bpostcond) ontrue = bpostcond;
else ontrue = bprecond;
onfalse = bout;
- if (!ir_block_create_if(end_bprecond, precond, ontrue, onfalse))
+ if (!ir_block_create_if(end_bprecond, ast_ctx(self), precond, ontrue, onfalse))
return false;
}
else if (bpostcond) tmpblock = bpostcond;
else if (bprecond) tmpblock = bprecond;
else tmpblock = bbody;
- if (!end_bbody->final && !ir_block_create_jump(end_bbody, tmpblock))
+ if (!end_bbody->final && !ir_block_create_jump(end_bbody, ast_ctx(self), tmpblock))
return false;
}
else if (bprecond) tmpblock = bprecond;
else if (bbody) tmpblock = bbody;
else tmpblock = bout;
- if (!ir_block_create_jump(end_bincrement, tmpblock))
+ if (!ir_block_create_jump(end_bincrement, ast_ctx(self), tmpblock))
return false;
}
else if (bincrement) ontrue = bincrement;
else ontrue = bpostcond;
onfalse = bout;
- if (!ir_block_create_if(end_bpostcond, postcond, ontrue, onfalse))
+ if (!ir_block_create_if(end_bpostcond, ast_ctx(self), postcond, ontrue, onfalse))
return false;
}
return false;
}
- if (!ir_block_create_jump(func->curblock, target))
+ if (!ir_block_create_jump(func->curblock, ast_ctx(self), target))
return false;
return true;
}
{
ast_expression_codegen *cgen;
- ast_switch_case *def_case = NULL;
- ir_block *def_bfall = NULL;
+ ast_switch_case *def_case = NULL;
+ ir_block *def_bfall = NULL;
+ ir_block *def_bfall_to = NULL;
+ bool set_def_bfall_to = false;
ir_value *dummy = NULL;
ir_value *irop = NULL;
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);
+ cond = ir_block_create_binop(func->curblock, ast_ctx(self), ast_function_label(func, "switch_eq"), cmpinstr, irop, val);
if (!cond)
return false;
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))
+ if (set_def_bfall_to) {
+ set_def_bfall_to = false;
+ def_bfall_to = bcase;
+ }
+ if (!ir_block_create_if(func->curblock, ast_ctx(self), cond, bcase, bnot))
return false;
/* Make the previous case-end fall through */
if (bfall && !bfall->final) {
- if (!ir_block_create_jump(bfall, bcase))
+ if (!ir_block_create_jump(bfall, ast_ctx(self), bcase))
return false;
}
bfall = NULL;
/* remember which case it was */
def_case = swcase;
+ /* And the next case will be remembered */
+ set_def_bfall_to = true;
}
}
/* Jump from the last bnot to bout */
- if (bfall && !bfall->final && !ir_block_create_jump(bfall, bout)) {
+ if (bfall && !bfall->final && !ir_block_create_jump(bfall, ast_ctx(self), bout)) {
/*
astwarning(ast_ctx(bfall), WARN_???, "missing break after last case");
*/
/* Insert the fallthrough jump */
if (def_bfall && !def_bfall->final) {
- if (!ir_block_create_jump(def_bfall, bcase))
+ if (!ir_block_create_jump(def_bfall, ast_ctx(self), bcase))
return false;
}
cgen = def_case->code->expression.codegen;
if (!(*cgen)((ast_expression*)def_case->code, func, false, &dummy))
return false;
+
+ /* see if we need to fall through */
+ if (def_bfall_to && !func->curblock->final)
+ {
+ if (!ir_block_create_jump(func->curblock, ast_ctx(self), def_bfall_to))
+ return false;
+ }
}
/* Jump from the last bnot to bout */
- if (!func->curblock->final && !ir_block_create_jump(func->curblock, bout))
+ if (!func->curblock->final && !ir_block_create_jump(func->curblock, ast_ctx(self), bout))
return false;
/* enter the outgoing block */
func->curblock = bout;
return false;
}
if (!func->curblock->final) {
- if (!ir_block_create_jump(func->curblock, self->irblock))
+ if (!ir_block_create_jump(func->curblock, ast_ctx(self), self->irblock))
return false;
}
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)) {
+ if (!ir_block_create_jump(self->irblock_from, ast_ctx(self), self->target->irblock)) {
compile_error(ast_ctx(self), "failed to generate goto to `%s`", self->name);
return false;
}
}
else
{
- if (!ir_block_create_jump(func->curblock, self->target->irblock)) {
+ if (!ir_block_create_jump(func->curblock, ast_ctx(self), self->target->irblock)) {
compile_error(ast_ctx(self), "failed to generate goto to `%s`", self->name);
return false;
}
vec_push(params, param);
}
- callinstr = ir_block_create_call(func->curblock, ast_function_label(func, "call"), funval);
+ callinstr = ir_block_create_call(func->curblock, ast_ctx(self),
+ ast_function_label(func, "call"),
+ funval, !!(self->func->expression.flags & AST_FLAG_NORETURN));
if (!callinstr)
goto error;
*out = ir_call_value(callinstr);
self->expression.outr = *out;
+ codegen_output_type(self, *out);
+
vec_free(params);
return true;
error: