MEM_VECTOR_INIT(self, functions);
MEM_VECTOR_INIT(self, globals);
self->name = NULL;
- ir_builder_set_name(self, modulename);
+ if (!ir_builder_set_name(self, modulename)) {
+ mem_d(self);
+ return NULL;
+ }
/* globals which always exist */
mem_d(self);
}
-void ir_builder_set_name(ir_builder *self, const char *name)
+bool ir_builder_set_name(ir_builder *self, const char *name)
{
if (self->name)
mem_d((void*)self->name);
self->name = util_strdup(name);
+ return !!self->name;
}
ir_function* ir_builder_get_function(ir_builder *self, const char *name)
}
fn = ir_function_new(self);
- ir_function_set_name(fn, name);
- ir_builder_functions_add(self, fn);
+ if (!ir_function_set_name(fn, name) ||
+ !ir_builder_functions_add(self, fn) )
+ {
+ ir_function_delete(fn);
+ return NULL;
+ }
return fn;
}
}
ve = ir_value_var(name, store_global, vtype);
- ir_builder_globals_add(self, ve);
+ if (!ir_builder_globals_add(self, ve)) {
+ ir_value_delete(ve);
+ return NULL;
+ }
return ve;
}
*IR Function
*/
-void ir_function_naive_phi(ir_function*);
+bool ir_function_naive_phi(ir_function*);
void ir_function_enumerate(ir_function*);
-void ir_function_calculate_liferanges(ir_function*);
+bool ir_function_calculate_liferanges(ir_function*);
ir_function* ir_function_new(ir_builder* owner)
{
ir_function *self;
self = (ir_function*)mem_a(sizeof(*self));
+ if (!ir_function_set_name(self, "<@unnamed>")) {
+ mem_d(self);
+ return NULL;
+ }
self->owner = owner;
self->context.file = "<@no context>";
self->context.line = 0;
MEM_VECTOR_INIT(self, blocks);
MEM_VECTOR_INIT(self, values);
MEM_VECTOR_INIT(self, locals);
- ir_function_set_name(self, "<@unnamed>");
self->run_id = 0;
return self;
MEM_VEC_FUNCTIONS(ir_function, ir_block*, blocks)
MEM_VEC_FUNCTIONS(ir_function, ir_value*, locals)
-void ir_function_set_name(ir_function *self, const char *name)
+bool ir_function_set_name(ir_function *self, const char *name)
{
if (self->name)
mem_d((void*)self->name);
self->name = util_strdup(name);
+ return !!self->name;
}
void ir_function_delete(ir_function *self)
mem_d(self);
}
-void ir_function_collect_value(ir_function *self, ir_value *v)
+bool GMQCC_WARN ir_function_collect_value(ir_function *self, ir_value *v)
{
- ir_function_values_add(self, v);
+ return ir_function_values_add(self, v);
}
ir_block* ir_function_create_block(ir_function *self, const char *label)
{
ir_block* bn = ir_block_new(self, label);
memcpy(&bn->context, &self->context, sizeof(self->context));
- ir_function_blocks_add(self, bn);
+ if (!ir_function_blocks_add(self, bn)) {
+ ir_block_delete(bn);
+ return NULL;
+ }
return bn;
}
-void ir_function_finalize(ir_function *self)
+bool ir_function_finalize(ir_function *self)
{
- ir_function_naive_phi(self);
+ if (!ir_function_naive_phi(self))
+ return false;
+
ir_function_enumerate(self);
- ir_function_calculate_liferanges(self);
+
+ if (!ir_function_calculate_liferanges(self))
+ return false;
+ return true;
}
ir_value* ir_function_get_local(ir_function *self, const char *name)
}
ve = ir_value_var(name, store_local, vtype);
- ir_function_locals_add(self, ve);
+ if (!ir_function_locals_add(self, ve)) {
+ ir_value_delete(ve);
+ return NULL;
+ }
return ve;
}
{
ir_block *self;
self = (ir_block*)mem_a(sizeof(*self));
+ if (!ir_block_set_label(self, name)) {
+ mem_d(self);
+ return NULL;
+ }
self->owner = owner;
self->context.file = "<@no context>";
self->context.line = 0;
MEM_VECTOR_INIT(self, entries);
MEM_VECTOR_INIT(self, exits);
self->label = NULL;
- ir_block_set_label(self, name);
self->eid = 0;
self->is_return = false;
mem_d(self);
}
-void ir_block_set_label(ir_block *self, const char *name)
+bool ir_block_set_label(ir_block *self, const char *name)
{
if (self->label)
mem_d((void*)self->label);
self->label = util_strdup(name);
+ return !!self->label;
}
/***********************************************************************
void ir_instr_delete(ir_instr *self)
{
- ir_instr_op(self, 0, NULL, false);
- ir_instr_op(self, 1, NULL, false);
- ir_instr_op(self, 2, NULL, false);
+ size_t i;
+ /* The following calls can only delete from
+ * vectors, we still want to delete this instruction
+ * so ignore the return value. Since with the warn_unused_result attribute
+ * gcc doesn't care about an explicit: (void)foo(); to ignore the result,
+ * I have to improvise here and use if(foo());
+ */
+ for (i = 0; i < self->phi_count; ++i) {
+ size_t idx;
+ if (ir_value_writes_find(self->phi[i].value, self, &idx))
+ if (ir_value_writes_remove(self->phi[i].value, idx));
+ if (ir_value_reads_find(self->phi[i].value, self, &idx))
+ if (ir_value_reads_remove(self->phi[i].value, idx));
+ }
MEM_VECTOR_CLEAR(self, phi);
+ if (ir_instr_op(self, 0, NULL, false));
+ if (ir_instr_op(self, 1, NULL, false));
+ if (ir_instr_op(self, 2, NULL, false));
mem_d(self);
}
-void ir_instr_op(ir_instr *self, int op, ir_value *v, bool writing)
+bool ir_instr_op(ir_instr *self, int op, ir_value *v, bool writing)
{
if (self->_ops[op]) {
- if (writing)
- ir_value_writes_add(self->_ops[op], self);
- else
- ir_value_reads_add(self->_ops[op], self);
+ size_t idx;
+ if (writing && ir_value_writes_find(self->_ops[op], self, &idx))
+ {
+ if (!ir_value_writes_remove(self->_ops[op], idx))
+ return false;
+ }
+ else if (ir_value_reads_find(self->_ops[op], self, &idx))
+ {
+ if (!ir_value_reads_remove(self->_ops[op], idx))
+ return false;
+ }
}
if (v) {
- if (writing)
- ir_value_writes_add(v, self);
- else
- ir_value_reads_add(v, self);
+ if (writing) {
+ if (!ir_value_writes_add(v, self))
+ return false;
+ } else {
+ if (!ir_value_reads_add(v, self))
+ return false;
+ }
}
self->_ops[op] = v;
+ return true;
}
/***********************************************************************
return self;
}
MEM_VEC_FUNCTIONS(ir_value, ir_life_entry_t, life)
-MEM_VEC_FUNCTIONS(ir_value, ir_instr*, reads)
-MEM_VEC_FUNCTIONS(ir_value, ir_instr*, writes)
+MEM_VEC_FUNCTIONS_ALL(ir_value, ir_instr*, reads)
+MEM_VEC_FUNCTIONS_ALL(ir_value, ir_instr*, writes)
ir_value* ir_value_out(ir_function *owner, const char *name, int storetype, int vtype)
{
ir_value *v = ir_value_var(name, storetype, vtype);
- ir_function_collect_value(owner, v);
+ if (!v)
+ return NULL;
+ if (!ir_function_collect_value(owner, v))
+ {
+ ir_value_delete(v);
+ return NULL;
+ }
return v;
}
return false;
}
-void ir_value_life_insert(ir_value *self, size_t idx, ir_life_entry_t e)
+bool ir_value_life_insert(ir_value *self, size_t idx, ir_life_entry_t e)
{
size_t k;
- ir_value_life_add(self, e); /* naive... */
+ if (!ir_value_life_add(self, e)) /* naive... */
+ return false;
for (k = self->life_count-1; k > idx; --k)
self->life[k] = self->life[k-1];
self->life[idx] = e;
+ return true;
}
bool ir_value_life_merge(ir_value *self, size_t s)
return false;
ir_life_entry_t e;
e.start = e.end = s;
- ir_value_life_add(self, e);
+ if (!ir_value_life_add(self, e))
+ return false; /* failing */
return true;
}
/* found */
{
/* merge */
before->end = life->end;
- ir_value_life_remove(self, i);
+ if (!ir_value_life_remove(self, i))
+ return false; /* failing */
return true;
}
if (before->end + 1 == s)
}
/* insert a new entry */
new_entry.start = new_entry.end = s;
- ir_value_life_insert(self, i, new_entry);
- return true;
+ return ir_value_life_insert(self, i, new_entry);
}
/***********************************************************************
return false;
} else {
ir_instr *in = ir_instr_new(self, op);
- ir_instr_op(in, 0, target, true);
- ir_instr_op(in, 1, what, false);
- ir_block_instr_add(self, in);
+ if (!in)
+ return false;
+ if (!ir_instr_op(in, 0, target, true) ||
+ !ir_instr_op(in, 1, what, false) ||
+ !ir_block_instr_add(self, in) )
+ {
+ return false;
+ }
return true;
}
}
return ir_block_create_store_op(self, op, target, what);
}
-void ir_block_create_return(ir_block *self, ir_value *v)
+bool ir_block_create_return(ir_block *self, ir_value *v)
{
ir_instr *in;
if (self->final) {
fprintf(stderr, "block already ended (%s)\n", self->label);
- return;
+ return false;
}
self->final = true;
self->is_return = true;
in = ir_instr_new(self, INSTR_RETURN);
- ir_instr_op(in, 0, v, false);
- ir_block_instr_add(self, in);
+ if (!in)
+ return false;
+
+ if (!ir_instr_op(in, 0, v, false) ||
+ !ir_block_instr_add(self, in) )
+ {
+ return false;
+ }
+ return true;
}
-void ir_block_create_if(ir_block *self, ir_value *v,
+bool ir_block_create_if(ir_block *self, ir_value *v,
ir_block *ontrue, ir_block *onfalse)
{
ir_instr *in;
if (self->final) {
fprintf(stderr, "block already ended (%s)\n", self->label);
- return;
+ return false;
}
self->final = true;
//in = ir_instr_new(self, (v->vtype == qc_string ? INSTR_IF_S : INSTR_IF_F));
in = ir_instr_new(self, VINSTR_COND);
- ir_instr_op(in, 0, v, false);
+ if (!in)
+ return false;
+
+ if (!ir_instr_op(in, 0, v, false)) {
+ ir_instr_delete(in);
+ return false;
+ }
+
in->bops[0] = ontrue;
in->bops[1] = onfalse;
- ir_block_instr_add(self, in);
- ir_block_exits_add(self, ontrue);
- ir_block_exits_add(self, onfalse);
- ir_block_entries_add(ontrue, self);
- ir_block_entries_add(onfalse, self);
+ if (!ir_block_instr_add(self, in))
+ return false;
+
+ if (!ir_block_exits_add(self, ontrue) ||
+ !ir_block_exits_add(self, onfalse) ||
+ !ir_block_entries_add(ontrue, self) ||
+ !ir_block_entries_add(onfalse, self) )
+ {
+ return false;
+ }
+ return true;
}
-void ir_block_create_jump(ir_block *self, ir_block *to)
+bool ir_block_create_jump(ir_block *self, ir_block *to)
{
ir_instr *in;
if (self->final) {
fprintf(stderr, "block already ended (%s)\n", self->label);
- return;
+ return false;
}
self->final = true;
in = ir_instr_new(self, VINSTR_JUMP);
+ if (!in)
+ return false;
+
in->bops[0] = to;
- ir_block_instr_add(self, in);
+ if (!ir_block_instr_add(self, in))
+ return false;
- ir_block_exits_add(self, to);
- ir_block_entries_add(to, self);
+ if (!ir_block_exits_add(self, to) ||
+ !ir_block_entries_add(to, self) )
+ {
+ return false;
+ }
+ return true;
}
-void ir_block_create_goto(ir_block *self, ir_block *to)
+bool ir_block_create_goto(ir_block *self, ir_block *to)
{
ir_instr *in;
if (self->final) {
fprintf(stderr, "block already ended (%s)\n", self->label);
- return;
+ return false;
}
self->final = true;
in = ir_instr_new(self, INSTR_GOTO);
+ if (!in)
+ return false;
+
in->bops[0] = to;
- ir_block_instr_add(self, in);
+ if (!ir_block_instr_add(self, in))
+ return false;
- ir_block_exits_add(self, to);
- ir_block_entries_add(to, self);
+ if (!ir_block_exits_add(self, to) ||
+ !ir_block_entries_add(to, self) )
+ {
+ return false;
+ }
+ return true;
}
ir_instr* ir_block_create_phi(ir_block *self, const char *label, int ot)
ir_value *out;
ir_instr *in;
in = ir_instr_new(self, VINSTR_PHI);
+ if (!in)
+ return NULL;
out = ir_value_out(self->owner, label, store_local, ot);
- ir_instr_op(in, 0, out, true);
- ir_block_instr_add(self, in);
+ if (!out) {
+ ir_instr_delete(in);
+ return NULL;
+ }
+ if (!ir_instr_op(in, 0, out, true)) {
+ ir_instr_delete(in);
+ ir_value_delete(out);
+ return NULL;
+ }
+ if (!ir_block_instr_add(self, in)) {
+ ir_instr_delete(in);
+ ir_value_delete(out);
+ return NULL;
+ }
return in;
}
return self->_ops[0];
}
-void ir_phi_add(ir_instr* self, ir_block *b, ir_value *v)
+bool ir_phi_add(ir_instr* self, ir_block *b, ir_value *v)
{
ir_phi_entry_t pe;
pe.value = v;
pe.from = b;
- ir_value_reads_add(v, self);
- ir_instr_phi_add(self, pe);
+ if (!ir_value_reads_add(v, self))
+ return false;
+ return ir_instr_phi_add(self, pe);
}
/* binary op related code */
};
if (ot == qc_void) {
/* The AST or parser were supposed to check this! */
- abort();
return NULL;
}
+
ir_value *out = ir_value_out(self->owner, label, store_local, ot);
+ if (!out)
+ return NULL;
+
ir_instr *in = ir_instr_new(self, opcode);
- ir_instr_op(in, 0, out, true);
- ir_instr_op(in, 1, left, false);
- ir_instr_op(in, 2, right, false);
- ir_block_instr_add(self, in);
+ if (!in) {
+ ir_value_delete(out);
+ return NULL;
+ }
+
+ if (!ir_instr_op(in, 0, out, true) ||
+ !ir_instr_op(in, 1, left, false) ||
+ !ir_instr_op(in, 2, right, false) )
+ {
+ goto on_error;
+ }
+
+ if (!ir_block_instr_add(self, in))
+ goto on_error;
+
return out;
+on_error:
+ ir_value_delete(out);
+ ir_instr_delete(in);
+ return NULL;
}
ir_value* ir_block_create_add(ir_block *self,
* step before life-range calculation.
*/
-static void ir_block_naive_phi(ir_block *self);
-void ir_function_naive_phi(ir_function *self)
+static bool ir_block_naive_phi(ir_block *self);
+bool ir_function_naive_phi(ir_function *self)
{
size_t i;
for (i = 0; i < self->blocks_count; ++i)
- ir_block_naive_phi(self->blocks[i]);
+ {
+ if (!ir_block_naive_phi(self->blocks[i]))
+ return false;
+ }
+ return true;
}
-static void ir_naive_phi_emit_store(ir_block *block, size_t iid, ir_value *old, ir_value *what)
+static bool ir_naive_phi_emit_store(ir_block *block, size_t iid, ir_value *old, ir_value *what)
{
ir_instr *instr;
size_t i;
for (i = block->instr_count; i > iid; --i)
block->instr[i] = block->instr[i-1];
block->instr[i] = instr;
+
+ return true;
}
-static void ir_block_naive_phi(ir_block *self)
+static bool ir_block_naive_phi(ir_block *self)
{
size_t i, p, w;
/* FIXME: optionally, create_phi can add the phis
if (instr->opcode != VINSTR_PHI)
continue;
- ir_block_instr_remove(self, i);
+ if (!ir_block_instr_remove(self, i))
+ return false;
--i; /* NOTE: i+1 below */
for (p = 0; p < instr->phi_count; ++p)
}
ir_instr_delete(instr);
}
+ return true;
}
/***********************************************************************
}
}
-static void ir_block_life_propagate(ir_block *b, ir_block *prev, bool *changed);
-void ir_function_calculate_liferanges(ir_function *self)
+static bool ir_block_life_propagate(ir_block *b, ir_block *prev, bool *changed);
+bool ir_function_calculate_liferanges(ir_function *self)
{
size_t i;
bool changed;
for (i = 0; i != self->blocks_count; ++i)
{
if (self->blocks[i]->is_return)
- ir_block_life_propagate(self->blocks[i], NULL, &changed);
+ {
+ if (!ir_block_life_propagate(self->blocks[i], NULL, &changed))
+ return false;
+ }
}
} while (changed);
+ return true;
}
/* Get information about which operand
return changed;
}
-static void ir_block_life_prop_previous(ir_block* self, ir_block *prev, bool *changed)
+static bool ir_block_life_prop_previous(ir_block* self, ir_block *prev, bool *changed)
{
size_t i;
/* values which have been read in a previous iteration are now
for (i = 0; i < self->living_count; ++i)
{
if (!ir_block_living_find(prev, self->living[i], NULL)) {
- ir_block_living_remove(self, i);
+ if (!ir_block_living_remove(self, i))
+ return false;
--i;
}
}
{
if (ir_block_living_find(self, prev->living[i], NULL))
continue;
- ir_block_living_add(self, prev->living[i]);
+ if (!ir_block_living_add(self, prev->living[i]))
+ return false;
/*
printf("%s got from prev: %s\n", self->label, prev->living[i]->_name);
*/
}
}
-static void ir_block_life_propagate(ir_block *self, ir_block *prev, bool *changed)
+static bool ir_block_life_propagate(ir_block *self, ir_block *prev, bool *changed)
{
ir_instr *instr;
ir_value *value;
MEM_VECTOR_INIT(&new_reads, v);
if (prev)
- ir_block_life_prop_previous(self, prev, changed);
+ {
+ if (!ir_block_life_prop_previous(self, prev, changed))
+ return false;
+ }
i = self->instr_count;
while (i)
*/
/* fprintf(stderr, "read: %s\n", value->_name); */
if (!new_reads_t_v_find(&new_reads, value, NULL))
- new_reads_t_v_add(&new_reads, value);
+ {
+ if (!new_reads_t_v_add(&new_reads, value))
+ goto on_error;
+ }
}
/* See which operands are read and write operands */
*/
/* fprintf(stderr, "read: %s\n", value->_name); */
if (!new_reads_t_v_find(&new_reads, value, NULL))
- new_reads_t_v_add(&new_reads, value);
+ {
+ if (!new_reads_t_v_add(&new_reads, value))
+ goto on_error;
+ }
}
/* write operands */
*/
*changed = *changed || tempbool;
/* Then remove */
- ir_block_living_remove(self, idx);
+ if (!ir_block_living_remove(self, idx))
+ goto on_error;
if (in_reads)
- new_reads_t_v_remove(&new_reads, readidx);
+ {
+ if (!new_reads_t_v_remove(&new_reads, readidx))
+ goto on_error;
+ }
}
}
}
for (rd = 0; rd < new_reads.v_count; ++rd)
{
if (!ir_block_living_find(self, new_reads.v[rd], NULL)) {
- ir_block_living_add(self, new_reads.v[rd]);
+ if (!ir_block_living_add(self, new_reads.v[rd]))
+ goto on_error;
}
if (!i && !self->entries_count) {
/* fix the top */
*changed = *changed || ir_value_life_merge(new_reads.v[rd], instr->eid);
}
}
- new_reads_t_v_clear(&new_reads);
+ MEM_VECTOR_CLEAR(&new_reads, v);
}
if (self->run_id == self->owner->run_id)
ir_block *entry = self->entries[i];
ir_block_life_propagate(entry, self, changed);
}
+
+ return true;
+on_error:
+ MEM_VECTOR_CLEAR(&new_reads, v);
+ return false;
}
void ir_value_delete(ir_value*);
void ir_value_set_name(ir_value*, const char *name);
-MEM_VECTOR_PROTO(ir_value, struct ir_instr_s*, reads)
-MEM_VECTOR_PROTO(ir_value, struct ir_instr_s*, writes)
+MEM_VECTOR_PROTO_ALL(ir_value, struct ir_instr_s*, reads)
+MEM_VECTOR_PROTO_ALL(ir_value, struct ir_instr_s*, writes)
bool ir_value_set_float(ir_value*, float f);
bool ir_value_set_int(ir_value*, int i);
void ir_instr_delete(ir_instr*);
MEM_VECTOR_PROTO(ir_value, ir_phi_entry_t, phi)
-void ir_instr_op(ir_instr*, int op, ir_value *value, bool writing);
+bool GMQCC_WARN ir_instr_op(ir_instr*, int op, ir_value *value, bool writing);
void ir_instr_dump(ir_instr* in, char *ind, int (*oprintf)(const char*,...));
ir_block* ir_block_new(struct ir_function_s *owner, const char *label);
void ir_block_delete(ir_block*);
-void ir_block_set_label(ir_block*, const char *label);
+bool ir_block_set_label(ir_block*, const char *label);
MEM_VECTOR_PROTO(ir_block, ir_instr*, instr)
MEM_VECTOR_PROTO_ALL(ir_block, ir_block*, exits)
ir_value* ir_block_create_div(ir_block*, const char *label, ir_value *l, ir_value *r);
ir_instr* ir_block_create_phi(ir_block*, const char *label, int vtype);
ir_value* ir_phi_value(ir_instr*);
-void ir_phi_add(ir_instr*, ir_block *b, ir_value *v);
+bool ir_phi_add(ir_instr*, ir_block *b, ir_value *v);
-void ir_block_create_return(ir_block*, ir_value *opt_value);
+bool ir_block_create_return(ir_block*, ir_value *opt_value);
-void ir_block_create_if(ir_block*, ir_value *cond,
+bool ir_block_create_if(ir_block*, ir_value *cond,
ir_block *ontrue, ir_block *onfalse);
/* A 'goto' is an actual 'goto' coded in QC, whereas
* a 'jump' is a virtual construct which simply names the
* A goto usually becomes an OP_GOTO in the resulting code,
* whereas a 'jump' usually doesn't add any actual instruction.
*/
-void ir_block_create_jump(ir_block*, ir_block *to);
-void ir_block_create_goto(ir_block*, ir_block *to);
+bool ir_block_create_jump(ir_block*, ir_block *to);
+bool ir_block_create_goto(ir_block*, ir_block *to);
MEM_VECTOR_PROTO_ALL(ir_block, ir_value*, living)
ir_function* ir_function_new(struct ir_builder_s *owner);
void ir_function_delete(ir_function*);
-void ir_function_collect_value(ir_function*, ir_value *value);
+bool GMQCC_WARN ir_function_collect_value(ir_function*, ir_value *value);
-void ir_function_set_name(ir_function*, const char *name);
+bool ir_function_set_name(ir_function*, const char *name);
MEM_VECTOR_PROTO(ir_function, int, params)
MEM_VECTOR_PROTO(ir_function, ir_block*, blocks)
ir_value* ir_function_get_local(ir_function *self, const char *name);
ir_value* ir_function_create_local(ir_function *self, const char *name, int vtype);
-void ir_function_finalize(ir_function*);
+bool ir_function_finalize(ir_function*);
/*
-void ir_function_naive_phi(ir_function*);
-void ir_function_enumerate(ir_function*);
-void ir_function_calculate_liferanges(ir_function*);
+bool ir_function_naive_phi(ir_function*);
+bool ir_function_enumerate(ir_function*);
+bool ir_function_calculate_liferanges(ir_function*);
*/
ir_block* ir_function_create_block(ir_function*, const char *label);
ir_builder* ir_builder_new(const char *modulename);
void ir_builder_delete(ir_builder*);
-void ir_builder_set_name(ir_builder *self, const char *name);
+bool ir_builder_set_name(ir_builder *self, const char *name);
MEM_VECTOR_PROTO(ir_builder, ir_function*, functions)
MEM_VECTOR_PROTO(ir_builder, ir_value*, globals)