On Mon, Sep 15, 2025 at 7:20 PM Andrew Pinski
<[email protected]> wrote:
>
> 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.

OK.

> 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 <[email protected]>
> ---
>  .../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