This is the mail archive of the
gcc-help@gcc.gnu.org
mailing list for the GCC project.
Clarification on gcc tail call optimization
- From: raghesh <raghesh dot a at gmail dot com>
- To: gcc-help at gcc dot gnu dot org
- Date: Mon, 31 Oct 2016 15:58:08 +0530
- Subject: Clarification on gcc tail call optimization
- Authentication-results: sourceware.org; auth=none
Hi All,
I am trying to perform tail call optimization on the code given at the
end of this mail (it is also attached).
To facilitate tail call optimization arguments of the functions are
maintained in a structure (so that all functions have same
signature).
The command I used to compile is
gcc -S -O2 -fno-inline struct-simple.c -o struct-simple.s
I observe that gcc performs tail call optimization by converting the
call to functions 'g' and 'h' as 'jmp' instructions in gcc version
4.4.7. However this optimization is not happening with gcc version
4.8.4.
Could someone please explain the reason behind this?
I learned that for gcc to perform tail call optimization it requires
to satisfy a few constraints like (i) caller and callee should have
same signature (ii) callee should not refer to a location in caller's
stack frame. In some cases, even if the input code satisfies these
constraints, I observe that the optimization is not performed. For
example in the code shown below if we have a printf (commented now)
inside function 'g' gcc fails to convert the call to 'h' as jump.
So it would be great if someone can explain or mention some good
reference to learn about the exact set of constraints needed to be
satisfied for gcc to perform tail call optimization.
#include <stdio.h>
#include <stdlib.h>
struct arglist_max {
int i;
int j;
int k;
int l;
};
struct arglist_g {
int a;
int b;
};
struct arglist_f {
int i;
int j;
int k;
int l;
};
void h(struct arglist_max al) {
struct arglist_g al_g = *((struct arglist_g *) &al);
printf("%d %d\n", al_g.a, al_g.b);
}
void g(struct arglist_max al) {
struct arglist_f al_f = *((struct arglist_f *) &al);
struct arglist_g al_g;
al_g.a = 10;
al_g.b = 20;
// The following printf if included the call to funciton
// 'h' will not be coverted to a jump.
//printf("%d %d\n", al_g.a, al_g.b);
struct arglist_max al_max = *((struct arglist_max *) &al_g);
h(al_max);
}
void f(struct arglist_max al) {
struct arglist_f al_f;
al_f.i = 10;
al_f.j = 20;
al_f.k = 30;
al_f.l = 40;
struct arglist_max al_max = *((struct arglist_max *) &al_f);
g(al_max);
}
int main() {
struct arglist_max main_al;
f(main_al);
}
Thanks and Regards,
--
Raghesh Aloor
PhD Scholar
PACE Lab, Dept. of CSE, IIT Madras
http://www.cse.iitm.ac.in/~raghesh/
#include <stdio.h>
#include <stdlib.h>
struct arglist_max {
int i;
int j;
int k;
int l;
};
struct arglist_g {
int a;
int b;
};
struct arglist_f {
int i;
int j;
int k;
int l;
};
void h(struct arglist_max al) {
struct arglist_g al_g = *((struct arglist_g *) &al);
printf("%d %d\n", al_g.a, al_g.b);
}
void g(struct arglist_max al) {
struct arglist_f al_f = *((struct arglist_f *) &al);
struct arglist_g al_g;
al_g.a = 10;
al_g.b = 20;
// The following printf if included the call to funciton
// 'h' will not be coverted to a jump.
//printf("%d %d\n", al_g.a, al_g.b);
struct arglist_max al_max = *((struct arglist_max *) &al_g);
h(al_max);
}
void f(struct arglist_max al) {
struct arglist_f al_f;
al_f.i = 10;
al_f.j = 20;
al_f.k = 30;
al_f.l = 40;
struct arglist_max al_max = *((struct arglist_max *) &al_f);
g(al_max);
}
int main() {
struct arglist_max main_al;
f(main_al);
}