};
/* protos */
-static void ir_gen_extparam(ir_builder *ir);
+static ir_value* ir_gen_extparam_proto(ir_builder *ir);
+static void ir_gen_extparam (ir_builder *ir);
/* error functions */
* Vector utility functions
*/
-bool GMQCC_WARN vec_ir_value_find(ir_value **vec, ir_value *what, size_t *idx)
+bool GMQCC_WARN vec_ir_value_find(ir_value **vec, const ir_value *what, size_t *idx)
{
size_t i;
size_t len = vec_size(vec);
self->functions = NULL;
self->globals = NULL;
self->fields = NULL;
- self->extparams = NULL;
self->filenames = NULL;
self->filestrings = NULL;
self->htglobals = util_htnew(IR_HT_SIZE);
self->htfields = util_htnew(IR_HT_SIZE);
self->htfunctions = util_htnew(IR_HT_SIZE);
+ self->extparams = NULL;
+ self->extparam_protos = NULL;
+
self->max_locals = 0;
self->str_immediate = 0;
self->memberof = NULL;
self->unique_life = false;
+ self->locked = false;
+ self->callparam = false;
self->life = NULL;
return self;
size_t pos;
ir_value *slot;
- const ir_value *v;
+ ir_value *v;
function_allocator alloc;
if (!vec_size(v->life))
continue;
+ /* CALL optimization:
+ * If the value is a parameter-temp: 1 write, 1 read from a CALL
+ * and it's not "locked", write it to the OFS_PARM directly.
+ */
+ if (OPTS_OPTIMIZATION(OPTIM_CALL_STORES)) {
+ if (!v->locked && vec_size(v->reads) == 1 && vec_size(v->writes) == 1 &&
+ (v->reads[0]->opcode == VINSTR_NRCALL ||
+ (v->reads[0]->opcode >= INSTR_CALL0 && v->reads[0]->opcode <= INSTR_CALL8)
+ )
+ )
+ {
+ size_t param;
+ ir_instr *call = v->reads[0];
+ if (!vec_ir_value_find(call->params, v, ¶m)) {
+ irerror(call->context, "internal error: unlocked parameter %s not found", v->name);
+ goto error;
+ }
+
+ v->callparam = true;
+ if (param < 8)
+ ir_value_code_setaddr(v, OFS_PARM0 + 3*param);
+ else {
+ ir_value *ep;
+ param -= 8;
+ if (vec_size(self->owner->extparam_protos) <= param)
+ ep = ir_gen_extparam_proto(self->owner);
+ else
+ ep = self->owner->extparam_protos[param];
+ ir_instr_op(v->writes[0], 0, ep, true);
+ call->params[param+8] = ep;
+ }
+ continue;
+ }
+ }
+
for (a = 0; a < vec_size(alloc.locals); ++a)
{
/* if it's reserved for a unique liferange: skip */
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;
}
}
+ /* 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;
+ }
/* call params are read operands too */
for (p = 0; p < vec_size(instr->params); ++p)
{
if ( (instr->opcode >= INSTR_CALL0 && instr->opcode <= INSTR_CALL8)
|| instr->opcode == VINSTR_NRCALL)
{
- /* Trivial call translation:
- * copy all params to OFS_PARM*
- * if the output's storetype is not store_return,
- * add append a STORE instruction!
- *
- * NOTES on how to do it better without much trouble:
- * -) The liferanges!
- * Simply check the liferange of all parameters for
- * other CALLs. For each param with no CALL in its
- * liferange, we can store it in an OFS_PARM at
- * generation already. This would even include later
- * reuse.... probably... :)
- */
size_t p, first;
ir_value *retvalue;
for (p = 0; p < first; ++p)
{
ir_value *param = instr->params[p];
+ if (param->callparam)
+ continue;
stmt.opcode = INSTR_STORE_F;
stmt.o3.u1 = 0;
ir_value *param = instr->params[p];
ir_value *targetparam;
+ if (param->callparam)
+ continue;
+
if (p-8 >= vec_size(ir->extparams))
ir_gen_extparam(ir);
return true;
}
+static ir_value* ir_gen_extparam_proto(ir_builder *ir)
+{
+ ir_value *global;
+ char name[128];
+
+ snprintf(name, sizeof(name), "EXTPARM#%i", (int)(vec_size(ir->extparam_protos)+8));
+ global = ir_value_var(name, store_global, TYPE_VECTOR);
+
+ vec_push(ir->extparam_protos, global);
+ return global;
+}
+
static void ir_gen_extparam(ir_builder *ir)
{
prog_section_def def;
ir_value *global;
- char name[128];
- snprintf(name, sizeof(name), "EXTPARM#%i", (int)(vec_size(ir->extparams)+8));
- global = ir_value_var(name, store_global, TYPE_VECTOR);
+ if (vec_size(ir->extparam_protos) < vec_size(ir->extparams)+1)
+ global = ir_gen_extparam_proto(ir);
+ else
+ global = ir->extparam_protos[vec_size(ir->extparams)];
- def.name = code_genstring(name);
+ def.name = code_genstring(global->name);
def.type = TYPE_VECTOR;
def.offset = vec_size(code_globals);
for (i = 0; i < vec_size(irfun->values); ++i)
{
ir_value *v = irfun->values[i];
+ if (v->callparam)
+ continue;
ir_value_code_setaddr(v, firstlocal + v->code.local);
}
return true;
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];