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);
+}

Reply via email to