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