Since after a tail call function (even if it is tail called in the end),
the current function does not care about the local memory any more so
there is no reason to do a copy of the argument. This is only true for the
first usage of the decl, the rest requires a copy (c-c++-common/pr42909-3.c 
checks that).

Bootstrapped and tested on aarch64-linux-gnu.

        PR middle-end/42909
gcc/ChangeLog:

        * calls.cc (initialize_argument_information): For tail
        calls allow to reuse the argument if it is not addressable
        nor static if the first use of the decl. Disallow tails if
        that argument is not an incoming argument.

gcc/testsuite/ChangeLog:

        * c-c++-common/pr42909-1.c: New testcase
        * c-c++-common/pr42909-2.c: New testcase
        * c-c++-common/pr42909-3.c: New testcase
        * c-c++-common/pr42909-4.c: New testcase

Signed-off-by: Andrew Pinski <quic_apin...@quicinc.com>
---
 gcc/calls.cc                           | 33 ++++++++++++++++++----
 gcc/testsuite/c-c++-common/pr42909-1.c | 19 +++++++++++++
 gcc/testsuite/c-c++-common/pr42909-2.c | 19 +++++++++++++
 gcc/testsuite/c-c++-common/pr42909-3.c | 38 ++++++++++++++++++++++++++
 gcc/testsuite/c-c++-common/pr42909-4.c | 20 ++++++++++++++
 5 files changed, 124 insertions(+), 5 deletions(-)
 create mode 100644 gcc/testsuite/c-c++-common/pr42909-1.c
 create mode 100644 gcc/testsuite/c-c++-common/pr42909-2.c
 create mode 100644 gcc/testsuite/c-c++-common/pr42909-3.c
 create mode 100644 gcc/testsuite/c-c++-common/pr42909-4.c

diff --git a/gcc/calls.cc b/gcc/calls.cc
index ffb57622389..c0416a719d7 100644
--- a/gcc/calls.cc
+++ b/gcc/calls.cc
@@ -52,6 +52,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "intl.h"
 #include "stringpool.h"
 #include "hash-map.h"
+#include "hash-set.h"
 #include "hash-traits.h"
 #include "attribs.h"
 #include "builtins.h"
