/*
- * Copyright (C) 2012
+ * Copyright (C) 2012, 2013
* Wolfgang Bumiller
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
"union",
"array",
- "nil"
+ "nil",
+ "<no-expression>"
};
size_t type_sizeof_[TYPE_COUNT] = {
0, /* TYPE_UNION */
0, /* TYPE_ARRAY */
0, /* TYPE_NIL */
+ 0, /* TYPE_NOESPR */
};
uint16_t type_store_instr[TYPE_COUNT] = {
AINSTR_END, /* union */
AINSTR_END, /* array */
AINSTR_END, /* nil */
+ AINSTR_END, /* noexpr */
};
uint16_t field_store_instr[TYPE_COUNT] = {
AINSTR_END, /* union */
AINSTR_END, /* array */
AINSTR_END, /* nil */
+ AINSTR_END, /* noexpr */
};
uint16_t type_storep_instr[TYPE_COUNT] = {
AINSTR_END, /* union */
AINSTR_END, /* array */
AINSTR_END, /* nil */
+ AINSTR_END, /* noexpr */
};
uint16_t type_eq_instr[TYPE_COUNT] = {
AINSTR_END, /* union */
AINSTR_END, /* array */
AINSTR_END, /* nil */
+ AINSTR_END, /* noexpr */
};
uint16_t type_ne_instr[TYPE_COUNT] = {
AINSTR_END, /* union */
AINSTR_END, /* array */
AINSTR_END, /* nil */
+ AINSTR_END, /* noexpr */
};
uint16_t type_not_instr[TYPE_COUNT] = {
AINSTR_END, /* union */
AINSTR_END, /* array */
AINSTR_END, /* nil */
+ AINSTR_END, /* noexpr */
};
/* protos */
}
}
- if (!ir_function_naive_phi(self))
+ if (!ir_function_naive_phi(self)) {
+ irerror(self->context, "internal error: ir_function_naive_phi failed");
return false;
+ }
for (i = 0; i < vec_size(self->locals); ++i) {
ir_value *v = self->locals[i];
return true;
}
-#if 0
-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;
-
- /* create a store */
- if (!ir_block_create_store(block, old, what))
- return false;
-
- /* we now move it up */
- instr = vec_last(block->instr);
- for (i = vec_size(block->instr)-1; i > iid; --i)
- block->instr[i] = block->instr[i-1];
- block->instr[i] = instr;
-
- return true;
-}
-#endif
-
static bool ir_block_naive_phi(ir_block *self)
{
size_t i, p; /*, w;*/
vec_push(b->instr, prevjump);
b->final = true;
}
-
-#if 0
- ir_value *v = instr->phi[p].value;
- for (w = 0; w < vec_size(v->writes); ++w) {
- ir_value *old;
-
- if (!v->writes[w]->_ops[0])
- continue;
-
- /* When the write was to a global, we have to emit a mov */
- old = v->writes[w]->_ops[0];
-
- /* The original instruction now writes to the PHI target local */
- if (v->writes[w]->_ops[0] == v)
- v->writes[w]->_ops[0] = instr->_ops[0];
-
- if (old->store != store_value && old->store != store_local && old->store != store_param)
- {
- /* If it originally wrote to a global we need to store the value
- * there as welli
- */
- if (!ir_naive_phi_emit_store(self, i+1, old, v))
- return false;
- if (i+1 < vec_size(self->instr))
- instr = self->instr[i+1];
- else
- instr = NULL;
- /* In case I forget and access instr later, it'll be NULL
- * when it's a problem, to make sure we crash, rather than accessing
- * invalid data.
- */
- }
- else
- {
- /* If it didn't, we can replace all reads by the phi target now. */
- size_t r;
- for (r = 0; r < vec_size(old->reads); ++r)
- {
- size_t op;
- ir_instr *ri = old->reads[r];
- for (op = 0; op < vec_size(ri->phi); ++op) {
- if (ri->phi[op].value == old)
- ri->phi[op].value = v;
- }
- for (op = 0; op < 3; ++op) {
- if (ri->_ops[op] == old)
- ri->_ops[op] = v;
- }
- }
- }
- }
-#endif
}
ir_instr_delete(instr);
}
void ir_function_enumerate(ir_function *self)
{
size_t i;
- size_t instruction_id = 1;
+ size_t instruction_id = 0;
for (i = 0; i < vec_size(self->blocks); ++i)
{
+ /* each block now gets an additional "entry" instruction id
+ * we can use to avoid point-life issues
+ */
+ self->blocks[i]->entry_id = instruction_id;
+ ++instruction_id;
+
self->blocks[i]->eid = i;
self->blocks[i]->run_id = 0;
ir_block_enumerate(self->blocks[i], &instruction_id);
size_t a;
ir_value *slot;
+ if (v->unique_life)
+ return function_allocator_alloc(alloc, v);
+
for (a = 0; a < vec_size(alloc->locals); ++a)
{
/* if it's reserved for a unique liferange: skip */
break;
else
v->locked = true; /* lock parameters locals */
- if (!function_allocator_alloc((v->locked || !opt_gt ? &lockalloc : &globalloc), self->locals[i]))
+ if (!function_allocator_alloc((v->locked || !opt_gt ? &lockalloc : &globalloc), v))
goto error;
}
for (; i < vec_size(self->locals); ++i)
bool changed = false;
for (i = 0; i != vec_size(self->living); ++i)
{
- if (!self->living[i]->locked)
+ if (!self->living[i]->locked) {
+ self->living[i]->locked = true;
changed = true;
- self->living[i]->locked = true;
+ }
}
return changed;
}
/* See which operands are read and write operands */
ir_op_read_write(instr->opcode, &read, &write);
- if (instr->opcode == INSTR_MUL_VF)
- {
- /* the float source will get an additional lifetime */
- tempbool = ir_value_life_merge(instr->_ops[2], instr->eid+1);
- *changed = *changed || tempbool;
- }
- else if (instr->opcode == INSTR_MUL_FV)
- {
- /* the float source will get an additional lifetime */
- tempbool = ir_value_life_merge(instr->_ops[1], instr->eid+1);
- *changed = *changed || tempbool;
- }
-
/* Go through the 3 main operands
* writes first, then reads
*/
}
}
+ if (instr->opcode == INSTR_MUL_VF)
+ {
+ value = instr->_ops[2];
+ /* the float source will get an additional lifetime */
+ if (ir_value_life_merge(value, instr->eid+1))
+ *changed = true;
+ if (value->memberof && ir_value_life_merge(value->memberof, instr->eid+1))
+ *changed = true;
+ }
+ else if (instr->opcode == INSTR_MUL_FV)
+ {
+ value = instr->_ops[1];
+ /* the float source will get an additional lifetime */
+ if (ir_value_life_merge(value, instr->eid+1))
+ *changed = true;
+ if (value->memberof && ir_value_life_merge(value->memberof, instr->eid+1))
+ *changed = true;
+ }
+
for (o = 0; o < 3; ++o)
{
if (!instr->_ops[o]) /* no such operand */
tempbool = ir_block_living_add_instr(self, instr->eid);
/*con_err( "living added values\n");*/
*changed = *changed || tempbool;
-
}
+ /* the "entry" instruction ID */
+ tempbool = ir_block_living_add_instr(self, self->entry_id);
+ *changed = *changed || tempbool;
if (self->run_id == self->owner->run_id)
return true;
size_t stidx;
size_t i;
-tailcall:
block->generated = true;
block->code_start = vec_size(code_statements);
for (i = 0; i < vec_size(block->instr); ++i)
/* for uncoditional jumps, if the target hasn't been generated
* yet, we generate them right here.
*/
- if (!target->generated) {
- block = target;
- goto tailcall;
- }
+ if (!target->generated)
+ return gen_blocks_recursive(func, target);
/* otherwise we generate a jump instruction */
stmt.opcode = INSTR_GOTO;
code_push_statement(&stmt, instr->context.line);
}
if (!ontrue->generated) {
- if (onfalse->generated) {
- block = ontrue;
- goto tailcall;
- }
+ if (onfalse->generated)
+ return gen_blocks_recursive(func, ontrue);
}
if (!onfalse->generated) {
- if (ontrue->generated) {
- block = onfalse;
- goto tailcall;
- }
+ if (ontrue->generated)
+ return gen_blocks_recursive(func, onfalse);
}
/* neither ontrue nor onfalse exist */
stmt.opcode = INSTR_IFNOT;
if (onfalse->generated) {
/* fixup the jump address */
code_statements[stidx].o2.s1 = (onfalse->code_start) - (stidx);
- if (code_statements[stidx].o2.s1 == 1) {
+ if (stidx+2 == vec_size(code_statements) && code_statements[stidx].o2.s1 == 1) {
code_statements[stidx] = code_statements[stidx+1];
if (code_statements[stidx].o1.s1 < 0)
code_statements[stidx].o1.s1++;
code_push_statement(&stmt, instr->context.line);
return true;
}
- else if (code_statements[stidx].o2.s1 == 1) {
+ else if (stidx+2 == vec_size(code_statements) && code_statements[stidx].o2.s1 == 1) {
code_statements[stidx] = code_statements[stidx+1];
if (code_statements[stidx].o1.s1 < 0)
code_statements[stidx].o1.s1++;
code_pop_statement();
}
/* if not, generate now */
- block = onfalse;
- goto tailcall;
+ return gen_blocks_recursive(func, onfalse);
}
if ( (instr->opcode >= INSTR_CALL0 && instr->opcode <= INSTR_CALL8)
if (param->vtype == TYPE_FIELD)
stmt.opcode = field_store_instr[param->fieldtype];
+ else if (param->vtype == TYPE_NIL)
+ stmt.opcode = INSTR_STORE_V;
else
stmt.opcode = type_store_instr[param->vtype];
stmt.o1.u1 = ir_value_code_addr(param);
if (param->vtype == TYPE_FIELD)
stmt.opcode = field_store_instr[param->fieldtype];
+ else if (param->vtype == TYPE_NIL)
+ stmt.opcode = INSTR_STORE_V;
else
stmt.opcode = type_store_instr[param->vtype];
stmt.o1.u1 = ir_value_code_addr(param);
}
}
+ /* generate nil */
+ ir_value_code_setaddr(self->nil, vec_size(code_globals));
+ vec_push(code_globals, 0);
+ vec_push(code_globals, 0);
+ vec_push(code_globals, 0);
+
/* generate global temps */
self->first_common_globaltemp = vec_size(code_globals);
for (i = 0; i < self->max_globaltemps; ++i) {
oprintf("endmodule %s\n", b->name);
}
+static const char *storenames[] = {
+ "[global]", "[local]", "[param]", "[value]", "[return]"
+};
+
void ir_function_dump(ir_function *f, char *ind,
int (*oprintf)(const char*, ...))
{
attr = "unique ";
else if (v->locked)
attr = "locked ";
- oprintf("%s\t%s: %s %s@%i ", ind, v->name, type_name[v->vtype], attr, (int)v->code.local);
+ oprintf("%s\t%s: %s %s %s%s@%i ", ind, v->name, type_name[v->vtype],
+ storenames[v->store],
+ attr, (v->callparam ? "callparam " : ""),
+ (int)v->code.local);
+ if (!v->life)
+ oprintf("[null]");
for (l = 0; l < vec_size(v->life); ++l) {
oprintf("[%i,%i] ", v->life[l].start, v->life[l].end);
}
ir_value *vm = v->members[m];
if (!vm)
continue;
- if (vm->unique_life && vm->locked)
- attr = "unique,locked ";
- else if (vm->unique_life)
- attr = "unique ";
- else if (vm->locked)
- attr = "locked ";
- oprintf("%s\t%s: %s@%i ", ind, vm->name, attr, (int)vm->code.local);
+ oprintf("%s\t%s: @%i ", ind, vm->name, (int)vm->code.local);
for (l = 0; l < vec_size(vm->life); ++l) {
oprintf("[%i,%i] ", vm->life[l].start, vm->life[l].end);
}
attr = "unique ";
else if (v->locked)
attr = "locked ";
- oprintf("%s\t%s: %s %s@%i ", ind, v->name, type_name[v->vtype], attr, (int)v->code.local);
+ oprintf("%s\t%s: %s %s %s%s@%i ", ind, v->name, type_name[v->vtype],
+ storenames[v->store],
+ attr, (v->callparam ? "callparam " : ""),
+ (int)v->code.local);
+ if (!v->life)
+ oprintf("[null]");
for (l = 0; l < vec_size(v->life); ++l) {
oprintf("[%i,%i] ", v->life[l].start, v->life[l].end);
}
oprintf("%s:%s\n", ind, b->label);
strncat(ind, "\t", IND_BUFSZ);
+ if (b->instr && b->instr[0])
+ oprintf("%s (%i) [entry]\n", ind, (int)(b->instr[0]->eid-1));
for (i = 0; i < vec_size(b->instr); ++i)
ir_instr_dump(b->instr[i], ind, oprintf);
ind[strlen(ind)-1] = 0;