With struct returns, we normally get a decl on the LHS of the call expression
that will be tail called and we can match things up there easy.
With TREE_ADDRESSABLE set on the type, things get more complex.
Instead we get:
```
  *_6(D) = get_s (1); [return slot optimization]
...
  return _6(D);
```

So we have to match _6 as being the ssa name for the result decl, make sure RSO 
is set
and match MEM_REF with a zero offset if we want to do tail calls.

This is also the first step in allowing tail calls in this case too;  I will 
expand
the patch for PR71761 to handle the taill call later on.

Bootstrapped and tested on x86_64-linux-gnu and aarch64-linux-gnu.

        PR tree-optimization/120871

gcc/ChangeLog:

        * tree-tailcall.cc (find_tail_calls): Allow a MEM_REF
        with a zero offset with RSO set on the call and with
        the MEM_REF is of the result decl default definition.

gcc/testsuite/ChangeLog:

        * g++.dg/opt/tail-call-1.C: New test.

Signed-off-by: Andrew Pinski <quic_apin...@quicinc.com>
---
 gcc/testsuite/g++.dg/opt/tail-call-1.C | 19 +++++++++++++
 gcc/tree-tailcall.cc                   | 37 ++++++++++++++++++++------
 2 files changed, 48 insertions(+), 8 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/opt/tail-call-1.C

diff --git a/gcc/testsuite/g++.dg/opt/tail-call-1.C 
b/gcc/testsuite/g++.dg/opt/tail-call-1.C
new file mode 100644
index 00000000000..eee5287f4aa
--- /dev/null
+++ b/gcc/testsuite/g++.dg/opt/tail-call-1.C
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-tailr-details " } */
+/* PR tree-optimization/120871 */
+
+struct Slice {
+    const char* data;
+    unsigned long size;
+    ~Slice() throw();
+};
+Slice get_s_impl();
+Slice get_s(bool t)
+{
+  if (!t)
+    return get_s(!t);
+  return Slice();
+}
+
+/* Should be able to eliminate the tail recusion in get_s. */
+/* { dg-final { scan-tree-dump-times "Eliminated tail recursion in" 1 "tailr1" 
} } */
diff --git a/gcc/tree-tailcall.cc b/gcc/tree-tailcall.cc
index d6d28302211..dbf70f54956 100644
--- a/gcc/tree-tailcall.cc
+++ b/gcc/tree-tailcall.cc
@@ -715,14 +715,23 @@ find_tail_calls (basic_block bb, struct tailcall **ret, 
bool only_musttail,
      struct.  In this case we won't have a temporary here, but we need
      to carry out the side effect anyway, so tailcall is impossible.
 
-     ??? In some situations (when the struct is returned in memory via
-     invisible argument) we could deal with this, e.g. by passing 'p'
-     itself as that argument to foo, but it's too early to do this here,
-     and expand_call() will not handle it anyway.  If it ever can, then
-     we need to revisit this here, to allow that situation.  */
+     If the call has RSO set and the lhs is a mem of the result decl of
+     the current function, we can handle this case.
+     That is if we have:
+     *_2(D) = function (...) [Return Slot Optimization];
+     This can handled by the middle-end and the tail recursion path.  */
   if (ass_var
-      && !is_gimple_reg (ass_var)
-      && !auto_var_in_fn_p (ass_var, cfun->decl))
+      && gimple_call_return_slot_opt_p (call)
+      && TREE_CODE (ass_var) == MEM_REF
+      && integer_zerop (TREE_OPERAND (ass_var, 1))
+      && TREE_CODE (TREE_OPERAND (ass_var, 0)) == SSA_NAME
+      && SSA_NAME_IS_DEFAULT_DEF (TREE_OPERAND (ass_var, 0))
+      && SSA_NAME_VAR (TREE_OPERAND (ass_var, 0))
+      && TREE_CODE (SSA_NAME_VAR (TREE_OPERAND (ass_var, 0))) == RESULT_DECL)
+    ;
+  else if (ass_var
+          && !is_gimple_reg (ass_var)
+          && !auto_var_in_fn_p (ass_var, cfun->decl))
     {
       maybe_error_musttail (call, _("return value in memory"), diag_musttail);
       return;
@@ -1098,7 +1107,19 @@ find_tail_calls (basic_block bb, struct tailcall **ret, 
bool only_musttail,
     {
       bool ok = false;
       value_range val;
-      if (ass_var == NULL_TREE && !tail_recursion)
+      /* If we have return <retval>_N;, then this can match
+        up with MEM_REF<_N, 0>.
+        RSO is already verfied to be set on the call above.  */
+      if (ass_var
+         && TREE_CODE (ret_var) == SSA_NAME
+         && SSA_NAME_IS_DEFAULT_DEF (ret_var)
+         && SSA_NAME_VAR (ret_var)
+         && TREE_CODE (SSA_NAME_VAR (ret_var)) == RESULT_DECL
+         && TREE_CODE (ass_var) == MEM_REF
+         && integer_zerop (TREE_OPERAND (ass_var, 1))
+         && TREE_OPERAND (ass_var, 0) == ret_var)
+       ok = true;
+      else if (ass_var == NULL_TREE && !tail_recursion)
        {
          tree other_value = NULL_TREE;
          /* If we have a function call that we know the return value is the 
same
-- 
2.43.0

Reply via email to