On Sun, Jun 8, 2025 at 7:52 PM Andrew Pinski <quic_apin...@quicinc.com> wrote:
>
> While thinking about how to implement the rest of the copy prop and makes 
> sure not
> to introduce some compile time problems, optimize_agr_copyprop should be 
> changed
> into a forwproping rather than looking backwards.

Can you explain the issues when doing the backwards looking?

Note since this is a pure local "propagation" I still wonder whether
(now in the forward direction)
we want to use single_imm_use () instead of iterating over all uses of
the VDEF.  Basically
we want to keep the optimization as "local" as possible.

I also wondered about

b = a;
c = b;
d = b;

we'll transform c = b into c = a and that's it.

In the end I still hope we can leverage more global analysis, like
that of SRA, to decide
whether propagation is profitable or not, thus whether we can elide a
temporary.  In
that regard, shouldn't we avoid the propagation if 'DEST' has its
address taken given
we certainly cannot elide it?

Thanks,
Richard.

> Bootstrapped and tested on x86_64-linux-gnu.
>
> gcc/ChangeLog:
>
>         * tree-ssa-forwprop.cc (optimize_agr_copyprop): Change into a
>         forward looking (looking at vdef's uses) instead of a back
>         looking (vuse's def).
>
> Signed-off-by: Andrew Pinski <quic_apin...@quicinc.com>
> ---
>  gcc/tree-ssa-forwprop.cc | 121 +++++++++++++++++++--------------------
>  1 file changed, 60 insertions(+), 61 deletions(-)
>
> diff --git a/gcc/tree-ssa-forwprop.cc b/gcc/tree-ssa-forwprop.cc
> index 43b1c9d696f..2dc77ccba1d 100644
> --- a/gcc/tree-ssa-forwprop.cc
> +++ b/gcc/tree-ssa-forwprop.cc
> @@ -1344,12 +1344,12 @@ optimize_memcpy_to_memset (gimple_stmt_iterator 
> *gsip, tree dest, tree src, tree
>    return true;
>  }
>  /* Optimizes
> -   a = c;
> -   b = a;
> +   DEST = SRC;
> +   DEST2 = DEST; # DEST2 = SRC2;
>     into
> -   a = c;
> -   b = c;
> -   GSIP is the second statement and SRC is the common
> +   DEST = SRC;
> +   DEST2 = SRC;
> +   GSIP is the first statement and SRC is the common
>     between the statements.
>  */
>  static bool
> @@ -1365,65 +1365,64 @@ optimize_agr_copyprop (gimple_stmt_iterator *gsip)
>    if (operand_equal_p (dest, src, 0))
>      return false;
>
> -  tree vuse = gimple_vuse (stmt);
> -  /* If the vuse is the default definition, then there is no store 
> beforehand.  */
> -  if (SSA_NAME_IS_DEFAULT_DEF (vuse))
> -    return false;
> -  gimple *defstmt = SSA_NAME_DEF_STMT (vuse);
> -  if (!gimple_assign_load_p (defstmt)
> -      || !gimple_store_p (defstmt))
> -    return false;
> -  if (gimple_has_volatile_ops (defstmt))
> -    return false;
> -
> -  tree dest2 = gimple_assign_lhs (defstmt);
> -  tree src2 = gimple_assign_rhs1 (defstmt);
> -
> -  /* If the original store is `src2 = src2;` skip over it. */
> -  if (operand_equal_p (src2, dest2, 0))
> -    return false;
> -  if (!operand_equal_p (src, dest2, 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;
> -     *b = t;
> -     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 (src2, dest, 0)
> -      && !DECL_P (dest) && !DECL_P (src2))
> -    return false;
> -
> -  if (dump_file && (dump_flags & TDF_DETAILS))
> +  tree vdef = gimple_vdef (stmt);
> +  imm_use_iterator iter;
> +  gimple *use_stmt;
> +  bool changed = false;
> +  FOR_EACH_IMM_USE_STMT (use_stmt, iter, vdef)
>      {
> -      fprintf (dump_file, "Simplified\n  ");
> -      print_gimple_stmt (dump_file, stmt, 0, dump_flags);
> -      fprintf (dump_file, "after previous\n  ");
> -      print_gimple_stmt (dump_file, defstmt, 0, dump_flags);
> -    }
> -  gimple_assign_set_rhs_from_tree (gsip, unshare_expr (src2));
> -  update_stmt (stmt);
> +      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_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, stmt, 0, dump_flags);
> +      if (dump_file && (dump_flags & TDF_DETAILS))
> +       {
> +         fprintf (dump_file, "into\n  ");
> +         print_gimple_stmt (dump_file, use_stmt, 0, dump_flags);
> +       }
> +      statistics_counter_event (cfun, "copy prop for aggregate", 1);
> +      changed = true;
>      }
> -  statistics_counter_event (cfun, "copy prop for aggregate", 1);
> -  return true;
> +  return changed;
>  }
>
>  /* *GSI_P is a GIMPLE_CALL to a builtin function.
> --
> 2.43.0
>

Reply via email to