| /* { dg-skip-if "requires frame pointers" { *-*-* } "-fomit-frame-pointer" "" } */ |
| /* { dg-require-effective-target return_address } */ |
| |
| extern void exit (int); |
| extern void abort (void); |
| extern void *alloca (__SIZE_TYPE__); |
| char *dummy (void); |
| |
| #define NOINLINE __attribute__((noinline)) __attribute__ ((noclone)) |
| |
| void *save_ret1[6]; |
| void *test4a (char *); |
| void *test5a (char *); |
| void *test6a (char *); |
| |
| void NOINLINE *test1 (void) |
| { |
| void * temp; |
| temp = __builtin_return_address (0); |
| return temp; |
| } |
| |
| void NOINLINE *test2 (void) |
| { |
| void * temp; |
| dummy (); |
| temp = __builtin_return_address (0); |
| return temp; |
| } |
| |
| void NOINLINE *test3 (void) |
| { |
| void * temp; |
| temp = __builtin_return_address (0); |
| dummy (); |
| return temp; |
| } |
| |
| void NOINLINE *test4 (void) |
| { |
| char * save = (char*) alloca (4); |
| |
| return test4a (save); |
| } |
| |
| void *NOINLINE test4a (char * p) |
| { |
| void * temp; |
| temp = __builtin_return_address (1); |
| return temp; |
| } |
| |
| void NOINLINE *test5 (void) |
| { |
| char * save = (char*) alloca (4); |
| |
| return test5a (save); |
| } |
| |
| void NOINLINE *test5a (char * p) |
| { |
| void * temp; |
| dummy (); |
| temp = __builtin_return_address (1); |
| return temp; |
| } |
| |
| void NOINLINE *test6 (void) |
| { |
| char * save = (char*) alloca (4); |
| |
| return test6a (save); |
| } |
| |
| void NOINLINE *test6a (char * p) |
| { |
| void * temp; |
| temp = __builtin_return_address (1); |
| dummy (); |
| return temp; |
| } |
| |
| void *(*func1[6])(void) = { test1, test2, test3, test4, test5, test6 }; |
| |
| char * NOINLINE call_func1 (int i) |
| { |
| save_ret1[i] = func1[i] (); |
| } |
| |
| static void *ret_addr; |
| void *save_ret2[6]; |
| void test10a (char *); |
| void test11a (char *); |
| void test12a (char *); |
| |
| void NOINLINE test7 (void) |
| { |
| ret_addr = __builtin_return_address (0); |
| return; |
| } |
| |
| void NOINLINE test8 (void) |
| { |
| dummy (); |
| ret_addr = __builtin_return_address (0); |
| return; |
| } |
| |
| void NOINLINE test9 (void) |
| { |
| ret_addr = __builtin_return_address (0); |
| dummy (); |
| return; |
| } |
| |
| void NOINLINE test10 (void) |
| { |
| char * save = (char*) alloca (4); |
| |
| test10a (save); |
| } |
| |
| void NOINLINE test10a (char * p) |
| { |
| ret_addr = __builtin_return_address (1); |
| return; |
| } |
| |
| void NOINLINE test11 (void) |
| { |
| char * save = (char*) alloca (4); |
| |
| test11a (save); |
| } |
| |
| void NOINLINE test11a (char * p) |
| { |
| dummy (); |
| ret_addr = __builtin_return_address (1); |
| return; |
| } |
| |
| void NOINLINE test12 (void) |
| { |
| char * save = (char*) alloca (4); |
| |
| test12a (save); |
| } |
| |
| void NOINLINE test12a (char * p) |
| { |
| ret_addr = __builtin_return_address (1); |
| dummy (); |
| return; |
| } |
| |
| char * dummy (void) |
| { |
| char * save = (char*) alloca (4); |
| |
| return save; |
| } |
| |
| void (*func2[6])(void) = { test7, test8, test9, test10, test11, test12 }; |
| |
| void NOINLINE call_func2 (int i) |
| { |
| func2[i] (); |
| save_ret2[i] = ret_addr; |
| } |
| |
| int main (void) |
| { |
| int i; |
| |
| for (i = 0; i < 6; i++) { |
| call_func1(i); |
| } |
| |
| if (save_ret1[0] != save_ret1[1] |
| || save_ret1[1] != save_ret1[2]) |
| abort (); |
| if (save_ret1[3] != save_ret1[4] |
| || save_ret1[4] != save_ret1[5]) |
| abort (); |
| if (save_ret1[3] && save_ret1[0] != save_ret1[3]) |
| abort (); |
| |
| |
| for (i = 0; i < 6; i++) { |
| call_func2(i); |
| } |
| |
| if (save_ret2[0] != save_ret2[1] |
| || save_ret2[1] != save_ret2[2]) |
| abort (); |
| if (save_ret2[3] != save_ret2[4] |
| || save_ret2[4] != save_ret2[5]) |
| abort (); |
| if (save_ret2[3] && save_ret2[0] != save_ret2[3]) |
| abort (); |
| |
| exit (0); |
| } |