self->memberof = NULL;
self->unique_life = false;
+ self->locked = false;
self->life = NULL;
return self;
if (!in)
return false;
- if (!ir_instr_op(in, 0, target, true) ||
+ if (!ir_instr_op(in, 0, target, (op < INSTR_STOREP_F || op > INSTR_STOREP_FNC)) ||
!ir_instr_op(in, 1, what, false))
{
ir_instr_delete(in);
return ir_block_create_general_instr(self, ctx, label, op, ent, field, outype);
}
-ir_value* ir_block_create_add(ir_block *self, lex_ctx ctx,
- const char *label,
- ir_value *left, ir_value *right)
-{
- int op = 0;
- int l = left->vtype;
- int r = right->vtype;
- if (l == r) {
- switch (l) {
- default:
- irerror(self->context, "invalid type for ir_block_create_add: %s", type_name[l]);
- return NULL;
- case TYPE_FLOAT:
- op = INSTR_ADD_F;
- break;
-#if 0
- case TYPE_INTEGER:
- op = INSTR_ADD_I;
- break;
-#endif
- case TYPE_VECTOR:
- op = INSTR_ADD_V;
- break;
- }
- } else {
-#if 0
- if ( (l == TYPE_FLOAT && r == TYPE_INTEGER) )
- op = INSTR_ADD_FI;
- else if ( (l == TYPE_INTEGER && r == TYPE_FLOAT) )
- op = INSTR_ADD_IF;
- else
-#endif
- {
- irerror(self->context, "invalid type for ir_block_create_add: %s", type_name[l]);
- return NULL;
- }
- }
- return ir_block_create_binop(self, ctx, label, op, left, right);
-}
-
-ir_value* ir_block_create_sub(ir_block *self, lex_ctx ctx,
- const char *label,
- ir_value *left, ir_value *right)
-{
- int op = 0;
- int l = left->vtype;
- int r = right->vtype;
- if (l == r) {
-
- switch (l) {
- default:
- irerror(self->context, "invalid type for ir_block_create_sub: %s", type_name[l]);
- return NULL;
- case TYPE_FLOAT:
- op = INSTR_SUB_F;
- break;
-#if 0
- case TYPE_INTEGER:
- op = INSTR_SUB_I;
- break;
-#endif
- case TYPE_VECTOR:
- op = INSTR_SUB_V;
- break;
- }
- } else {
-#if 0
- if ( (l == TYPE_FLOAT && r == TYPE_INTEGER) )
- op = INSTR_SUB_FI;
- else if ( (l == TYPE_INTEGER && r == TYPE_FLOAT) )
- op = INSTR_SUB_IF;
- else
-#endif
- {
- irerror(self->context, "invalid type for ir_block_create_sub: %s", type_name[l]);
- return NULL;
- }
- }
- return ir_block_create_binop(self, ctx, label, op, left, right);
-}
-
-ir_value* ir_block_create_mul(ir_block *self, lex_ctx ctx,
- const char *label,
- ir_value *left, ir_value *right)
-{
- int op = 0;
- int l = left->vtype;
- int r = right->vtype;
- if (l == r) {
-
- switch (l) {
- default:
- irerror(self->context, "invalid type for ir_block_create_mul: %s", type_name[l]);
- return NULL;
- case TYPE_FLOAT:
- op = INSTR_MUL_F;
- break;
-#if 0
- case TYPE_INTEGER:
- op = INSTR_MUL_I;
- break;
-#endif
- case TYPE_VECTOR:
- op = INSTR_MUL_V;
- break;
- }
- } else {
- if ( (l == TYPE_VECTOR && r == TYPE_FLOAT) )
- op = INSTR_MUL_VF;
- else if ( (l == TYPE_FLOAT && r == TYPE_VECTOR) )
- op = INSTR_MUL_FV;
-#if 0
- else if ( (l == TYPE_VECTOR && r == TYPE_INTEGER) )
- op = INSTR_MUL_VI;
- else if ( (l == TYPE_INTEGER && r == TYPE_VECTOR) )
- op = INSTR_MUL_IV;
- else if ( (l == TYPE_FLOAT && r == TYPE_INTEGER) )
- op = INSTR_MUL_FI;
- else if ( (l == TYPE_INTEGER && r == TYPE_FLOAT) )
- op = INSTR_MUL_IF;
-#endif
- else {
- irerror(self->context, "invalid type for ir_block_create_mul: %s", type_name[l]);
- return NULL;
- }
- }
- return ir_block_create_binop(self, ctx, label, op, left, right);
-}
-
-ir_value* ir_block_create_div(ir_block *self, lex_ctx ctx,
- const char *label,
- ir_value *left, ir_value *right)
-{
- int op = 0;
- int l = left->vtype;
- int r = right->vtype;
- if (l == r) {
-
- switch (l) {
- default:
- irerror(self->context, "invalid type for ir_block_create_div: %s", type_name[l]);
- return NULL;
- case TYPE_FLOAT:
- op = INSTR_DIV_F;
- break;
-#if 0
- case TYPE_INTEGER:
- op = INSTR_DIV_I;
- break;
-#endif
- }
- } else {
-#if 0
- if ( (l == TYPE_VECTOR && r == TYPE_FLOAT) )
- op = INSTR_DIV_VF;
- else if ( (l == TYPE_FLOAT && r == TYPE_INTEGER) )
- op = INSTR_DIV_FI;
- else if ( (l == TYPE_INTEGER && r == TYPE_FLOAT) )
- op = INSTR_DIV_IF;
- else
-#endif
- {
- irerror(self->context, "invalid type for ir_block_create_div: %s", type_name[l]);
- return NULL;
- }
- }
- return ir_block_create_binop(self, ctx, label, op, left, right);
-}
-
/* PHI resolving breaks the SSA, and must thus be the last
* step before life-range calculation.
*/
void ir_function_enumerate(ir_function *self)
{
size_t i;
- size_t instruction_id = 0;
+ size_t instruction_id = 1;
for (i = 0; i < vec_size(self->blocks); ++i)
{
self->blocks[i]->eid = i;
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;
+ size_t i, s;
bool changed;
+ /* parameters live at 0 */
+ for (i = 0; i < vec_size(self->params); ++i)
+ ir_value_life_merge(self->locals[i], 0);
+
do {
self->run_id++;
changed = false;
ir_value *v = block->living[i];
if (v->store != store_local)
continue;
- if ((v->members[0] && v->members[1] && v->members[2])) {
- /* all vector members have been accessed - only treat this as uninitialized
- * if any of them is also uninitialized.
- */
- if (!vec_ir_value_find(block->living, v->members[0], NULL) &&
- !vec_ir_value_find(block->living, v->members[1], NULL) &&
- !vec_ir_value_find(block->living, v->members[2], NULL))
+ if (v->vtype == TYPE_VECTOR)
+ continue;
+ self->flags |= IR_FLAG_HAS_UNINITIALIZED;
+ /* find the instruction reading from it */
+ for (s = 0; s < vec_size(v->reads); ++s) {
+ if (v->reads[s]->eid == v->life[0].end)
+ break;
+ }
+ if (s < vec_size(v->reads)) {
+ if (irwarning(v->context, WARN_USED_UNINITIALIZED,
+ "variable `%s` may be used uninitialized in this function\n"
+ " -> %s:%i",
+ v->name,
+ v->reads[s]->context.file, v->reads[s]->context.line)
+ )
{
- continue;
+ return false;
}
+ continue;
}
if (v->memberof) {
- /* A member is only uninitialized if the whole vector is also uninitialized */
- if (!vec_ir_value_find(block->living, v->memberof, NULL))
+ ir_value *vec = v->memberof;
+ for (s = 0; s < vec_size(vec->reads); ++s) {
+ if (vec->reads[s]->eid == v->life[0].end)
+ break;
+ }
+ if (s < vec_size(vec->reads)) {
+ if (irwarning(v->context, WARN_USED_UNINITIALIZED,
+ "variable `%s` may be used uninitialized in this function\n"
+ " -> %s:%i",
+ v->name,
+ vec->reads[s]->context.file, vec->reads[s]->context.line)
+ )
+ {
+ return false;
+ }
continue;
+ }
}
- self->flags |= IR_FLAG_HAS_UNINITIALIZED;
if (irwarning(v->context, WARN_USED_UNINITIALIZED,
"variable `%s` may be used uninitialized in this function", v->name))
{
for (i = 0; i < vec_size(self->locals); ++i)
{
- if (!OPTS_OPTIMIZATION(OPTIM_LOCALTEMPS))
+ if (!OPTS_OPTIMIZATION(OPTIM_LOCAL_TEMPS))
self->locals[i]->unique_life = true;
if (!function_allocator_alloc(&alloc, self->locals[i]))
goto error;
for (i = 0; i != vec_size(self->living); ++i)
{
tempbool = ir_value_life_merge(self->living[i], eid);
- /* debug
- if (tempbool)
- irerror(self->context, "block_living_add_instr() value instruction added %s: %i", self->living[i]->_name, (int)eid);
- */
changed = changed || tempbool;
}
return changed;
}
+static bool ir_block_living_lock(ir_block *self)
+{
+ size_t i;
+ bool changed = false;
+ for (i = 0; i != vec_size(self->living); ++i)
+ {
+ if (!self->living[i]->locked)
+ changed = true;
+ self->living[i]->locked = true;
+ }
+ return changed;
+}
+
static bool ir_block_life_prop_previous(ir_block* self, ir_block *prev, bool *changed)
{
size_t i;
ir_instr *instr;
ir_value *value;
bool tempbool;
- size_t i, o, p;
+ size_t i, o, p, mem;
/* bitmasks which operands are read from or written to */
size_t read, write;
char dbg_ind[16] = { '#', '0' };
* and make sure it's only printed once
* since this function is run multiple times.
*/
- /* For now: debug info: */
/* con_err( "Value only written %s\n", value->name); */
tempbool = ir_value_life_merge(value, instr->eid);
*changed = *changed || tempbool;
- /*
- ir_instr_dump(instr, dbg_ind, printf);
- abort();
- */
} else {
/* since 'living' won't contain it
* anymore, merge the value, since
* (A) doesn't.
*/
tempbool = ir_value_life_merge(value, instr->eid);
- /*
- if (tempbool)
- con_err( "value added id %s %i\n", value->name, (int)instr->eid);
- */
*changed = *changed || tempbool;
/* Then remove */
vec_remove(self->living, idx, 1);
}
+ /* Removing a vector removes all members */
+ for (mem = 0; mem < 3; ++mem) {
+ if (value->members[mem] && vec_ir_value_find(self->living, value->members[mem], &idx)) {
+ tempbool = ir_value_life_merge(value->members[mem], instr->eid);
+ *changed = *changed || tempbool;
+ vec_remove(self->living, idx, 1);
+ }
+ }
+ /* Removing the last member removes the vector */
+ if (value->memberof) {
+ value = value->memberof;
+ for (mem = 0; mem < 3; ++mem) {
+ if (value->members[mem] && vec_ir_value_find(self->living, value->members[mem], NULL))
+ break;
+ }
+ if (mem == 3 && vec_ir_value_find(self->living, value, &idx)) {
+ tempbool = ir_value_life_merge(value, instr->eid);
+ *changed = *changed || tempbool;
+ vec_remove(self->living, idx, 1);
+ }
+ }
}
}
{
if (!vec_ir_value_find(self->living, value, NULL))
vec_push(self->living, value);
+ /* reading adds the full vector */
+ if (value->memberof && !vec_ir_value_find(self->living, value->memberof, NULL))
+ vec_push(self->living, value->memberof);
+ for (mem = 0; mem < 3; ++mem) {
+ if (value->members[mem] && !vec_ir_value_find(self->living, value->members[mem], NULL))
+ vec_push(self->living, value->members[mem]);
+ }
}
}
/* PHI operands are always read operands */
value = instr->phi[p].value;
if (!vec_ir_value_find(self->living, value, NULL))
vec_push(self->living, value);
+ /* reading adds the full vector */
+ if (value->memberof && !vec_ir_value_find(self->living, value->memberof, NULL))
+ vec_push(self->living, value->memberof);
+ for (mem = 0; mem < 3; ++mem) {
+ if (value->members[mem] && !vec_ir_value_find(self->living, value->members[mem], NULL))
+ vec_push(self->living, value->members[mem]);
+ }
}
/* call params are read operands too */
value = instr->params[p];
if (!vec_ir_value_find(self->living, value, NULL))
vec_push(self->living, value);
+ /* reading adds the full vector */
+ if (value->memberof && !vec_ir_value_find(self->living, value->memberof, NULL))
+ vec_push(self->living, value->memberof);
+ for (mem = 0; mem < 3; ++mem) {
+ if (value->members[mem] && !vec_ir_value_find(self->living, value->members[mem], NULL))
+ vec_push(self->living, value->members[mem]);
+ }
+ }
+ /* on a call, all these values must be "locked" */
+ if (instr->opcode >= INSTR_CALL0 && instr->opcode <= INSTR_CALL8) {
+ if (ir_block_living_lock(self))
+ *changed = true;
}
/* (A) */
code_push_statement(&stmt, instr->context.line);
retvalue = instr->_ops[0];
- if (retvalue && retvalue->store != store_return && (vec_size(retvalue->life) || retvalue->store == store_global))
+ if (retvalue && retvalue->store != store_return &&
+ (retvalue->store == store_global || vec_size(retvalue->life)))
{
/* not to be kept in OFS_RETURN */
if (retvalue->vtype == TYPE_FIELD && OPTS_FLAG(ADJUST_VECTOR_FIELDS))
def.type = global->vtype;
def.offset = vec_size(code_globals);
- if (global->name) {
+ if (OPTS_OPTIMIZATION(OPTIM_STRIP_CONSTANT_NAMES) &&
+ (global->name[0] == '#' || global->cvq == CV_CONST))
+ {
+ pushdef = false;
+ }
+
+ if (pushdef && global->name) {
if (global->name[0] == '#') {
if (!self->str_immediate)
self->str_immediate = code_genstring("IMMEDIATE");
case TYPE_FIELD:
if (pushdef) {
vec_push(code_defs, def);
- if (global->fieldtype == TYPE_VECTOR)
+ if (global->fieldtype == TYPE_VECTOR) {
gen_vector_defs(def, global->name);
+ ir_value_vector_member(global, 0);
+ ir_value_vector_member(global, 1);
+ ir_value_vector_member(global, 2);
+ }
}
return gen_global_field(global);
case TYPE_ENTITY:
case TYPE_VECTOR:
{
size_t d;
+ ir_value_vector_member(global, 0);
+ ir_value_vector_member(global, 1);
+ ir_value_vector_member(global, 2);
ir_value_code_setaddr(global, vec_size(code_globals));
if (global->hasvalue) {
iptr = (int32_t*)&global->constval.ivec[0];
memcpy(vec_add(lnofile, 5), ".lno", 5);
}
- if (lnofile)
- con_out("writing '%s' and '%s'...\n", filename, lnofile);
- else
- con_out("writing '%s'\n", filename);
+ if (!opts.quiet) {
+ if (lnofile)
+ con_out("writing '%s' and '%s'...\n", filename, lnofile);
+ else
+ con_out("writing '%s'\n", filename);
+ }
if (!code_write(filename, lnofile)) {
vec_free(lnofile);
return false;
}
oprintf("%sliferanges:\n", ind);
for (i = 0; i < vec_size(f->locals); ++i) {
- size_t l;
+ size_t l, m;
ir_value *v = f->locals[i];
oprintf("%s\t%s: %s@%i ", ind, v->name, (v->unique_life ? "unique " : ""), (int)v->code.local);
for (l = 0; l < vec_size(v->life); ++l) {
oprintf("[%i,%i] ", v->life[l].start, v->life[l].end);
}
oprintf("\n");
+ for (m = 0; m < 3; ++m) {
+ ir_value *vm = v->members[m];
+ if (!vm)
+ continue;
+ oprintf("%s\t%s: %s@%i ", ind, vm->name, (vm->unique_life ? "unique " : ""), (int)vm->code.local);
+ for (l = 0; l < vec_size(vm->life); ++l) {
+ oprintf("[%i,%i] ", vm->life[l].start, vm->life[l].end);
+ }
+ oprintf("\n");
+ }
}
for (i = 0; i < vec_size(f->values); ++i) {
size_t l;