https://gcc.gnu.org/g:ee67004474d521f7e107ec2795cfbb894a855c87

commit r16-3201-gee67004474d521f7e107ec2795cfbb894a855c87
Author: Andrew Pinski <quic_apin...@quicinc.com>
Date:   Tue Jun 10 00:11:58 2025 -0700

    forwprop: Copy prop aggregates into args
    
    This implements the simple copy prop of aggregates into
    arguments of function calls. This can reduce the number of copies
    done. Just like removing of an extra copy in general, this can and
    will help out SRA; since we might not need to do a full scalarization
    of the aggregate now.
    
    This is the simpliest form of this copy prop of aggregates into function 
arguments.
    
    Changes since v1:
    * v2: Merge in the changes of r16-3160-g2fe432175ef135.
          Move the checks for assignment and call statement into 
optimize_agr_copyprop
          rather than having it in optimize_agr_copyprop_1 and 
optimize_agr_copyprop_arg.
    
    gcc/ChangeLog:
    
            * tree-ssa-forwprop.cc (optimize_agr_copyprop_1): New function 
split out of ...
            (optimize_agr_copyprop): Here. Also try calling 
optimize_agr_copyprop_arg.
            (optimize_agr_copyprop_arg): New function.
    
    gcc/testsuite/ChangeLog:
    
            * gcc.dg/tree-ssa/copy-prop-aggregate-arg-1.c: New test.
    
    Signed-off-by: Andrew Pinski <quic_apin...@quicinc.com>

Diff:
---
 .../gcc.dg/tree-ssa/copy-prop-aggregate-arg-1.c    |  21 +++
 gcc/tree-ssa-forwprop.cc                           | 171 ++++++++++++++-------
 2 files changed, 137 insertions(+), 55 deletions(-)

diff --git a/gcc/testsuite/gcc.dg/tree-ssa/copy-prop-aggregate-arg-1.c 
b/gcc/testsuite/gcc.dg/tree-ssa/copy-prop-aggregate-arg-1.c
new file mode 100644
index 000000000000..2ce68918e576
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/copy-prop-aggregate-arg-1.c
@@ -0,0 +1,21 @@
+/* { dg-do compile } */ 
+/* { dg-options "-O1 -fdump-tree-optimized -fdump-tree-forwprop1-details" } */
+
+struct s1
+{
+  int t[1024];
+};
+
+void f(struct s1);
+
+void g(struct s1 a)
+{
+  struct s1 temp_struct0 = a;
+  f(temp_struct0);
+}
+
+/* There should be no references to any of "temp_struct*"
+   temporaries.  */
+/* { dg-final { scan-tree-dump-times "temp_struct" 0 "optimized" } } */
+/* Also check that forwprop pass did the copy prop. */
+/* { dg-final { scan-tree-dump-times "after previous" 1 "forwprop1" } } */
diff --git a/gcc/tree-ssa-forwprop.cc b/gcc/tree-ssa-forwprop.cc
index 2878b45b60d6..ec4fbeb9e540 100644
--- a/gcc/tree-ssa-forwprop.cc
+++ b/gcc/tree-ssa-forwprop.cc
@@ -1416,6 +1416,106 @@ optimize_aggr_zeroprop (gimple_stmt_iterator *gsip)
 
   return changed;
 }
