Importing tail-recursion optimization

This commit is contained in:
Wolfgang (Blub) Bumiller 2012-11-30 11:12:53 +01:00
parent a890589031
commit e1fe6cff54
3 changed files with 98 additions and 0 deletions

View file

@ -895,6 +895,7 @@ static const unsigned int opts_opt_oflag[] = {
# include "opts.def"
0
};
extern unsigned int optimization_count[COUNT_OPTIMIZATIONS];
/* other options: */
enum {

94
ir.c
View file

@ -524,11 +524,105 @@ ir_block* ir_function_create_block(lex_ctx ctx, ir_function *self, const char *l
return bn;
}
bool ir_function_pass_tailcall(ir_function *self)
{
size_t b, p;
for (b = 0; b < vec_size(self->blocks); ++b) {
ir_value *funcval;
ir_instr *ret, *call, *store = NULL;
ir_block *block = self->blocks[b];
if (!block->final || vec_size(block->instr) < 2)
continue;
ret = block->instr[vec_size(block->instr)-1];
if (ret->opcode != INSTR_DONE && ret->opcode != INSTR_RETURN)
continue;
call = block->instr[vec_size(block->instr)-2];
if (call->opcode >= INSTR_STORE_F && call->opcode <= INSTR_STORE_FNC) {
/* account for the unoptimized
* CALL
* STORE %return, %tmp
* RETURN %tmp
* version
*/
if (vec_size(block->instr) < 3)
continue;
store = call;
call = block->instr[vec_size(block->instr)-3];
}
if (call->opcode < INSTR_CALL0 || call->opcode > INSTR_CALL8)
continue;
if (store) {
/* optimize out the STORE */
if (ret->_ops[0] &&
ret->_ops[0] == store->_ops[0] &&
store->_ops[1] == call->_ops[0])
{
++optimization_count[OPTIM_MINOR];
call->_ops[0] = store->_ops[0];
vec_remove(block, vec_size(block->instr) - 2, 1);
ir_instr_delete(store);
}
else
continue;
}
if (!call->_ops[0])
continue;
funcval = call->_ops[1];
if (!funcval)
continue;
if (funcval->vtype != TYPE_FUNCTION || funcval->constval.vfunc != self)
continue;
/* now we have a CALL and a RET, check if it's a tailcall */
if (ret->_ops[0] && call->_ops[0] != ret->_ops[0])
continue;
++optimization_count[OPTIM_TAIL_RECURSION];
vec_shrinkby(block->instr, 2);
block->final = false; /* open it back up */
/* emite parameter-stores */
for (p = 0; p < vec_size(call->params); ++p) {
/* assert(call->params_count <= self->locals_count); */
if (!ir_block_create_store(block, self->locals[p], call->params[p])) {
irerror(call->context, "failed to create tailcall store instruction for parameter %i", (int)p);
return false;
}
}
if (!ir_block_create_jump(block, self->blocks[0])) {
irerror(call->context, "failed to create tailcall jump");
return false;
}
ir_instr_delete(call);
ir_instr_delete(ret);
}
return true;
}
bool ir_function_finalize(ir_function *self)
{
if (self->builtin)
return true;
if (OPTS_OPTIMIZATION(OPTIM_TAIL_RECURSION)) {
if (!ir_function_pass_tailcall(self)) {
irerror(self->context, "tailcall optimization pass broke something in `%s`", self->name);
return false;
}
}
if (!ir_function_naive_phi(self))
return false;

3
main.c
View file

@ -27,6 +27,9 @@
uint32_t opts_flags[1 + (COUNT_FLAGS / 32)];
uint32_t opts_optimization[1 + (COUNT_OPTIMIZATIONS / 32)];
/* counter increased in ir.c */
unsigned int optimization_count[COUNT_OPTIMIZATIONS];
uint32_t opts_O = 1;
const char *opts_output = "progs.dat";
int opts_standard = COMPILER_GMQCC;