};
/* 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;
bool ir_function_finalize(ir_function *self)
{
+ size_t i;
+
if (self->builtin)
return true;
if (!ir_function_naive_phi(self))
return false;
+ for (i = 0; i < vec_size(self->locals); ++i) {
+ ir_value *v = self->locals[i];
+ if (v->vtype == TYPE_VECTOR ||
+ (v->vtype == TYPE_FIELD && v->outtype == TYPE_VECTOR))
+ {
+ ir_value_vector_member(v, 0);
+ ir_value_vector_member(v, 1);
+ ir_value_vector_member(v, 2);
+ }
+ }
+ for (i = 0; i < vec_size(self->values); ++i) {
+ ir_value *v = self->values[i];
+ if (v->vtype == TYPE_VECTOR ||
+ (v->vtype == TYPE_FIELD && v->outtype == TYPE_VECTOR))
+ {
+ ir_value_vector_member(v, 0);
+ ir_value_vector_member(v, 1);
+ ir_value_vector_member(v, 2);
+ }
+ }
+
ir_function_enumerate(self);
if (!ir_function_calculate_liferanges(self))
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) && !v->locked) {
+ if (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;
+ }
+
+ ++opts_optimizationcount[OPTIM_CALL_STORES];
+ 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;
+ }
+ if (vec_size(v->writes) == 1 && v->writes[0]->opcode == INSTR_CALL0)
+ {
+ v->store = store_return;
+ ++opts_optimizationcount[OPTIM_CALL_STORES];
+ continue;
+ }
+ }
+
for (a = 0; a < vec_size(alloc.locals); ++a)
{
/* if it's reserved for a unique liferange: skip */
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);
static bool gen_function_code(ir_function *self)
{
ir_block *block;
- prog_section_statement stmt;
+ prog_section_statement stmt, *retst;
/* Starting from entry point, we generate blocks "as they come"
* for now. Dead blocks will not be translated obviously.
}
/* code_write and qcvm -disasm need to know that the function ends here */
- stmt.opcode = INSTR_DONE;
- stmt.o1.u1 = 0;
- stmt.o2.u1 = 0;
- stmt.o3.u1 = 0;
- code_push_statement(&stmt, vec_last(code_linenums));
+ retst = &vec_last(code_statements);
+ if (OPTS_OPTIMIZATION(OPTIM_VOID_RETURN) &&
+ self->outtype == TYPE_VOID &&
+ retst->opcode == INSTR_RETURN &&
+ !retst->o1.u1 && !retst->o2.u1 && !retst->o3.u1)
+ {
+ retst->opcode = INSTR_DONE;
+ ++opts_optimizationcount[OPTIM_VOID_RETURN];
+ } else {
+ stmt.opcode = INSTR_DONE;
+ stmt.o1.u1 = 0;
+ stmt.o2.u1 = 0;
+ stmt.o3.u1 = 0;
+ code_push_statement(&stmt, vec_last(code_linenums));
+ }
return true;
}
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];