From: Leopold Toetsch <[EMAIL PROTECTED]>
   Date: Tue, 22 Feb 2005 10:40:40 +0100

   Bob Rogers <[EMAIL PROTECTED]> wrote:
   >    From: Leopold Toetsch <[EMAIL PROTECTED]>

   > It had seemed otherwise, looking at imcc/pcc.c yesterday, but I must not
   > have been looking closely enough.  Is that what the "&& !tmp->next" in
   > line 583 does (CVS 1.86)?  Is there a rationale behind limiting it this
   > way?

   Yep - No, I don't see a rationale behind it. Just remove the test and
   try it ;)

It works, with no apparent change to other tests (because none of them
specify "-Oc", no doubt).

   . . .

   > ... For consistency, there
   > must be two .pcc_* constructs:  .pcc_tail_call and .pcc_return_call,
   > with corresponding semantics.

   Just .pcc_tail_call.

   >    The extra syntax also provides detailed control over tail-call
   > optimization.

   I'd say: .tail_call always does a tail call. The check_tail_call() can
   be dropped then.

   leo

That takes IMCC out of the loop when it comes to tail-call optimization.
But IMCC seems like the natural place for doing these low-level
optimizations . . .

   In any case, the patch in the first attachment below does three
things:

   1.  Removes the arbitrary check_tail_call() restriction to the final
position.

   2.  Fixes a bug in testing for the implicit "null I0; null I3;
returncc" sequence -- it's "returncc", not "invoke".  Those instructions
are still emitted after the "tailcall"; I wasn't sure how to remove them
without leaking memory.

   3.  Additionally, fixes a subtle typo in ABI_CHANGES (look closely!)

   And the test file in the second attachment adds three tests to cover
1 and 2, albeit with calls in "lying to IMCC" style.  I put this in
imcc/t/syn/tail.t, but there may be a better place.

   Also, I notice that none of this tailcall optimization behavior is
documented . . . is there an appropriate place for it?

   So now I'm motivated to "do it right."  My contribution to the Parrot
code so far is the deletion of five tokens, and the replacement of one
other -- and several posts explaining why this isn't adequate.  I don't
dare leave it at just that.  ;-}

                                        -- Bob Rogers
                                           http://rgrjr.dyndns.org/

Index: ABI_CHANGES
===================================================================
RCS file: /cvs/public/parrot/ABI_CHANGES,v
retrieving revision 1.2
diff -u -r1.2 ABI_CHANGES
--- ABI_CHANGES 27 Nov 2004 13:19:21 -0000      1.2
+++ ABI_CHANGES 26 Feb 2005 17:27:15 -0000
@@ -41,4 +41,4 @@
 2004.11.15 leo
 
 The variables P0, P1, P2, S0 aren't visible in the called subroutine
