On Wed, Sep 17, 2025 at 12:33 AM Andrew Pinski
<andrew.pin...@oss.qualcomm.com> wrote:
>
> After r16-3887-g597b50abb0d2fc, the check to see if the copy is
> a nop copy becomes inefficient. The code going into an infinite
> loop as the copy keeps on being propagated over and over again.
>
> That is if we have:
> ```
>   struct s1 *b = &a.t;
>   a.t = *b;
>   p = *b;
> ```
>
> This goes into an infinite loop propagating over and over again the
> `MEM[&a]`.
> To solve this a new function is needed for the comparison that is
> similar to new_src_based_on_copy.

OK.

>         PR tree-optimization/121962
>
> gcc/ChangeLog:
>
>         * tree-ssa-forwprop.cc (same_for_assignment): New function.
>         (optimize_agr_copyprop_1): Use same_for_assignment to check for
>         nop copies.
>         (optimize_agr_copyprop): Likewise.
>
> gcc/testsuite/ChangeLog:
>
>         * gcc.dg/torture/pr121962-1.c: New test.
>
> Signed-off-by: Andrew Pinski <andrew.pin...@oss.qualcomm.com>
> ---
>  gcc/testsuite/gcc.dg/torture/pr121962-1.c | 21 ++++++++
>  gcc/tree-ssa-forwprop.cc                  | 64 ++++++++++++++++++++++-
>  2 files changed, 83 insertions(+), 2 deletions(-)
>  create mode 100644 gcc/testsuite/gcc.dg/torture/pr121962-1.c
>
> diff --git a/gcc/testsuite/gcc.dg/torture/pr121962-1.c 
> b/gcc/testsuite/gcc.dg/torture/pr121962-1.c
> new file mode 100644
> index 00000000000..97f88ad5734
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/torture/pr121962-1.c
> @@ -0,0 +1,21 @@
> +/* PR tree-optimization/121962 */
> +struct s1
> +{
> +  int t;
> +};
> +
> +struct s2
> +{
> +  struct s1 t;
> +};
> +
> +struct s1 p;
> +
> +void f(struct s2 a)
> +{
> +  struct s1 *b = &a.t;
> +  /* this is a nop load/store and should be ignored
> +     by copy propagation for aggregates.  */
> +  a.t = *b;
> +  p = *b;
> +}
> diff --git a/gcc/tree-ssa-forwprop.cc b/gcc/tree-ssa-forwprop.cc
> index 9d389e1b9bf..833a354ce2c 100644
> --- a/gcc/tree-ssa-forwprop.cc
> +++ b/gcc/tree-ssa-forwprop.cc
> @@ -1528,6 +1528,66 @@ new_src_based_on_copy (tree src2, tree dest, tree src)
>    return fold_build1 (VIEW_CONVERT_EXPR,TREE_TYPE (src2), src);
>  }
>
> +/* Returns true if SRC and DEST are the same address such that
> +   `SRC == DEST;` is conisdered a nop. This is more than an
> +   operand_equal_p check as it needs to be similar to
> +   new_src_based_on_copy.  */
> +
> +static bool
> +same_for_assignment (tree src, tree dest)
> +{
> +  if (operand_equal_p (dest, src, 0))
> +    return true;
> +  /* if both dest and src2 are decls, then we know these 2
> +     accesses can't be the same.  */
> +  if (DECL_P (dest) && DECL_P (src))
> +    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 (src, &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;
> +  return true;
> +}
> +
>  /* 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. */
> @@ -1542,7 +1602,7 @@ optimize_agr_copyprop_1 (gimple *stmt, gimple *use_stmt,
>    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))
> +  if (same_for_assignment (src2, dest2))
>      return false;
>    src = new_src_based_on_copy (src2, dest, src);
>    if (!src)
> @@ -1702,7 +1762,7 @@ optimize_agr_copyprop (gimple_stmt_iterator *gsip)
>    tree dest = gimple_assign_lhs (stmt);
>    tree src = gimple_assign_rhs1 (stmt);
>    /* If the statement is `src = src;` then ignore it. */
> -  if (operand_equal_p (dest, src, 0))
> +  if (same_for_assignment (dest, src))
>      return false;
>
>    tree vdef = gimple_vdef (stmt);
> --
> 2.43.0
>

Reply via email to