This moves the code used in optimize_agr_copyprop_1 (r16-3887-g597b50abb0d)
to handle this same case into its new function and use it inside
optimize_agr_copyprop_arg. This allows to remove more copies that show up only
in arguments.

Bootstrapped and tested on x86_64-linux-gnu.

gcc/ChangeLog:

        * tree-ssa-forwprop.cc (optimize_agr_copyprop_1): Split out
        the case where `operand_equal_p (dest, src2)` is false into ...
        (new_src_based_on_copy): This. New function.
        (optimize_agr_copyprop_arg): Use new_src_based_on_copy
        instead of operand_equal_p to find the new src.

gcc/testsuite/ChangeLog:

        * gcc.dg/tree-ssa/copy-prop-aggregate-arg-2.c: New test.

Signed-off-by: Andrew Pinski <andrew.pin...@oss.qualcomm.com>
---
 .../tree-ssa/copy-prop-aggregate-arg-2.c      |  33 +++++
 gcc/tree-ssa-forwprop.cc                      | 135 ++++++++++--------
 2 files changed, 106 insertions(+), 62 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/copy-prop-aggregate-arg-2.c

diff --git a/gcc/testsuite/gcc.dg/tree-ssa/copy-prop-aggregate-arg-2.c 
b/gcc/testsuite/gcc.dg/tree-ssa/copy-prop-aggregate-arg-2.c
new file mode 100644
index 00000000000..11f0768c111
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/copy-prop-aggregate-arg-2.c
@@ -0,0 +1,33 @@
+/* { dg-do compile } */
+/* { dg-options "-O1 -fdump-tree-forwprop1-details -fdump-tree-optimized" } */
+
+
+struct s1
+{
+  int t[1024];
+};
+
+struct s2 {
+  struct s1 t;
+};
+
+struct s3
+{
+  struct s2 t;
+};
+
+void g(struct s3);
+
+void f(struct s1 s)
+{
+  struct s2 removeme;
+  removeme.t = s;
+  struct s3 removeme2;
+  removeme2.t = removeme;
+  g(removeme2);
+}
+
+
+/* { dg-final { scan-tree-dump-times "after previous" 2 "forwprop1" } } */
+/* { dg-final { scan-tree-dump-not "removeme " "optimized" } } */
+/* { dg-final { scan-tree-dump-not "removeme2 " "optimized" } } */
diff --git a/gcc/tree-ssa-forwprop.cc b/gcc/tree-ssa-forwprop.cc
index 1eacff01587..f58a7b8c591 100644
--- a/gcc/tree-ssa-forwprop.cc
+++ b/gcc/tree-ssa-forwprop.cc
@@ -1458,6 +1458,72 @@ split_core_and_offset_size (tree expr,
   return core;
 }
 
+/* Returns a new src based on the
+   copy `DEST = SRC` and for the old SRC2.
+   Returns null if SRC2 is not related to DEST.  */
+
+static tree
+new_src_based_on_copy (tree src2, tree dest, tree src)
+{
+  /* If the second src is not exactly the same as dest,
+     try to handle it seperately; see it is address/size equivalent.
+     Handles `a` and `a.b` and `MEM<char[N]>(&a)` which all have
+     the same size and offsets as address/size equivalent.
+     This allows copying over a memcpy and also one for copying
+     where one field is the same size as the whole struct.  */
+  if (operand_equal_p (dest, src2))
+    return src;
+  /* A VCE can't be used with imag/real or BFR so reject them early. */
+  if (TREE_CODE (src) == IMAGPART_EXPR
+      || TREE_CODE (src) == REALPART_EXPR
+      || TREE_CODE (src) == BIT_FIELD_REF)
+    return NULL_TREE;
+  tree core1, core2;
+  poly_int64 bytepos1, bytepos2;
+  poly_int64 bytesize1, bytesize2;
+  tree toffset1, toffset2;
+  int reversep1 = 0;
+  int reversep2 = 0;
+  poly_int64 diff = 0;
+  core1 = split_core_and_offset_size (dest, &bytesize1, &bytepos1,
+                                         &toffset1, &reversep1);
+  core2 = split_core_and_offset_size (src2, &bytesize2, &bytepos2,
+                                         &toffset2, &reversep2);
+  if (!core1 || !core2)
+    return NULL_TREE;
+  if (reversep1 != reversep2)
+    return NULL_TREE;
+  /* The sizes of the 2 accesses need to be the same. */
+  if (!known_eq (bytesize1, bytesize2))
+    return NULL_TREE;
+  if (!operand_equal_p (core1, core2, 0))
+    return NULL_TREE;
+
+  if (toffset1 && toffset2)
+    {
+      tree type = TREE_TYPE (toffset1);
+      if (type != TREE_TYPE (toffset2))
+       toffset2 = fold_convert (type, toffset2);
+
+      tree tdiff = fold_build2 (MINUS_EXPR, type, toffset1, toffset2);
+      if (!cst_and_fits_in_hwi (tdiff))
+       return NULL_TREE;
+
+      diff = int_cst_value (tdiff);
+    }
+  else if (toffset1 || toffset2)
+    {
+      /* If only one of the offsets is non-constant, the difference cannot
+        be a constant.  */
+      return NULL_TREE;
+    }
+  diff += bytepos1 - bytepos2;
+  /* The offset between the 2 need to be 0. */
+  if (!known_eq (diff, 0))
+    return NULL_TREE;
+  return fold_build1 (VIEW_CONVERT_EXPR,TREE_TYPE (src2), src);
+}
+
 /* Helper function for optimize_agr_copyprop.
    For aggregate copies in USE_STMT, see if DEST
    is on the lhs of USE_STMT and replace it with SRC. */
