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