> Am 13.08.2025 um 19:05 schrieb Andrew Pinski <andrew.pin...@oss.qualcomm.com>:
>
> From: Andrew Pinski <quic_apin...@quicinc.com>
>
> 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.
Ok
Thanks,
Richard
> 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>
> ---
> .../tree-ssa/copy-prop-aggregate-arg-1.c | 21 +++
> gcc/tree-ssa-forwprop.cc | 171 ++++++++++++------
> 2 files changed, 137 insertions(+), 55 deletions(-)
> create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/copy-prop-aggregate-arg-1.c
>
> 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 00000000000..2ce68918e57
> --- /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 2878b45b60d..ec4fbeb9e54 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;
> }
> --
> 2.43.0
>