Hi, The fix for
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=49519 is too conservative. It disables some sibcall optimizations. This patch changes to check register address only when called from store_one_arg. Any comments? Thanks. H.J. --- gcc/ 2011-09-10 H.J. Lu <hongjiu...@intel.com> PR middle-end/49719 PR middle-end/50074 * calls.c (mem_overlaps_already_clobbered_arg_p): Add an argument and check if address is stored in register only when needed. (load_register_parameters): Pass false mem_overlaps_already_clobbered_arg_p. (check_sibcall_argument_overlap_1): Likewise. (store_one_arg): Pass true to mem_overlaps_already_clobbered_arg_p. gcc/testsuite/ 2011-09-10 H.J. Lu <hongjiu...@intel.com> PR middle-end/50074 * gcc.dg/sibcall-9.c: New. diff --git a/gcc/calls.c b/gcc/calls.c index a6e96e4..dabc8b0 100644 --- a/gcc/calls.c +++ b/gcc/calls.c @@ -1578,7 +1578,9 @@ rtx_for_function_call (tree fndecl, tree addr) sibcall. */ static bool -mem_overlaps_already_clobbered_arg_p (rtx addr, unsigned HOST_WIDE_INT size) +mem_overlaps_already_clobbered_arg_p (rtx addr, + unsigned HOST_WIDE_INT size, + bool check_addr_reg) { HOST_WIDE_INT i; @@ -1595,7 +1597,7 @@ mem_overlaps_already_clobbered_arg_p (rtx addr, unsigned HOST_WIDE_INT size) return true; /* If the address comes in a register, we have no idea of its origin so give up and conservatively return true. */ - else if (REG_P(addr)) + else if (check_addr_reg && REG_P(addr)) return true; else return false; @@ -1716,7 +1718,8 @@ load_register_parameters (struct arg_data *args, int num_actuals, if (is_sibcall && (size == 0 || mem_overlaps_already_clobbered_arg_p - (XEXP (args[i].value, 0), size))) + (XEXP (args[i].value, 0), size, + false))) *sibcall_failure = 1; /* Handle a BLKmode that needs shifting. */ @@ -1843,7 +1846,8 @@ check_sibcall_argument_overlap_1 (rtx x) if (code == MEM) return mem_overlaps_already_clobbered_arg_p (XEXP (x, 0), - GET_MODE_SIZE (GET_MODE (x))); + GET_MODE_SIZE (GET_MODE (x)), + false); /* Scan all subexpressions. */ fmt = GET_RTX_FORMAT (code); @@ -4256,7 +4260,8 @@ store_one_arg (struct arg_data *arg, rtx argblock, int flags, if ((flags & ECF_SIBCALL) && MEM_P (arg->value) && mem_overlaps_already_clobbered_arg_p (XEXP (arg->value, 0), - arg->locate.size.constant)) + arg->locate.size.constant, + true)) sibcall_failure = 1; /* Don't allow anything left on stack from computation diff --git a/gcc/testsuite/gcc.dg/sibcall-9.c b/gcc/testsuite/gcc.dg/sibcall-9.c new file mode 100644 index 0000000..a6299af --- /dev/null +++ b/gcc/testsuite/gcc.dg/sibcall-9.c @@ -0,0 +1,38 @@ +/* { dg-do run { target { { i?86-*-* x86_64-*-* s390*-*-* } && fpic } } } */ +/* { dg-skip-if "" { { i?86-*-* x86_64-*-* } && ia32 } { "*" } { "" } } */ +/* { dg-options "-O2 -foptimize-sibling-calls -fno-ipa-cp -fPIC" } */ + +extern void abort (void); +extern void exit (int); + +int foo (int); +int bar (int); + +int (*ptr) (int); +int *f_addr; + +int +main () +{ + ptr = bar; + foo (7); + exit (0); +} + +int __attribute__ ((noinline)) +bar (b) + int b; +{ + if (f_addr == (int*) __builtin_return_address (0)) + return b; + else + abort (); +} + +int __attribute__ ((noinline)) +foo (f) + int f; +{ + f_addr = (int*) __builtin_return_address (0); + return (*ptr)(f); +}