+
+/* 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. */
+static bool
+optimize_agr_copyprop_1 (gimple *stmt, gimple *use_stmt,
+                        tree dest, tree src)
+{
+  gcc_assert (gimple_assign_load_p (use_stmt)
+             && gimple_store_p (use_stmt));
+  if (gimple_has_volatile_ops (use_stmt))
+    return false;
+  tree dest2 = gimple_assign_lhs (use_stmt);
+  tree src2 = gimple_assign_rhs1 (use_stmt);
+  /* If the new store is `src2 = src2;` skip over it. */
+  if (operand_equal_p (src2, dest2, 0))
+    return false;
+  if (!operand_equal_p (dest, src2, 0))
+    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.
+     See PR 22237 for full details.
+     E.g.
+     t = *a; #DEST = SRC;
+     *b = t; #DEST2 = SRC2;
+     Cannot be convert into
+     t = *a;
+     *b = *a;
+     Though the following is allowed to be done:
+     t = *a;
+     *a = t;
+     And convert it into:
+     t = *a;
+     *a = *a;
+     */
+  if (!operand_equal_p (dest2, src, 0)
+      && !DECL_P (dest2) && !DECL_P (src))
+    return false;
+
+  if (dump_file && (dump_flags & TDF_DETAILS))
+    {
+      fprintf (dump_file, "Simplified\n  ");
+      print_gimple_stmt (dump_file, use_stmt, 0, dump_flags);
+      fprintf (dump_file, "after previous\n  ");
+      print_gimple_stmt (dump_file, stmt, 0, dump_flags);
+    }
+  gimple *orig_stmt = use_stmt;
+  gimple_stmt_iterator gsi = gsi_for_stmt (use_stmt);
+  gimple_assign_set_rhs_from_tree (&gsi, unshare_expr (src));
+  update_stmt (use_stmt);
+
+  if (dump_file && (dump_flags & TDF_DETAILS))
+    {
+      fprintf (dump_file, "into\n  ");
+      print_gimple_stmt (dump_file, use_stmt, 0, dump_flags);
+    }
+  if (maybe_clean_or_replace_eh_stmt (orig_stmt, use_stmt))
+    bitmap_set_bit (to_purge, gimple_bb (stmt)->index);
+  statistics_counter_event (cfun, "copy prop for aggregate", 1);
+  return true;
+}
+
+/* Helper function for optimize_agr_copyprop_1, propagate aggregates
+   into the arguments of USE_STMT if the argument matches with DEST;
+   replacing it with SRC.  */
+static bool
+optimize_agr_copyprop_arg (gimple *defstmt, gcall *call,
+                          tree dest, tree src)
+{
+  bool changed = false;
+  for (unsigned arg = 0; arg < gimple_call_num_args (call); arg++)
+    {
+      tree *argptr = gimple_call_arg_ptr (call, arg);
+      if (TREE_CODE (*argptr) == SSA_NAME
+         || is_gimple_min_invariant (*argptr)
+         || TYPE_VOLATILE (TREE_TYPE (*argptr)))
+       continue;
+      if (!operand_equal_p (*argptr, dest, 0))
+       continue;
+      if (dump_file && (dump_flags & TDF_DETAILS))
+       {
+         fprintf (dump_file, "Simplified\n  ");
+         print_gimple_stmt (dump_file, call, 0, dump_flags);
+         fprintf (dump_file, "after previous\n  ");
+         print_gimple_stmt (dump_file, defstmt, 0, dump_flags);
+       }
+      *argptr = unshare_expr (src);
+      changed = true;
+      if (dump_file && (dump_flags & TDF_DETAILS))
+       {
+         fprintf (dump_file, "into\n  ");
+         print_gimple_stmt (dump_file, call, 0, dump_flags);
+       }
+    }
+  if (changed)
+    update_stmt (call);
+  return changed;
+}
+
 /* Optimizes
    DEST = SRC;
    DEST2 = DEST; # DEST2 = SRC2;
@@ -1424,6 +1524,14 @@ optimize_aggr_zeroprop (gimple_stmt_iterator *gsip)
    DEST2 = SRC;
    GSIP is the first statement and SRC is the common
    between the statements.
+
+   Also optimizes:
+   DEST = SRC;
+   call_func(..., DEST, ...);
+   into:
+   DEST = SRC;
+   call_func(..., SRC, ...);
+
 */
 static bool
 optimize_agr_copyprop (gimple_stmt_iterator *gsip)
@@ -1448,61 +1556,14 @@ optimize_agr_copyprop (gimple_stmt_iterator *gsip)
   bool changed = false;
   FOR_EACH_IMM_USE_STMT (use_stmt, iter, vdef)
     {
-      if (!gimple_assign_load_p (use_stmt)
-         || !gimple_store_p (use_stmt))
-       continue;
-      if (gimple_has_volatile_ops (use_stmt))
-       continue;
-      tree dest2 = gimple_assign_lhs (use_stmt);
-      tree src2 = gimple_assign_rhs1 (use_stmt);
-      /* If the new store is `src2 = src2;` skip over it. */
-      if (operand_equal_p (src2, dest2, 0))
-       continue;
-      if (!operand_equal_p (dest, src2, 0))
-       continue;
-      /* 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.
-        See PR 22237 for full details.
-        E.g.
-        t = *a; #DEST = SRC;
-        *b = t; #DEST2 = SRC2;
-        Cannot be convert into
-        t = *a;
-        *b = *a;
-        Though the following is allowed to be done:
-        t = *a;
-        *a = t;
-        And convert it into:
-        t = *a;
-        *a = *a;
-       */
-      if (!operand_equal_p (dest2, src, 0)
-         && !DECL_P (dest2) && !DECL_P (src))
-       continue;
-      if (dump_file && (dump_flags & TDF_DETAILS))
-       {
-         fprintf (dump_file, "Simplified\n  ");
-         print_gimple_stmt (dump_file, use_stmt, 0, dump_flags);
-         fprintf (dump_file, "after previous\n  ");
-         print_gimple_stmt (dump_file, stmt, 0, dump_flags);
-       }
-      gimple *orig_stmt = use_stmt;
-      gimple_stmt_iterator gsi = gsi_for_stmt (use_stmt);
-      gimple_assign_set_rhs_from_tree (&gsi, unshare_expr (src));
-      update_stmt (use_stmt);
-
-      if (dump_file && (dump_flags & TDF_DETAILS))
-       {
-         fprintf (dump_file, "into\n  ");
-         print_gimple_stmt (dump_file, use_stmt, 0, dump_flags);
-       }
-
-      /* Mark the bb for eh cleanup if needed.  */
-      if (maybe_clean_or_replace_eh_stmt (orig_stmt, use_stmt))
-       bitmap_set_bit (to_purge, gimple_bb (stmt)->index);
-      statistics_counter_event (cfun, "copy prop for aggregate", 1);
-      changed = true;
+      if (gimple_assign_load_p (use_stmt)
+         && gimple_store_p (use_stmt)
+         && optimize_agr_copyprop_1 (stmt, use_stmt, dest, src))
+       changed = true;
+      else if (is_gimple_call (use_stmt)
+              && optimize_agr_copyprop_arg (stmt, as_a<gcall*>(use_stmt),
+                                            dest, src))
+       changed = true;
     }
   return changed;
 }

Reply via email to