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));
{
if (self->name)
mem_d((void*)self->name);
- if (self->isconst) {
+ if (self->hasvalue) {
switch (self->expression.vtype)
{
case TYPE_STRING:
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);
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);
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)
{
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;
self->breakblock = NULL;
self->continueblock = NULL;
- vtype->isconst = true;
+ vtype->hasvalue = true;
vtype->constval.vfunc = self;
return 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*
{
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)
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;
}
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)
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)
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)
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)
*/
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)
v->context = ast_ctx(self);
}
- if (self->isconst) {
+ if (self->hasvalue) {
switch (self->expression.vtype)
{
case TYPE_FLOAT:
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.
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)
/* 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:
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;
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;
}
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;
}
*/
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))
}
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;
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;
}
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;
}
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;
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;
/* 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;
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 */
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... */
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
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
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 */
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;
*/
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;
* 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 */
}
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 */
}
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;
/* 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;
old_bcontinue = func->continueblock;
func->breakblock = bbreak;
func->continueblock = bcontinue;
+ if (!func->continueblock)
+ func->continueblock = bbody;
/* generate */
cgen = self->body->expression.codegen;
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;
}
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;
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))
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;