@@ -1337,6 +1338,7 @@ initialize_argument_information (int num_actuals 
ATTRIBUTE_UNUSED,
 {
   CUMULATIVE_ARGS *args_so_far_pnt = get_cumulative_args (args_so_far);
   location_t loc = EXPR_LOCATION (exp);
+  hash_set<tree> decl_reused;
 
   /* Count arg position in order args appear.  */
   int argpos;
@@ -1428,15 +1430,37 @@ initialize_argument_information (int num_actuals 
ATTRIBUTE_UNUSED,
          const bool callee_copies
            = reference_callee_copied (args_so_far_pnt, arg);
          tree base;
-
+         bool can_reuse_arg = false;
+         bool can_reuse_with_tail_call = call_from_thunk_p;
          /* If we're compiling a thunk, pass directly the address of an object
             already in memory, instead of making a copy.  Likewise if we want
-            to make the copy in the callee instead of the caller.  */
+            to make the copy in the callee instead of the caller. */
          if ((call_from_thunk_p || callee_copies)
              && TREE_CODE (args[i].tree_value) != WITH_SIZE_EXPR
              && ((base = get_base_address (args[i].tree_value)), true)
              && TREE_CODE (base) != SSA_NAME
              && (!DECL_P (base) || MEM_P (DECL_RTL (base))))
+           can_reuse_arg = true;
+
+         /* If we're compiling a tail call, pass the address of an object
+            already in memory, instead of a copy if the argument is a local
+            variable. Since after the tail call, the memory belongs to the 
caller,
+            this is safe even if we don't expand the call in the end as a tail 
call.
+            The first use of the decl can reuse it, the rest uses requires a 
copy.  */
+         if (*may_tailcall
+             && TREE_CODE (args[i].tree_value) != WITH_SIZE_EXPR
+             && ((base = get_base_address (args[i].tree_value)), true)
+             && TREE_CODE (base) != SSA_NAME
+             && DECL_P (base)
+             && !TREE_STATIC (base)
+             && !TREE_ADDRESSABLE (base)
+             && !decl_reused.add (base))
+           {
+             can_reuse_arg = true;
+             can_reuse_with_tail_call = TREE_CODE (base) == PARM_DECL;
+           }
+
+         if (can_reuse_arg)
            {
              /* We may have turned the parameter value into an SSA name.
                 Go back to the original parameter so we can take the
@@ -1461,11 +1485,10 @@ initialize_argument_information (int num_actuals 
ATTRIBUTE_UNUSED,
 
              /* We can't use sibcalls if a callee-copied argument is
                 stored in the current function's frame.  */
-             if (!call_from_thunk_p && DECL_P (base) && !TREE_STATIC (base))
+             if (!can_reuse_with_tail_call && DECL_P (base) && !TREE_STATIC 
(base))
                {
                  *may_tailcall = false;
-                 maybe_complain_about_tail_call (exp, _("a callee-copied "
-                                                        "argument is stored "
+                 maybe_complain_about_tail_call (exp, _("an argument is stored 
"
                                                         "in the current "
                                                         "function's frame"));
                }
diff --git a/gcc/testsuite/c-c++-common/pr42909-1.c 
b/gcc/testsuite/c-c++-common/pr42909-1.c
new file mode 100644
index 00000000000..74348902bc7
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr42909-1.c
@@ -0,0 +1,19 @@
+/* PR middle-end/42909 */
+/* { dg-do compile { target musttail } } */
+/* { dg-options "-O2" } */
+
+typedef struct Foo {
+   int o[16];
+}Foo;
+
+
+int moo(Foo);
+
+int goo(Foo x)
+{
+  [[gnu::musttail]]
+  return moo(x);
+}
+
+/* { dg-final { scan-assembler "b      " { target { aarch64*-*-* } } } } */
+/* { dg-final { scan-assembler-not "bl " { target { aarch64*-*-* } } } } */
diff --git a/gcc/testsuite/c-c++-common/pr42909-2.c 
b/gcc/testsuite/c-c++-common/pr42909-2.c
new file mode 100644
index 00000000000..4cf6ac1842b
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr42909-2.c
@@ -0,0 +1,19 @@
+/* PR middle-end/42909 */
+/* { dg-do compile { target musttail } } */
+/* { dg-options "-O2" } */
+
+typedef struct Foo {
+   int o[16];
+}Foo;
+
+
+int moo(int, Foo);
+
+int goo(Foo x)
+{
+  [[gnu::musttail]]
+  return moo(1, x);
+}
+
+/* { dg-final { scan-assembler "b      " { target { aarch64*-*-* } } } } */
+/* { dg-final { scan-assembler-not "bl " { target { aarch64*-*-* } } } } */
diff --git a/gcc/testsuite/c-c++-common/pr42909-3.c 
b/gcc/testsuite/c-c++-common/pr42909-3.c
new file mode 100644
index 00000000000..3018927c070
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr42909-3.c
@@ -0,0 +1,38 @@
+/* PR middle-end/42909 */
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+
+
+typedef struct Foo {
+   int o[16];
+}Foo;
+
+
+__attribute__((noinline,noipa))
+void check(Foo *a, Foo *b)
+{
+  if (a == b)
+    __builtin_abort();
+}
+
+/* check to make sure what is passed
+   into moo are two locations.  */
+__attribute__((noinline,noipa))
+int moo(Foo x, Foo y)
+{
+  y.o[0] = 1;
+  check(&x, &y);
+  return x.o[0];
+}
+
+__attribute__((noinline,noipa))
+int goo(Foo x)
+{
+  return moo(x, x);
+}
+
+int main()
+{
+  Foo x = {};
+  return goo(x);
+}
diff --git a/gcc/testsuite/c-c++-common/pr42909-4.c 
b/gcc/testsuite/c-c++-common/pr42909-4.c
new file mode 100644
index 00000000000..4567d8ec285
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr42909-4.c
@@ -0,0 +1,20 @@
+/* PR middle-end/42909 */
+/* { dg-do compile { target musttail } } */
+/* { dg-options "-O2" } */
+
+typedef struct Foo {
+   int o[16];
+}Foo;
+
+
+int moo(Foo);
+
+int goo(Foo x)
+{
+  x.o[1] = 1;
+  [[gnu::musttail]]
+  return moo(x);
+}
+
+/* { dg-final { scan-assembler "b      " { target { aarch64*-*-* } } } } */
+/* { dg-final { scan-assembler-not "bl " { target { aarch64*-*-* } } } } */
-- 
2.43.5

Reply via email to