new file mode 100644
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-tailr-details" } */
+
+void *f(void *a1, void *a2, __SIZE_TYPE__ a3)
+{
+ __builtin_memcpy (a1, a2, a3);
+ return a1;
+}
+
+/* { dg-final { scan-tree-dump "_\[0-9\]* = __builtin_memcpy" "tailr1" } } */
@@ -401,6 +401,7 @@ find_tail_calls (basic_block bb, struct tailcall **ret)
basic_block abb;
size_t idx;
tree var;
+ greturn *ret_stmt = NULL;
if (!single_succ_p (bb))
return;
@@ -408,6 +409,8 @@ find_tail_calls (basic_block bb, struct tailcall **ret)
for (gsi = gsi_last_bb (bb); !gsi_end_p (gsi); gsi_prev (&gsi))
{
stmt = gsi_stmt (gsi);
+ if (!ret_stmt)
+ ret_stmt = dyn_cast<greturn *> (stmt);
/* Ignore labels, returns, nops, clobbers and debug stmts. */
if (gimple_code (stmt) == GIMPLE_LABEL
@@ -422,6 +425,35 @@ find_tail_calls (basic_block bb, struct tailcall **ret)
{
call = as_a <gcall *> (stmt);
ass_var = gimple_call_lhs (call);
+ if (!ass_var && ret_stmt)
+ {
+ /* Check if function returns one if it's arguments
+ and that argument is used as return value.
+ In that case create an artificial lhs to call_stmt,
+ and set it as the return value. */
+
+ unsigned rf = gimple_call_return_flags (call);
+ if (rf & ERF_RETURNS_ARG)
+ {
+ unsigned argnum = rf & ERF_RETURN_ARG_MASK;
+ if (argnum < gimple_call_num_args (call))
+ {
+ tree arg = gimple_call_arg (call, argnum);
+ tree retval = gimple_return_retval (ret_stmt);
+ if (retval
+ && TREE_CODE (retval) == SSA_NAME
+ && operand_equal_p (retval, arg, 0)
+ && !DECL_BY_REFERENCE (DECL_RESULT (cfun->decl)))
+ {
+ ass_var = copy_ssa_name (arg);
+ gimple_call_set_lhs (call, ass_var);
+ update_stmt (call);
+ gimple_return_set_retval (ret_stmt, ass_var);
+ update_stmt (ret_stmt);
+ }
+ }
+ }
+ }
break;
}