self->name = name ? util_strdup(name) : NULL;
self->expression.vtype = t;
self->expression.next = NULL;
- self->constant = false;
+ self->isfield = false;
+ self->cvq = CV_NONE;
self->hasvalue = false;
self->uses = 0;
memset(&self->constval, 0, sizeof(self->constval));
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;
}
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);
* 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;
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);
array->ir_v = self->ir_v = v;
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);
}
mem_d(name);
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);
namelen = strlen(self->name);
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);
}
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;
}
/* link us to the ir_value */
+ v->cvq = self->cvq;
self->ir_v = v;
return true;
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);
namelen = strlen(self->name);
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);
}
}
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);
}
}
/* link us to the ir_value */
+ v->cvq = self->cvq;
self->ir_v = v;
if (self->setter) {
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;
/* TODO: check return types */
if (!self->curblock->is_return)
{
- /*
- return ir_block_create_return(self->curblock, NULL);
- */
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))
{
/* error("missing return"); */
if (compile_warning(ast_ctx(self), WARN_MISSING_RETURN_VALUES,
- "control reaches end of non-void function (`%s`)",
- self->name))
+ "control reaches end of non-void function (`%s`) via %s",
+ self->name, self->curblock->label))
{
return false;
}
+ return ir_block_create_return(self->curblock, ast_ctx(self), NULL);
}
}
return true;
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);
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);
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);
+ codegen_output_type(self, *out);
}
if (!*out) {
compile_error(ast_ctx(self), "failed to create %s instruction (output type %s)",
arr = (ast_value*)self->array;
idx = (ast_value*)self->index;
- if (!ast_istype(self->index, ast_value) || !idx->hasvalue) {
+ if (!ast_istype(self->index, ast_value) || !idx->hasvalue || idx->cvq != CV_CONST) {
/* Time to use accessor functions */
ast_expression_codegen *cgen;
ir_value *iridx, *funval;
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);
if (!call)
return false;
ir_call_param(call, iridx);
return true;
}
- if (idx->expression.vtype == TYPE_FLOAT)
- *out = arr->ir_values[(int)idx->constval.vfloat];
- else if (idx->expression.vtype == TYPE_INTEGER)
- *out = arr->ir_values[idx->constval.vint];
+ if (idx->expression.vtype == TYPE_FLOAT) {
+ unsigned int arridx = idx->constval.vfloat;
+ if (arridx >= self->array->expression.count)
+ {
+ compile_error(ast_ctx(self), "array index out of bounds: %i", arridx);
+ return false;
+ }
+ *out = arr->ir_values[arridx];
+ }
+ else if (idx->expression.vtype == TYPE_INTEGER) {
+ unsigned int arridx = idx->constval.vint;
+ if (arridx >= self->array->expression.count)
+ {
+ compile_error(ast_ctx(self), "array index out of bounds: %i", arridx);
+ return false;
+ }
+ *out = arr->ir_values[arridx];
+ }
else {
compile_error(ast_ctx(self), "array indexing here needs an integer constant");
return false;
ir_block *onfalse;
ir_block *ontrue_endblock = NULL;
ir_block *onfalse_endblock = NULL;
- ir_block *merge;
+ ir_block *merge = NULL;
/* We don't output any value, thus also don't care about r/lvalue */
(void)out;
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))
- return false;
-
- /* we create the if here, that way all blocks are ordered :)
- */
- if (!ir_block_create_if(cond, condval,
- (ontrue ? ontrue : merge),
- (onfalse ? onfalse : merge)))
- {
+ if (onfalse && !onfalse_endblock->final && !ir_block_create_jump(onfalse_endblock, ast_ctx(self), merge))
return false;
- }
/* Now enter the merge block */
func->curblock = merge;
}
+ /* we create the if here, that way all blocks are ordered :)
+ */
+ if (!ir_block_create_if(cond, ast_ctx(self), condval,
+ (ontrue ? ontrue : merge),
+ (onfalse ? onfalse : merge)))
+ {
+ return false;
+ }
+
return true;
}
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);
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;
}
if (bincrement) tmpblock = bincrement;
else if (bpostcond) tmpblock = bpostcond;
else if (bprecond) tmpblock = bprecond;
- else tmpblock = bout;
- if (!end_bbody->final && !ir_block_create_jump(end_bbody, tmpblock))
+ else tmpblock = bbody;
+ 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;
}
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 (!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;
}
}
/* 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;
}
}
/* 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);
if (!callinstr)
goto error;
*out = ir_call_value(callinstr);
self->expression.outr = *out;
+ codegen_output_type(self, *out);
+
vec_free(params);
return true;
error: