-Ocall-stores as part of -O1: instead of having CALL instructions issue STOREs for every parameter, use the newly introduced 'lock' flag to make the operations generating the call's parameters generate them right into the OFS_PARM if there's no interfering CALL in between

This commit is contained in:
Wolfgang Bumiller 2012-12-25 23:25:59 +01:00
parent d7de5cb5ff
commit a7c3ef3e22
3 changed files with 72 additions and 23 deletions

88
ir.c
View file

@ -194,7 +194,8 @@ uint16_t type_not_instr[TYPE_COUNT] = {
};
/* 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 */
@ -220,7 +221,7 @@ static bool irwarning(lex_ctx ctx, int warntype, const char *fmt, ...)
* 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);
@ -278,13 +279,15 @@ ir_builder* ir_builder_new(const char *modulename)
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;
@ -988,6 +991,7 @@ ir_value* ir_value_var(const char *name, int storetype, int vtype)
self->unique_life = false;
self->locked = false;
self->callparam = false;
self->life = NULL;
return self;
@ -2136,7 +2140,7 @@ bool ir_function_allocate_locals(ir_function *self)
size_t pos;
ir_value *slot;
const ir_value *v;
ir_value *v;
function_allocator alloc;
@ -2164,6 +2168,41 @@ bool ir_function_allocate_locals(ir_function *self)
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, &param)) {
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 */
@ -2765,19 +2804,6 @@ tailcall:
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;
@ -2787,6 +2813,8 @@ tailcall:
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;
@ -2807,6 +2835,9 @@ tailcall:
ir_value *param = instr->params[p];
ir_value *targetparam;
if (param->callparam)
continue;
if (p-8 >= vec_size(ir->extparams))
ir_gen_extparam(ir);
@ -2992,16 +3023,29 @@ static bool gen_global_function(ir_builder *ir, ir_value *global)
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);
@ -3078,6 +3122,8 @@ static bool gen_function_locals(ir_builder *ir, ir_value *global)
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;

6
ir.h
View file

@ -79,6 +79,7 @@ typedef struct ir_value_s {
bool unique_life;
/* temps living during a CALL must be locked */
bool locked;
bool callparam;
/* For the temp allocator */
ir_life_entry_t *life;
@ -96,7 +97,7 @@ void ir_value_delete(ir_value*);
bool ir_value_set_name(ir_value*, const char *name);
ir_value* ir_value_vector_member(ir_value*, unsigned int member);
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);
bool GMQCC_WARN ir_value_set_float(ir_value*, float f);
bool GMQCC_WARN ir_value_set_func(ir_value*, int f);
@ -153,7 +154,7 @@ void ir_instr_delete(ir_instr*);
bool GMQCC_WARN vec_ir_instr_find(ir_instr **vec, ir_instr *what, size_t *idx);
bool GMQCC_WARN ir_instr_op(ir_instr*, int op, ir_value *value, bool writing);
bool ir_instr_op(ir_instr*, int op, ir_value *value, bool writing);
void ir_instr_dump(ir_instr* in, char *ind, int (*oprintf)(const char*,...));
@ -309,6 +310,7 @@ typedef struct ir_builder_s
ht htfields;
ir_value **extparams;
ir_value **extparam_protos;
/* the highest func->allocated_locals */
size_t max_locals;

View file

@ -86,6 +86,7 @@
GMQCC_DEFINE_FLAG(OVERLAP_LOCALS, 3)
GMQCC_DEFINE_FLAG(STRIP_CONSTANT_NAMES, 1)
GMQCC_DEFINE_FLAG(OVERLAP_STRINGS, 2)
GMQCC_DEFINE_FLAG(CALL_STORES, 1)
#endif
/* some cleanup so we don't have to */