@@ -1474,66 +1540,9 @@ optimize_agr_copyprop_1 (gimple *stmt, gimple *use_stmt,
   /* If the new store is `src2 = src2;` skip over it. */
   if (operand_equal_p (src2, dest2, 0))
     return false;
-  /* If the second src is not exactly the same as dest,
-     try to handle it seperately; see it is address/size equivalent.
-     Handles `a` and `a.b` and `MEM<char[N]>(&a)` which all have
-     the same size and offsets as address/size equivalent.
-     This allows copying over a memcpy and also one for copying
-     where one field is the same size as the whole struct.  */
-  if (!operand_equal_p (dest, src2, 0))
-    {
-      /* A VCE can't be used with imag/real or BFR so reject them early. */
-      if (TREE_CODE (src) == IMAGPART_EXPR
-         || TREE_CODE (src) == REALPART_EXPR
-         || TREE_CODE (src) == BIT_FIELD_REF)
-       return false;
-      tree core1, core2;
-      poly_int64 bytepos1, bytepos2;
-      poly_int64 bytesize1, bytesize2;
-      tree toffset1, toffset2;
-      int reversep1 = 0;
-      int reversep2 = 0;
-      poly_int64 diff = 0;
-      core1 = split_core_and_offset_size (dest, &bytesize1, &bytepos1,
-                                         &toffset1, &reversep1);
-      core2 = split_core_and_offset_size (src2, &bytesize2, &bytepos2,
-                                         &toffset2, &reversep2);
-      if (!core1 || !core2)
-       return false;
-      if (reversep1 != reversep2)
-       return false;
-      /* The sizes of the 2 accesses need to be the same. */
-      if (!known_eq (bytesize1, bytesize2))
-       return false;
-      if (!operand_equal_p (core1, core2, 0))
-       return false;
-
-      if (toffset1 && toffset2)
-       {
-         tree type = TREE_TYPE (toffset1);
-         if (type != TREE_TYPE (toffset2))
-           toffset2 = fold_convert (type, toffset2);
-
-         tree tdiff = fold_build2 (MINUS_EXPR, type, toffset1, toffset2);
-         if (!cst_and_fits_in_hwi (tdiff))
-           return false;
-
-         diff = int_cst_value (tdiff);
-       }
-      else if (toffset1 || toffset2)
-       {
-         /* If only one of the offsets is non-constant, the difference cannot
-            be a constant.  */
-         return false;
-       }
-      diff += bytepos1 - bytepos2;
-      /* The offset between the 2 need to be 0. */
-      if (!known_eq (diff, 0))
-       return false;
-      src = fold_build1_loc (gimple_location (use_stmt),
-                            VIEW_CONVERT_EXPR,
-                            TREE_TYPE (src2), src);
-    }
+  src = new_src_based_on_copy (src2, dest, src);
+  if (!src)
+    return false;
   /* For 2 memory refences and using a temporary to do the copy,
      don't remove the temporary as the 2 memory references might overlap.
      Note t does not need to be decl as it could be field.
@@ -1634,8 +1643,10 @@ optimize_agr_copyprop_arg (gimple *defstmt, gcall *call,
          || is_gimple_min_invariant (*argptr)
          || TYPE_VOLATILE (TREE_TYPE (*argptr)))
        continue;
-      if (!operand_equal_p (*argptr, dest, 0))
+      tree newsrc = new_src_based_on_copy (*argptr, dest, src);
+      if (!newsrc)
        continue;
+
       if (dump_file && (dump_flags & TDF_DETAILS))
        {
          fprintf (dump_file, "Simplified\n  ");
@@ -1643,7 +1654,7 @@ optimize_agr_copyprop_arg (gimple *defstmt, gcall *call,
          fprintf (dump_file, "after previous\n  ");
          print_gimple_stmt (dump_file, defstmt, 0, dump_flags);
        }
-      *argptr = unshare_expr (src);
+      *argptr = unshare_expr (newsrc);
       changed = true;
       if (dump_file && (dump_flags & TDF_DETAILS))
        {
-- 
2.43.0

Reply via email to