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)
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;
}
if (!(*cgen)((ast_expression*)(self->source), func, false, &right))
return false;
- call = ir_block_create_call(func->curblock, ast_ctx(self), 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*)(arr->setter), func, true, &funval))
return false;
- call = ir_block_create_call(func->curblock, ast_ctx(self), 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);
} else {
*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_ctx(self), 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;
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;
{
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;
bnot = ir_function_create_block(ast_ctx(self), func->ir_func, ast_function_label(func, "not_case"));
if (!bcase || !bnot)
return false;
+ 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;
bfall = NULL;
/* remember which case it was */
def_case = swcase;
+ /* And the next case will be remembered */
+ set_def_bfall_to = true;
}
}
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 */
vec_push(params, param);
}
- callinstr = ir_block_create_call(func->curblock, ast_ctx(self), 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: