self->nil = ir_value_var("nil", store_value, TYPE_NIL);
self->nil->cvq = CV_CONST;
+ self->reserved_va_count = NULL;
+
return self;
}
return ve;
}
+ir_value* ir_builder_get_va_count(ir_builder *self)
+{
+ if (self->reserved_va_count)
+ return self->reserved_va_count;
+ return (self->reserved_va_count = ir_builder_create_global(self, "reserved:va_count", TYPE_FLOAT));
+}
+
ir_value* ir_builder_get_field(ir_builder *self, const char *name)
{
return (ir_value*)util_htget(self->htfields, name);
self->values = NULL;
self->locals = NULL;
+ self->max_varargs = 0;
+
self->code_function_def = -1;
self->allocated_locals = 0;
self->globaltemps = 0;
self->fieldtype = TYPE_VOID;
self->outtype = TYPE_VOID;
self->store = storetype;
+ self->flags = 0;
self->reads = NULL;
self->writes = NULL;
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);
return true;
}
-static bool ir_value_has_point_life(const ir_value *v)
-{
- size_t i, vs = vec_size(v->life);
- for (i = 0; i < vs; ++i) {
- if (v->life[i].start == v->life[i].end)
- return true;
- }
- return false;
-}
-
bool ir_function_allocate_locals(ir_function *self)
{
size_t i;
for (i = 0; i < vec_size(self->locals); ++i)
{
v = self->locals[i];
- if (ir_value_has_point_life(v))
- v->unique_life = true;
- if (!OPTS_OPTIMIZATION(OPTIM_LOCAL_TEMPS)) {
+ if ((self->flags & IR_FLAG_MASK_NO_LOCAL_TEMPS) || !OPTS_OPTIMIZATION(OPTIM_LOCAL_TEMPS)) {
v->locked = true;
v->unique_life = true;
}
v = self->locals[i];
if (!vec_size(v->life))
continue;
- if (ir_value_has_point_life(v))
- v->unique_life = true;
if (!ir_function_allocator_assign(self, (v->locked || !opt_gt ? &lockalloc : &globalloc), v))
goto error;
}
if (!vec_size(v->life))
continue;
- if (ir_value_has_point_life(v)) {
- /* happens on free ternarys like:
- if (x) {
- cond ? a : b;
- }
- irerror(v->context, "internal error: point life SSA value leaked: %s", v->name);
- */
- v->unique_life = true;
- }
/* CALL optimization:
* If the value is a parameter-temp: 1 write, 1 read from a CALL
/* Locals need to know their new position */
for (i = 0; i < vec_size(self->locals); ++i) {
v = self->locals[i];
- if (i >= vec_size(self->params) && !vec_size(v->life))
- continue;
if (v->locked || !opt_gt)
v->code.local = lockalloc.positions[v->code.local];
else
/* Take over the actual slot positions on values */
for (i = 0; i < vec_size(self->values); ++i) {
v = self->values[i];
- if (!vec_size(v->life))
- continue;
if (v->locked || !opt_gt)
v->code.local = lockalloc.positions[v->code.local];
else
/* 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;
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)
return true;
}
+static bool gen_function_varargs_copy(ir_function *self)
+{
+ size_t i, ext, numparams, maxparams;
+
+ ir_builder *ir = self->owner;
+ ir_value *ep;
+ prog_section_statement stmt;
+
+ numparams = vec_size(self->params);
+ if (!numparams)
+ return true;
+
+ stmt.opcode = INSTR_STORE_V;
+ stmt.o3.s1 = 0;
+ maxparams = numparams + self->max_varargs;
+ for (i = numparams; i < maxparams; ++i) {
+ if (i <= 8) {
+ stmt.o1.u1 = OFS_PARM0 + 3*i;
+ stmt.o2.u1 = ir_value_code_addr(self->locals[i]);
+ code_push_statement(&stmt, self->context.line);
+ continue;
+ }
+ ext = i - 8;
+ if (ext >= vec_size(ir->extparams))
+ ir_gen_extparam(ir);
+
+ ep = ir->extparams[ext];
+
+ stmt.o1.u1 = ir_value_code_addr(ep);
+ stmt.o2.u1 = ir_value_code_addr(self->locals[i]);
+ code_push_statement(&stmt, self->context.line);
+ }
+
+ return true;
+}
+
static bool gen_function_locals(ir_builder *ir, ir_value *global)
{
prog_section_function *def;
irerror(irfun->context, "Failed to generate extparam-copy code for function %s", irfun->name);
return false;
}
+ if (irfun->max_varargs && !gen_function_varargs_copy(irfun)) {
+ irerror(irfun->context, "Failed to generate vararg-copy code for function %s", irfun->name);
+ return false;
+ }
if (!gen_function_code(irfun)) {
irerror(irfun->context, "Failed to generate code for function %s", irfun->name);
return false;
pushdef = true;
if (OPTS_OPTIMIZATION(OPTIM_STRIP_CONSTANT_NAMES) &&
+ !(global->flags & IR_FLAG_INCLUDE_DEF) &&
(global->name[0] == '#' || global->cvq == CV_CONST))
{
pushdef = false;
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%s@%i ", ind, v->name, type_name[v->vtype],
+ 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%s@%i ", ind, v->name, type_name[v->vtype],
+ 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;