compile tail calls into OP_TAILCALL

This commit is contained in:
Yuichi Nishiwaki 2013-10-30 10:04:23 +09:00
parent e4b913cb15
commit a4d20060e7
1 changed files with 56 additions and 44 deletions

View File

@ -164,11 +164,11 @@ scope_global_define(pic_state *pic, const char *name)
return e->val; return e->val;
} }
static void codegen_call(codegen_state *, pic_value); static void codegen_call(codegen_state *, pic_value, bool);
static struct pic_irep *codegen_lambda(codegen_state *, pic_value); static struct pic_irep *codegen_lambda(codegen_state *, pic_value);
static void static void
codegen(codegen_state *state, pic_value obj) codegen(codegen_state *state, pic_value obj, bool tailpos)
{ {
pic_state *pic = state->pic; pic_state *pic = state->pic;
struct pic_irep *irep = state->irep; struct pic_irep *irep = state->irep;
@ -243,7 +243,7 @@ codegen(codegen_state *state, pic_value obj)
idx = scope_global_define(pic, pic_symbol_name(pic, pic_sym(var))); idx = scope_global_define(pic, pic_symbol_name(pic, pic_sym(var)));
codegen(state, val); codegen(state, val, false);
irep->code[irep->clen].insn = OP_GSET; irep->code[irep->clen].insn = OP_GSET;
irep->code[irep->clen].u.i = idx; irep->code[irep->clen].u.i = idx;
irep->clen++; irep->clen++;
@ -276,33 +276,41 @@ codegen(codegen_state *state, pic_value obj)
if_true = pic_car(pic, pic_cdr(pic, pic_cdr(pic, obj))); if_true = pic_car(pic, pic_cdr(pic, pic_cdr(pic, obj)));
} }
codegen(state, pic_car(pic, pic_cdr(pic, obj))); codegen(state, pic_car(pic, pic_cdr(pic, obj)), false);
irep->code[irep->clen].insn = OP_JMPIF; irep->code[irep->clen].insn = OP_JMPIF;
s = irep->clen++; s = irep->clen++;
/* if false branch */ /* if false branch */
codegen(state, if_false); codegen(state, if_false, tailpos);
irep->code[irep->clen].insn = OP_JMP; irep->code[irep->clen].insn = OP_JMP;
t = irep->clen++; t = irep->clen++;
irep->code[s].u.i = irep->clen - s; irep->code[s].u.i = irep->clen - s;
/* if true branch */ /* if true branch */
codegen(state, if_true); codegen(state, if_true, tailpos);
irep->code[t].u.i = irep->clen - t; irep->code[t].u.i = irep->clen - t;
break; break;
} }
else if (sym == pic->sBEGIN) { else if (sym == pic->sBEGIN) {
int i, len;
pic_value v, seq; pic_value v, seq;
seq = pic_cdr(pic, obj); seq = pic_cdr(pic, obj);
for (v = seq; ! pic_nil_p(v); v = pic_cdr(pic, v)) { len = pic_length(pic, seq);
codegen(state, pic_car(pic, v)); for (i = 0; i < len; ++i) {
v = pic_car(pic, seq);
if (i + 1 >= len) {
codegen(state, v, tailpos);
}
else {
codegen(state, v, false);
irep->code[irep->clen].insn = OP_POP; irep->code[irep->clen].insn = OP_POP;
irep->clen++; irep->clen++;
} }
irep->clen--; seq = pic_cdr(pic, seq);
}
break; break;
} }
else if (sym == pic->sSETBANG) { else if (sym == pic->sSETBANG) {
@ -324,7 +332,7 @@ codegen(codegen_state *state, pic_value obj)
pic_error(pic, "unbound variable"); pic_error(pic, "unbound variable");
} }
codegen(state, pic_car(pic, pic_cdr(pic, pic_cdr(pic, obj)))); codegen(state, pic_car(pic, pic_cdr(pic, pic_cdr(pic, obj))), false);
switch (depth) { switch (depth) {
case -1: /* global */ case -1: /* global */
@ -372,108 +380,108 @@ codegen(codegen_state *state, pic_value obj)
else if (sym == pic->sCONS) { else if (sym == pic->sCONS) {
ARGC_ASSERT(2); ARGC_ASSERT(2);
codegen(state, pic_car(pic, pic_cdr(pic, obj))); codegen(state, pic_car(pic, pic_cdr(pic, obj)), false);
codegen(state, pic_car(pic, pic_cdr(pic, pic_cdr(pic, obj)))); codegen(state, pic_car(pic, pic_cdr(pic, pic_cdr(pic, obj))), false);
irep->code[irep->clen].insn = OP_CONS; irep->code[irep->clen].insn = OP_CONS;
irep->clen++; irep->clen++;
break; break;
} }
else if (sym == pic->sCAR) { else if (sym == pic->sCAR) {
ARGC_ASSERT(1); ARGC_ASSERT(1);
codegen(state, pic_car(pic, pic_cdr(pic, obj))); codegen(state, pic_car(pic, pic_cdr(pic, obj)), false);
irep->code[irep->clen].insn = OP_CAR; irep->code[irep->clen].insn = OP_CAR;
irep->clen++; irep->clen++;
break; break;
} }
else if (sym == pic->sCDR) { else if (sym == pic->sCDR) {
ARGC_ASSERT(1); ARGC_ASSERT(1);
codegen(state, pic_car(pic, pic_cdr(pic, obj))); codegen(state, pic_car(pic, pic_cdr(pic, obj)), false);
irep->code[irep->clen].insn = OP_CDR; irep->code[irep->clen].insn = OP_CDR;
irep->clen++; irep->clen++;
break; break;
} }
else if (sym == pic->sNILP) { else if (sym == pic->sNILP) {
ARGC_ASSERT(1); ARGC_ASSERT(1);
codegen(state, pic_car(pic, pic_cdr(pic, obj))); codegen(state, pic_car(pic, pic_cdr(pic, obj)), false);
irep->code[irep->clen].insn = OP_NILP; irep->code[irep->clen].insn = OP_NILP;
irep->clen++; irep->clen++;
break; break;
} }
else if (sym == pic->sADD) { else if (sym == pic->sADD) {
ARGC_ASSERT(2); ARGC_ASSERT(2);
codegen(state, pic_car(pic, pic_cdr(pic, obj))); codegen(state, pic_car(pic, pic_cdr(pic, obj)), false);
codegen(state, pic_car(pic, pic_cdr(pic, pic_cdr(pic, obj)))); codegen(state, pic_car(pic, pic_cdr(pic, pic_cdr(pic, obj))), false);
irep->code[irep->clen].insn = OP_ADD; irep->code[irep->clen].insn = OP_ADD;
irep->clen++; irep->clen++;
break; break;
} }
else if (sym == pic->sSUB) { else if (sym == pic->sSUB) {
ARGC_ASSERT(2); ARGC_ASSERT(2);
codegen(state, pic_car(pic, pic_cdr(pic, obj))); codegen(state, pic_car(pic, pic_cdr(pic, obj)), false);
codegen(state, pic_car(pic, pic_cdr(pic, pic_cdr(pic, obj)))); codegen(state, pic_car(pic, pic_cdr(pic, pic_cdr(pic, obj))), false);
irep->code[irep->clen].insn = OP_SUB; irep->code[irep->clen].insn = OP_SUB;
irep->clen++; irep->clen++;
break; break;
} }
else if (sym == pic->sMUL) { else if (sym == pic->sMUL) {
ARGC_ASSERT(2); ARGC_ASSERT(2);
codegen(state, pic_car(pic, pic_cdr(pic, obj))); codegen(state, pic_car(pic, pic_cdr(pic, obj)), false);
codegen(state, pic_car(pic, pic_cdr(pic, pic_cdr(pic, obj)))); codegen(state, pic_car(pic, pic_cdr(pic, pic_cdr(pic, obj))), false);
irep->code[irep->clen].insn = OP_MUL; irep->code[irep->clen].insn = OP_MUL;
irep->clen++; irep->clen++;
break; break;
} }
else if (sym == pic->sDIV) { else if (sym == pic->sDIV) {
ARGC_ASSERT(2); ARGC_ASSERT(2);
codegen(state, pic_car(pic, pic_cdr(pic, obj))); codegen(state, pic_car(pic, pic_cdr(pic, obj)), false);
codegen(state, pic_car(pic, pic_cdr(pic, pic_cdr(pic, obj)))); codegen(state, pic_car(pic, pic_cdr(pic, pic_cdr(pic, obj))), false);
irep->code[irep->clen].insn = OP_DIV; irep->code[irep->clen].insn = OP_DIV;
irep->clen++; irep->clen++;
break; break;
} }
else if (sym == pic->sEQ) { else if (sym == pic->sEQ) {
ARGC_ASSERT(2); ARGC_ASSERT(2);
codegen(state, pic_car(pic, pic_cdr(pic, obj))); codegen(state, pic_car(pic, pic_cdr(pic, obj)), false);
codegen(state, pic_car(pic, pic_cdr(pic, pic_cdr(pic, obj)))); codegen(state, pic_car(pic, pic_cdr(pic, pic_cdr(pic, obj))), false);
irep->code[irep->clen].insn = OP_EQ; irep->code[irep->clen].insn = OP_EQ;
irep->clen++; irep->clen++;
break; break;
} }
else if (sym == pic->sLT) { else if (sym == pic->sLT) {
ARGC_ASSERT(2); ARGC_ASSERT(2);
codegen(state, pic_car(pic, pic_cdr(pic, obj))); codegen(state, pic_car(pic, pic_cdr(pic, obj)), false);
codegen(state, pic_car(pic, pic_cdr(pic, pic_cdr(pic, obj)))); codegen(state, pic_car(pic, pic_cdr(pic, pic_cdr(pic, obj))), false);
irep->code[irep->clen].insn = OP_LT; irep->code[irep->clen].insn = OP_LT;
irep->clen++; irep->clen++;
break; break;
} }
else if (sym == pic->sLE) { else if (sym == pic->sLE) {
ARGC_ASSERT(2); ARGC_ASSERT(2);
codegen(state, pic_car(pic, pic_cdr(pic, obj))); codegen(state, pic_car(pic, pic_cdr(pic, obj)), false);
codegen(state, pic_car(pic, pic_cdr(pic, pic_cdr(pic, obj)))); codegen(state, pic_car(pic, pic_cdr(pic, pic_cdr(pic, obj))), false);
irep->code[irep->clen].insn = OP_LE; irep->code[irep->clen].insn = OP_LE;
irep->clen++; irep->clen++;
break; break;
} }
else if (sym == pic->sGT) { else if (sym == pic->sGT) {
ARGC_ASSERT(2); ARGC_ASSERT(2);
codegen(state, pic_car(pic, pic_cdr(pic, pic_cdr(pic, obj)))); codegen(state, pic_car(pic, pic_cdr(pic, pic_cdr(pic, obj))), false);
codegen(state, pic_car(pic, pic_cdr(pic, obj))); codegen(state, pic_car(pic, pic_cdr(pic, obj)), false);
irep->code[irep->clen].insn = OP_LT; irep->code[irep->clen].insn = OP_LT;
irep->clen++; irep->clen++;
break; break;
} }
else if (sym == pic->sGE) { else if (sym == pic->sGE) {
ARGC_ASSERT(2); ARGC_ASSERT(2);
codegen(state, pic_car(pic, pic_cdr(pic, pic_cdr(pic, obj)))); codegen(state, pic_car(pic, pic_cdr(pic, pic_cdr(pic, obj))), false);
codegen(state, pic_car(pic, pic_cdr(pic, obj))); codegen(state, pic_car(pic, pic_cdr(pic, obj)), false);
irep->code[irep->clen].insn = OP_LE; irep->code[irep->clen].insn = OP_LE;
irep->clen++; irep->clen++;
break; break;
} }
} }
codegen_call(state, obj); codegen_call(state, obj, tailpos);
break; break;
} }
case PIC_TT_BOOL: { case PIC_TT_BOOL: {
@ -524,7 +532,7 @@ codegen(codegen_state *state, pic_value obj)
} }
static void static void
codegen_call(codegen_state *state, pic_value obj) codegen_call(codegen_state *state, pic_value obj, bool tailpos)
{ {
pic_state *pic = state->pic; pic_state *pic = state->pic;
struct pic_irep *irep = state->irep; struct pic_irep *irep = state->irep;
@ -535,10 +543,10 @@ codegen_call(codegen_state *state, pic_value obj)
pic_value v; pic_value v;
v = pic_car(pic, seq); v = pic_car(pic, seq);
codegen(state, v); codegen(state, v, false);
++i; ++i;
} }
irep->code[irep->clen].insn = OP_CALL; irep->code[irep->clen].insn = tailpos ? OP_TAILCALL : OP_CALL;
irep->code[irep->clen].u.i = i; irep->code[irep->clen].u.i = i;
irep->clen++; irep->clen++;
} }
@ -593,11 +601,15 @@ codegen_lambda(codegen_state *state, pic_value obj)
/* body */ /* body */
body = pic_cdr(pic, pic_cdr(pic, obj)); body = pic_cdr(pic, pic_cdr(pic, obj));
for (v = body; ! pic_nil_p(v); v = pic_cdr(pic, v)) { for (v = body; ! pic_nil_p(v); v = pic_cdr(pic, v)) {
codegen(state, pic_car(pic, v)); if (pic_nil_p(pic_cdr(pic, v))) {
codegen(state, pic_car(pic, v), true);
}
else {
codegen(state, pic_car(pic, v), false);
irep->code[irep->clen].insn = OP_POP; irep->code[irep->clen].insn = OP_POP;
irep->clen++; irep->clen++;
} }
irep->clen--; }
irep->code[irep->clen].insn = OP_RET; irep->code[irep->clen].insn = OP_RET;
irep->clen++; irep->clen++;
@ -651,7 +663,7 @@ pic_codegen(pic_state *pic, pic_value obj)
} }
state->irep = new_irep(pic); state->irep = new_irep(pic);
state->irep->argc = 1; state->irep->argc = 1;
codegen(state, obj); codegen(state, obj, false);
state->irep->code[state->irep->clen].insn = OP_STOP; state->irep->code[state->irep->clen].insn = OP_STOP;
state->irep->clen++; state->irep->clen++;