Message ID | CAAgBjMkcer2PZkJNBE10eAqWt2RXT7vOp+ERmp+FL1QQhmVZGA@mail.gmail.com |
---|---|
State | New |
Headers | show |
On Thu, 24 Nov 2016, Prathamesh Kulkarni wrote: > Hi, > Consider following test-case: > > void *f(void *a1, void *a2, __SIZE_TYPE__ a3) > { > __builtin_memcpy (a1, a2, a3); > return a1; > } > > return a1 can be considered equivalent to return value of memcpy, > and the call could be emitted as a tail-call. > gcc doesn't emit the above call to memcpy as a tail-call, > but if it is changed to: > > void *t1 = __builtin_memcpy (a1, a2, a3); > return t1; > > Then memcpy is emitted as a tail-call. > The attached patch tries to handle the former case. > > Bootstrapped+tested on x86_64-unknown-linux-gnu. > Cross tested on arm*-*-*, aarch64*-*-* > Does this patch look OK ? +/* Return arg, if function returns it's argument or NULL if it doesn't. */ +tree +gimple_call_return_arg (gcall *call_stmt) +{ Please just inline it at the single use - the name is not terribly informative. I'm not sure you can rely on code-generation working if you not effectively change the IL to a1 = __builtin_memcpy (a1, a2, a3); return a1; someone more familiar with RTL expansion plus tail call emission on RTL needs to chime in. Richard.
diff --git a/gcc/gimple.c b/gcc/gimple.c index 0a3dc72..ec460fc 100644 --- a/gcc/gimple.c +++ b/gcc/gimple.c @@ -2561,6 +2561,23 @@ gimple_call_combined_fn (const gimple *stmt) return CFN_LAST; } +/* Return arg, if function returns it's argument or NULL if it doesn't. */ +tree +gimple_call_return_arg (gcall *call_stmt) +{ + unsigned rf = gimple_call_return_flags (call_stmt); + if (rf & ERF_RETURNS_ARG) + { + unsigned argnum = rf & ERF_RETURN_ARG_MASK; + if (argnum < gimple_call_num_args (call_stmt)) + { + tree arg = gimple_call_arg (call_stmt, argnum); + return arg; + } + } + return NULL_TREE; +} + /* Return true if STMT clobbers memory. STMT is required to be a GIMPLE_ASM. */ diff --git a/gcc/gimple.h b/gcc/gimple.h index 0d0296e..ebccbe1 100644 --- a/gcc/gimple.h +++ b/gcc/gimple.h @@ -1520,6 +1520,7 @@ extern combined_fn gimple_call_combined_fn (const gimple *); extern bool gimple_call_builtin_p (const gimple *); extern bool gimple_call_builtin_p (const gimple *, enum built_in_class); extern bool gimple_call_builtin_p (const gimple *, enum built_in_function); +extern tree gimple_call_return_arg (gcall *); extern bool gimple_asm_clobbers_memory_p (const gasm *); extern void dump_decl_set (FILE *, bitmap); extern bool nonfreeing_call_p (gimple *); diff --git a/gcc/testsuite/gcc.dg/tree-ssa/tailcall-8.c b/gcc/testsuite/gcc.dg/tree-ssa/tailcall-8.c new file mode 100644 index 0000000..b3fdc6c --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/tailcall-8.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-tailc-details" } */ + +void *f(void *a1, void *a2, __SIZE_TYPE__ a3) +{ + __builtin_memcpy (a1, a2, a3); + return a1; +} + +/* { dg-final { scan-tree-dump-times "Found tail call" 1 "tailc" } } */ diff --git a/gcc/tree-tailcall.c b/gcc/tree-tailcall.c index f97541d..3396473 100644 --- a/gcc/tree-tailcall.c +++ b/gcc/tree-tailcall.c @@ -422,6 +422,8 @@ find_tail_calls (basic_block bb, struct tailcall **ret) { call = as_a <gcall *> (stmt); ass_var = gimple_call_lhs (call); + if (!ass_var) + ass_var = gimple_call_return_arg (call); break; }