-anymore.  See docs/ppds/pdd03_calling_conventions.pod.
+anymore.  See docs/pdds/pdd03_calling_conventions.pod.
Index: imcc/pcc.c
===================================================================
RCS file: /cvs/public/parrot/imcc/pcc.c,v
retrieving revision 1.86
diff -u -r1.86 pcc.c
--- imcc/pcc.c  15 Jan 2005 21:04:58 -0000      1.86
+++ imcc/pcc.c  26 Feb 2005 17:27:18 -0000
@@ -580,8 +580,8 @@
     if (!tmp)
         return 0;
     if (tmp->opnum == -1 && (tmp->type & ITPCCSUB) &&
-            (tmp->type & ITLABEL) && !tmp->next) {
-                ret_ins = tmp;
+            (tmp->type & ITLABEL)) {
+        ret_ins = tmp;
         IMCC_debug(interp, DEBUG_OPT1, "check tail call %I \n", ins);
     }
     /*
@@ -605,7 +605,7 @@
         }
         else
             return 0;
-        if (strcmp(tmp->op, "invoke"))
+        if (strcmp(tmp->op, "returncc"))
             return 0;
         IMCC_debug(interp, DEBUG_OPT1, "check tail call %I \n", tmp);
         nrets = 0;
#!perl
use strict;
use TestCompiler tests => 3;

##############################
# Parrot Calling Conventions:  Tail call optimization.

$ENV{TEST_PROG_ARGS} = '-Oc';

output_is(<<'CODE', <<'OUT', "tail call optimization, final position");

.sub _main @MAIN

        $P1 = new PerlInt
        $P1 = 20
        $P2 = new PerlInt
        $P2 = 3
        newsub $P99, .Sub, _floor
        ($P3, $P4) = _funcall($P99, $P1, $P2)
        print "_floor returned "
        print argcP
        print " values, "
        print $P3
        print " and "
        print $P4
        print ".\n"
        newsub $P98, .Sub, _fib_step
        ($P3, $P4, $P5) = _funcall($P98, $P1, $P2)
        print "_fib_step returned "
        print argcP
        print " values, "
        print $P3
        print ", "
        print $P4
        print ", and "
        print $P5
        print ".\n"
.end

.sub _funcall non_prototyped
        .param pmc function
        .local pmc argv
        argv = foldup 1

        print "[doing _funcall]\n"
        $I33 = defined function
        if $I33 goto doit
bad_func:
        printerr "_funcall:  Bad function.\n"
        die
doit:
        .pcc_begin prototyped
        .flatten_arg argv
        .pcc_call function
        .pcc_end
        .pcc_begin_return
        .pcc_end_return
.end

## Return quotient and remainder as two integers.
.sub _floor
        .param pmc arg1
        .param pmc arg2

        $P1 = new PerlInt
        $P1 = arg1 / arg2
        ## truncate.
        $I1 = $P1
        $P1 = $I1
        $P2 = new PerlInt
        $P2 = arg1 % arg2
        .pcc_begin_return
        .return $P1
        .return $P2
        .pcc_end_return
.end

## Return the sum and the two arguments as three integers.
.sub _fib_step
        .param pmc arg1
        .param pmc arg2

        $P1 = new PerlInt
        $P1 = arg1 + arg2
        .pcc_begin_return
        .return $P1
        .return arg1
        .return arg2
        .pcc_end_return
.end
CODE
[doing _funcall]
_floor returned 2 values, 6 and 2.
[doing _funcall]
_fib_step returned 3 values, 23, 20, and 3.
OUT

output_is(<<'CODE', <<'OUT', "tail call optimization, intermediate position");

.sub _main @MAIN

        $P1 = new PerlInt
        $P1 = 20
        $P2 = new PerlInt
        $P2 = 3
        newsub $P99, .Sub, _floor
        ($P3, $P4) = _funcall($P99, $P1, $P2)
        print "_floor returned "
        print argcP
        print " values, "
        print $P3
        print " and "
        print $P4
        print ".\n"
        newsub $P98, .Sub, _fib_step
        ($P3, $P4, $P5) = _funcall($P98, $P1, $P2)
        print "_fib_step returned "
        print argcP
        print " values, "
        print $P3
        print ", "
        print $P4
        print ", and "
        print $P5
        print ".\n"
.end

.sub _funcall non_prototyped
        .param pmc function
        .local pmc argv
        argv = foldup 1

        print "[doing _funcall]\n"
        $I33 = defined function
        unless $I33 goto bad_func
doit:
        .pcc_begin prototyped
        .flatten_arg argv
        .pcc_call function
        .pcc_end
        .pcc_begin_return
        .pcc_end_return
bad_func:
        printerr "_funcall:  Bad function.\n"
        die
.end

## Return quotient and remainder as two integers.
.sub _floor
        .param pmc arg1
        .param pmc arg2

        $P1 = new PerlInt
        $P1 = arg1 / arg2
        ## truncate.
        $I1 = $P1
        $P1 = $I1
        $P2 = new PerlInt
        $P2 = arg1 % arg2
        .pcc_begin_return
        .return $P1
        .return $P2
        .pcc_end_return
.end

## Return the sum and the two arguments as three integers.
.sub _fib_step
        .param pmc arg1
        .param pmc arg2

        $P1 = new PerlInt
        $P1 = arg1 + arg2
        .pcc_begin_return
        .return $P1
        .return arg1
        .return arg2
        .pcc_end_return
.end
CODE
[doing _funcall]
_floor returned 2 values, 6 and 2.
[doing _funcall]
_fib_step returned 3 values, 23, 20, and 3.
OUT

output_is(<<'CODE', <<'OUT', "tail call optimization, implicit final return");

.sub _main @MAIN

        $P1 = new PerlInt
        $P1 = 20
        $P2 = new PerlInt
        $P2 = 3
        newsub $P99, .Sub, _floor
        ($P3, $P4) = _funcall($P99, $P1, $P2)
        print "_floor returned "
        print argcP
        print " values, "
        print $P3
        print " and "
        print $P4
        print ".\n"
        newsub $P98, .Sub, _fib_step
        ($P3, $P4, $P5) = _funcall($P98, $P1, $P2)
        print "_fib_step returned "
        print argcP
        print " values, "
        print $P3
        print ", "
        print $P4
        print ", and "
        print $P5
        print ".\n"
.end

.sub _funcall non_prototyped
        .param pmc function
        .local pmc argv
        argv = foldup 1

        print "[doing _funcall]\n"
        $I33 = defined function
        if $I33 goto doit
bad_func:
        printerr "_funcall:  Bad function.\n"
        die
doit:
        .pcc_begin prototyped
        .flatten_arg argv
        .pcc_call function
        .pcc_end
.end

## Return quotient and remainder as two integers.
.sub _floor
        .param pmc arg1
        .param pmc arg2

        $P1 = new PerlInt
        $P1 = arg1 / arg2
        ## truncate.
        $I1 = $P1
        $P1 = $I1
        $P2 = new PerlInt
        $P2 = arg1 % arg2
        .pcc_begin_return
        .return $P1
        .return $P2
        .pcc_end_return
.end

## Return the sum and the two arguments as three integers.
.sub _fib_step
        .param pmc arg1
        .param pmc arg2

        $P1 = new PerlInt
        $P1 = arg1 + arg2
        .pcc_begin_return
        .return $P1
        .return arg1
        .return arg2
        .pcc_end_return
.end
CODE
[doing _funcall]
_floor returned 2 values, 6 and 2.
[doing _funcall]
_fib_step returned 3 values, 23, 20, and 3.
OUT

Reply via email to