[net.lang.c] Tail recursion optimization

atbowler@watmath.UUCP (Alan T. Bowler [SDG]) (04/15/86)

In article <708@bentley.UUCP> kwh@bentley.UUCP (KW Heuer) writes:
>A good optimizer should compile tail-recursion into a jump anyway.  (But
>there are few good optimizers by that standard.)
>
There is a problem if you want to support a "nargs" function with this.
If an implementation tries stores the nargs value in some fixed position
in the call sequence then it cannot optimize tail recursion into
a branch to this or some other function.  (If your compiler
wants to optimize tail recursion then why not end calls as well.)
   On a lot of hardware models it is quite feasible to put a nargs
constant a part of the call sequence (as was done in pre-version 6 Unix).
If this is possible it seems the most useful place to keep it since
it involves essentially no overhead unless the called program chooses
to use it.  Tail recursion and end call optimization results in
the "wrong" nargs value being found.  (i.e. that associated with
the original call to the function and not the call that was
optimized out).  There are 2 ways arround this
  1) always pass the nargs value as an explicit hidden argument
     which raises the overhead for all function calls.
     (i.e. an expensive choice to make).
  2) delete nargs functionality which denies the programmer a
     very useful tool to reduced the overhead and name clutter
     in is program.
I know that the later option is one I must assume when I am writing
very portable programs, but there are many times when I am writing
system specific code and it is annoying to have to do things like
"node1(a), node2(a, b), node3(a,b,c)".  In environments where
I have NARGS guaranteed, I make more use of it than tail recursion.

henry@utzoo.UUCP (Henry Spencer) (04/15/86)

> >A good optimizer should compile tail-recursion into a jump anyway...
> 
> There is a problem if you want to support a "nargs" function with this...

Nargs was a useful thing back in the days of V5 and early V6, when almost
everything in C was one word in size.  Its usefulness is greatly diminished
now that C's data types have gotten more diverse.  Especially since there
are serious portability problems involved in *doing* anything with the
information, and with implementing nargs at all.  For these reasons, most
everyone has stopped using it.  Nargs is not a major argument against a
potentially useful optimization.
-- 
Support the International
League For The Derision		Henry Spencer @ U of Toronto Zoology
Of User-Friendliness!		{allegra,ihnp4,decvax,pyramid}!utzoo!henry

sam@delftcc.UUCP (Sam Kendall) (04/17/86)

I haven't seen it mentioned yet that if you optimize away a stack frame
which is referred to by a jmp_buf (the setjmp data type), a longjmp
to that stack frame will fail.  Therefore a compiler that wants to
optimize tail recursion must know about setjmp in order to suppress
tail recursion optimization in functions that call setjmp.  This is
compatible with the ANSI draft standard.

A couple of points to answer (square brackets mine):

In article <2122@watmath.UUCP>, atbowler@watmath.UUCP writes:
> There is a problem if you want to support a "nargs" function with [tail
> recursion].
> If an implementation tries stores the nargs value in some fixed position
> in the call sequence then it cannot optimize tail recursion into
> a branch to this or some other function.

If you really want nargs, just optimize tail recursion into a change to
the nargs value, followed by a branch.  What's the problem?

> [I]t is annoying to have to do things like
> "node1(a), node2(a, b), node3(a,b,c)".

You can use varargs here.  You also need an argument list terminator,
so do something like

	#define NIL	((NODE *) NULL)
	/* assuming arguments to node are of type NODE * */
	node(a, NIL)
	node(a, b, c, NIL)

----
Sam Kendall			{ ihnp4 | seismo!cmcl2 }!delftcc!sam
Delft Consulting Corp.		ARPA: delftcc!sam@NYU.ARPA