Author: leo
Date: Thu Feb 2 09:15:36 2006
New Revision: 11405
Modified:
trunk/compilers/imcc/pcc.c
Log:
Code generation - recursive tail calls
* if -Oc is set and the tail call is recursive, then it's converted
into a loop
* this isn't finished yet - use at your own risk ;)
Modified: trunk/compilers/imcc/pcc.c
==============================================================================
--- trunk/compilers/imcc/pcc.c (original)
+++ trunk/compilers/imcc/pcc.c Thu Feb 2 09:15:36 2006
@@ -1,20 +1,7 @@
/*
* pcc.c
*
- * A specific calling convention implementation. Called by the generic
- * API for subs (see sub.c).
- *
- * FASTCALL convention can be enabled with:
- * .pragma fastcall
- * at the start of an IMC module.
- *
- * This will allow library developers (or non-Perl languages) to turn
- * on very efficient optimizations and a lightweight calling convention.
- * It could also be used for internal libs that do not callout to PCC
- * routines, but present PCC entry points for the module itself.
- *
- * XXX FIXME: FASTCALL is not currently finished and may not be completely
- * compatible with PCC convention. (ie. you can't mix and match, for now at
least)
+ * Parrot calling convention implementation.
*
* see: docs/pdds/pdd03_calling_conventions.pod
*
@@ -258,12 +245,71 @@ expand_pcc_sub_ret(Parrot_Interp interp,
}
}
+/*
+ * convert a recursive tailcall into a loop
+ */
+
+static int
+recursive_tail_call(Parrot_Interp interp, IMC_Unit * unit,
+ Instruction *ins, SymReg *sub)
+{
+ SymReg *called_sub, *this_sub, *r0, *r1, *label;
+ SymReg *regs[2];
+ int i;
+ Instruction *get_params, *tmp_ins;
+ char *buf;
+
+ if (!(unit->instructions->type & ITLABEL))
+ return 0;
+ this_sub = unit->instructions->r[0];
+ if (!this_sub)
+ return 0;
+ called_sub = sub->pcc_sub->sub;
+ if (strcmp(this_sub->name, called_sub->name))
+ return 0;
+ if (sub->pcc_sub->nargs != this_sub->pcc_sub->nargs)
+ return 0;
+ /* TODO check if we have only positional args
+ */
+
+ get_params = unit->instructions->next;
+ if (get_params->opnum != PARROT_OP_get_params_pc)
+ return 0;
+ buf = malloc(strlen(this_sub->name) + 3);
+ sprintf(buf, "[EMAIL PROTECTED]", this_sub->name);
+ if ( (label = find_sym(interp, buf)) == NULL) {
+ label = mk_local_label(interp, str_dup(buf));
+ tmp_ins = INS_LABEL(unit, label, 0);
+ insert_ins(unit, get_params, tmp_ins);
+ }
+ free(buf);
+
+ for (i = 0; i < sub->pcc_sub->nargs; ++i) {
+ /*
+ * TODO if there is a register collision
+ * try to reverse assignmened order
+ * or use a temp var
+ */
+ r0 = this_sub->pcc_sub->args[i];
+ r1 = sub->pcc_sub->args[i];
+ if (r0 != r1) {
+ regs[0] = r0;
+ regs[1] = r1;
+ ins = insINS(interp, unit, ins, "set", regs, 2);
+ }
+ }
+ regs[0] = label;
+ insINS(interp, unit, ins, "branch", regs, 1);
+ return 1;
+}
+
static void
insert_tail_call(Parrot_Interp interp, IMC_Unit * unit,
Instruction *ins, SymReg *sub, int meth_call, SymReg *s0)
{
SymReg *regs[2];
+
if (meth_call) {
s0 = s0 ? s0 : get_pasm_reg(interp, "S0");
regs[0] = sub->pcc_sub->object;
@@ -303,6 +349,10 @@ expand_pcc_sub_call(Parrot_Interp interp
return;
}
tail_call = (sub->pcc_sub->flags & isTAIL_CALL);
+ if (tail_call && IMCC_INFO(interp)->optimizer_level & OPT_SUB) {
+ if (recursive_tail_call(interp, unit, ins, sub))
+ return;
+ }
if (sub->pcc_sub->object) {
meth_call = 1;