On 24 November 2016 at 14:07, Richard Biener <rguent...@suse.de> wrote:
> 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.
Well I was trying to copy-propagate function's argument into uses of
it's return value if
function returned that argument, so the assignment to lhs of call
could be made redundant.

eg:
void *f(void *a1, void *a2, __SIZE_TYPE__ a3)
{
  void *t1 = __builtin_memcpy (a1, a2, a3);
  return t1;
}

After patch, copyprop transformed it into:
t1 = __builtin_memcpy (a1, a2, a3);
return a1;

But this now interferes with tail-call optimization, because it is not
able to emit memcpy
as tail-call anymore due to which the patch regressed 20050503-1.c.
I am not sure how to workaround this.

Thanks,
Prathamesh
>
> Richard.
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-copyprop-3.c 
b/gcc/testsuite/gcc.dg/tree-ssa/ssa-copyprop-3.c
new file mode 100644
index 0000000..8319e9f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-copyprop-3.c
@@ -0,0 +1,35 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-copyprop-slim" } */
+
+void f(char *dest, const char *src, __SIZE_TYPE__ n)
+{
+  char *t1 = __builtin_strcpy (dest, src);
+  if (t1 != dest)
+    __builtin_abort ();
+
+  char *t2 = __builtin_strncpy (dest, src, n);
+  if (t2 != dest)
+    __builtin_abort ();
+
+  char *t3 = __builtin_strcat (dest, src);
+  if (t3 != dest)
+    __builtin_abort ();
+
+  char *t4 = __builtin_strncat (dest, src, n);
+  if (t4 != dest)
+    __builtin_abort ();
+
+  void *t5 = __builtin_memmove (dest, src, n);
+  if (t5 != dest)
+    __builtin_abort ();
+
+  void *t6 = __builtin_memcpy (dest, src, n);
+  if (t6 != dest)
+    __builtin_abort ();
+
+  void *t7 = __builtin_memset (dest, 0, n);
+  if (t7 != dest)
+    __builtin_abort ();
+}
+
+/* { dg-final { scan-tree-dump-not "__builtin_abort" "copyprop1" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-copyprop-4.c 
b/gcc/testsuite/gcc.dg/tree-ssa/ssa-copyprop-4.c
new file mode 100644
index 0000000..199074d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-copyprop-4.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-copyprop" } */
+
+char *f(char *dest, const char *src)
+{
+  char *t1 = __builtin_strcpy (dest, src);
+  return t1; 
+}
+
+/* { dg-final { scan-tree-dump "return dest_\[0-9\]*\\(D\\);" "copyprop1" } } 
*/
diff --git a/gcc/tree-ssa-copy.c b/gcc/tree-ssa-copy.c
index abc6205..77f4ad7 100644
--- a/gcc/tree-ssa-copy.c
+++ b/gcc/tree-ssa-copy.c
@@ -80,6 +80,9 @@ stmt_may_generate_copy (gimple *stmt)
   if (gimple_code (stmt) == GIMPLE_PHI)
     return !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (gimple_phi_result (stmt));
 
+  if (gimple_code (stmt) == GIMPLE_CALL)
+    return true;
+
   if (gimple_code (stmt) != GIMPLE_ASSIGN)
     return false;
 
@@ -252,6 +255,40 @@ copy_prop_visit_cond_stmt (gimple *stmt, edge 
*taken_edge_p)
   return retval;
 }
 
+/* Check if call returns one of it's arguments, and in that
+   case set copy-of (lhs) to the returned argument.  */
+
+static enum ssa_prop_result
+copy_prop_visit_call (gcall *call_stmt, tree *result_p)
+{
+  tree lhs = gimple_call_lhs (call_stmt);
+  if (!lhs || TREE_CODE (lhs) != SSA_NAME)
+    return SSA_PROP_VARYING;
+
+  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);
+         if (TREE_CODE (arg) == SSA_NAME)
+           {
+             arg = valueize_val (arg);
+             if (!may_propagate_copy (lhs, arg))
+               return SSA_PROP_VARYING;
+
+             *result_p = lhs;
+             if (set_copy_of_val (*result_p, arg))
+               return SSA_PROP_INTERESTING;
+             else
+               return SSA_PROP_NOT_INTERESTING;
+           }
+       }
+    }
+
+  return SSA_PROP_VARYING;
+}
 
 /* Evaluate statement STMT.  If the statement produces a new output
    value, return SSA_PROP_INTERESTING and store the SSA_NAME holding
@@ -290,6 +327,8 @@ copy_prop_visit_stmt (gimple *stmt, edge *taken_edge_p, 
tree *result_p)
         jump.  */
       retval = copy_prop_visit_cond_stmt (stmt, taken_edge_p);
     }
+  else if (gcall *call_stmt = dyn_cast<gcall *> (stmt))
+    retval = copy_prop_visit_call (call_stmt, result_p);
   else
     retval = SSA_PROP_VARYING;
 

Reply via email to