Tail Recursion
Tel
telford@eng.uts.edu.au
Fri Oct 2 00:09:00 GMT 1998
I'm from the guile (scheme) mailing list and the argument has come
up over tail calls. Some test code of mine seems to show a bug in
egcs tail recursion:
----------------------------------------------------------------tail.c
typedef int returnable_thing;
extern int i;
extern void silly_side_effect( void );
extern returnable_thing tail_final( void );
returnable_thing tail_eater( void )
{
silly_side_effect();
if( i-- )
{
return( tail_eater());
}
return( tail_final());
}
----------------------------------------------------------------------
Compiled with: gcc -O -S -fomit-frame-pointer tail.c
to give:
----------------------------------------------------------------tail.s
.file "tail.c"
.version "01.01"
gcc2_compiled.:
.text
.align 4
.globl tail_eater
.type tail_eater,@function
tail_eater:
.L3:
call silly_side_effect
decl i
cmpl $-1,i
jne .L3
call tail_final
ret
.Lfe1:
.size tail_eater,.Lfe1-tail_eater
.ident "GCC: (GNU) egcs-2.91.57 19980901 (egcs-1.1 release)"
----------------------------------------------------------------------
All looks good here, the tail recursion of tail_eater() into itself
has become a loop and doesn't blow the stack. However, changing the
first line to:
typedef void returnable_thing;
will give this result:
----------------------------------------------------------------tail.s
.file "tail.c"
.version "01.01"
gcc2_compiled.:
.text
.align 4
.globl tail_eater
.type tail_eater,@function
tail_eater:
call silly_side_effect
decl i
cmpl $-1,i
je .L2
call tail_eater
ret
.p2align 4,,7
.L2:
call tail_final
ret
.Lfe1:
.size tail_eater,.Lfe1-tail_eater
.ident "GCC: (GNU) egcs-2.91.57 19980901 (egcs-1.1 release)"
----------------------------------------------------------------------
The tail recursion is spoiled but why shouldn't I get tail recursion
from a function returning void? It seems strange that it would be handled
differently to other functions, am I missing the obvious?
One further question... why can't ``call tail_final'' also be optimised to a
jump? It seems to me that ANY call immediately followed by a return
should be optimised to a jump. I understand that the frame pointer
would normally be between the call and the ret but when I tell the
compiler -fomit-frame-pointer then I'm saying that I don't give a toss
about debugging and what I want is the best optimisation. This would
allow mutual recursion and state machines and other nice things.
Does this depend on processor architecture? Is so, why?
- Tel
More information about the Gcc-bugs
mailing list