On Wed, Sep 17, 2025 at 4:55 AM Andrew Pinski
<[email protected]> wrote:
>
> Since now optimize_aggr_zeroprop and optimize_agr_copyprop work by forward
> walk to prop
> the zero/aggregate and does not change the statement at hand, there is no
> reason to
> repeat the loop if they do anything. This will prevent problems like PR
> 121962 from
> happening again as we will never loop.
>
> Bootstrapped and tested on x86_64-linux-gnu.
>
> gcc/ChangeLog:
>
> * tree-ssa-forwprop.cc (optimize_aggr_zeroprop_1): Change return type
> to void.
> (optimize_aggr_zeroprop): Likewise.
> (optimize_agr_copyprop_1): Likewise.
> (optimize_agr_copyprop_arg): Likewise.
> (optimize_agr_copyprop): Likewise.
> (simplify_builtin_call): Handle update of the return type
> of optimize_aggr_zeroprop.
> (pass_forwprop::execute): Likewise and optimize_agr_copyprop.
>
> Signed-off-by: Andrew Pinski <[email protected]>
> ---
> gcc/tree-ssa-forwprop.cc | 90 ++++++++++++++++------------------------
> 1 file changed, 35 insertions(+), 55 deletions(-)
>
> diff --git a/gcc/tree-ssa-forwprop.cc b/gcc/tree-ssa-forwprop.cc
> index 833a354ce2c..357eec54d00 100644
> --- a/gcc/tree-ssa-forwprop.cc
> +++ b/gcc/tree-ssa-forwprop.cc
> @@ -1190,7 +1190,7 @@ constant_pointer_difference (tree p1, tree p2)
> /* Helper function for optimize_aggr_zeroprop.
> Props the zeroing (memset, VAL) that was done in DEST+OFFSET:LEN
> (DEFSTMT) into the STMT. Returns true if the STMT was updated. */
> -static bool
> +static void
> optimize_aggr_zeroprop_1 (gimple *defstmt, gimple *stmt,
> tree dest, poly_int64 offset, tree val,
> poly_offset_int len)
> @@ -1214,29 +1214,29 @@ optimize_aggr_zeroprop_1 (gimple *defstmt, gimple
> *stmt,
> : TYPE_SIZE_UNIT (TREE_TYPE (src2)));
> /* Can only handle zero memsets. */
> if (!integer_zerop (val))
> - return false;
> + return;
> }
> else
> - return false;
> + return;
>
> if (len2 == NULL_TREE
> || !poly_int_tree_p (len2))
> - return false;
> + return;
>
> src2 = get_addr_base_and_unit_offset (src2, &offset2);
> if (src2 == NULL_TREE
> || maybe_lt (offset2, offset))
> - return false;
> + return;
>
> if (!operand_equal_p (dest, src2, 0))
> - return false;
> + return;
>
> /* [ dest + offset, dest + offset + len - 1 ] is set to val.
> Make sure that
> [ dest + offset2, dest + offset2 + len2 - 1 ] is a subset of that. */
> if (maybe_gt (wi::to_poly_offset (len2) + (offset2 - offset),
> len))
> - return false;
> + return;
>
> if (dump_file && (dump_flags & TDF_DETAILS))
> {
> @@ -1282,8 +1282,6 @@ optimize_aggr_zeroprop_1 (gimple *defstmt, gimple *stmt,
> /* Mark the bb for eh cleanup if needed. */
> if (maybe_clean_or_replace_eh_stmt (orig_stmt, stmt))
> bitmap_set_bit (to_purge, gimple_bb (stmt)->index);
> -
> - return true;
> }
>
> /* Optimize
> @@ -1295,19 +1293,18 @@ optimize_aggr_zeroprop_1 (gimple *defstmt, gimple
> *stmt,
> Similarly for memset (&a, ..., sizeof (a)); instead of a = {};
> and/or memcpy (&b, &a, sizeof (a)); instead of b = a; */
>
> -static bool
> +static void
> optimize_aggr_zeroprop (gimple_stmt_iterator *gsip, bool full_walk)
> {
> ao_ref read;
> gimple *stmt = gsi_stmt (*gsip);
> if (gimple_has_volatile_ops (stmt))
> - return false;
> + return;
>
> tree dest = NULL_TREE;
> tree val = integer_zero_node;
> tree len = NULL_TREE;
> bool can_use_tbba = true;
> - bool changed = false;
>
> if (gimple_call_builtin_p (stmt, BUILT_IN_MEMSET)
> && TREE_CODE (gimple_call_arg (stmt, 0)) == ADDR_EXPR
> @@ -1362,7 +1359,7 @@ optimize_aggr_zeroprop (gimple_stmt_iterator *gsip,
> bool full_walk)
> }
>
> if (dest == NULL_TREE)
> - return false;
> + return;
>
> if (len == NULL_TREE)
> len = (TREE_CODE (dest) == COMPONENT_REF
> @@ -1370,13 +1367,13 @@ optimize_aggr_zeroprop (gimple_stmt_iterator *gsip,
> bool full_walk)
> : TYPE_SIZE_UNIT (TREE_TYPE (dest)));
> if (len == NULL_TREE
> || !poly_int_tree_p (len))
> - return false;
> + return;
>
> /* This store needs to be on the byte boundary and pointing to an object.
> */
> poly_int64 offset;
> tree dest_base = get_addr_base_and_unit_offset (dest, &offset);
> if (dest_base == NULL_TREE)
> - return false;
> + return;
>
> /* Setup the worklist. */
> auto_vec<std::pair<tree, unsigned>> worklist;
> @@ -1409,13 +1406,11 @@ optimize_aggr_zeroprop (gimple_stmt_iterator *gsip,
> bool full_walk)
> new_limit));
> }
>
> - if (optimize_aggr_zeroprop_1 (stmt, use_stmt, dest_base, offset,
> - val, wi::to_poly_offset (len)))
> - changed = true;
> + optimize_aggr_zeroprop_1 (stmt, use_stmt, dest_base, offset,
> + val, wi::to_poly_offset (len));
> }
> }
>
> - return changed;
> }
>
> /* Returns the pointer to the base of the object of the
> @@ -1591,22 +1586,22 @@ same_for_assignment (tree src, tree dest)
> /* 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
> +static void
> 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;
> + return;
> 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 (same_for_assignment (src2, dest2))
> - return false;
> + return;
> src = new_src_based_on_copy (src2, dest, src);
> if (!src)
> - return false;
> + return;
> /* 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,7 +1629,7 @@ optimize_agr_copyprop_1 (gimple *stmt, gimple *use_stmt,
> tree len = TYPE_SIZE_UNIT (TREE_TYPE (src));
> if (len == NULL_TREE
> || !tree_fits_poly_int64_p (len))
> - return false;
> + return;
> tree base1 = get_addr_base_and_unit_offset (dest2, &offset1);
> tree base2 = get_addr_base_and_unit_offset (src, &offset2);
> poly_int64 size = tree_to_poly_int64 (len);
> @@ -1659,14 +1654,14 @@ optimize_agr_copyprop_1 (gimple *stmt, gimple
> *use_stmt,
> of overlapping. */
> if (maybe_lt (align1, size)
> || maybe_lt (align2, size))
> - return false;
> + return;
> }
> /* Make sure [offset1, offset1 + len - 1] does
> not overlap with [offset2, offset2 + len - 1],
> it is ok if they are at the same location though. */
> else if (ranges_maybe_overlap_p (offset1, size, offset2, size)
> && !known_eq (offset2, offset1))
> - return false;
> + return;
> }
>
> if (dump_file && (dump_flags & TDF_DETAILS))
> @@ -1689,13 +1684,12 @@ optimize_agr_copyprop_1 (gimple *stmt, gimple
> *use_stmt,
> 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
> +static void
> optimize_agr_copyprop_arg (gimple *defstmt, gcall *call,
> tree dest, tree src)
> {
> @@ -1728,7 +1722,6 @@ optimize_agr_copyprop_arg (gimple *defstmt, gcall *call,
> }
> if (changed)
> update_stmt (call);
> - return changed;
> }
>
> /* Optimizes
> @@ -1748,39 +1741,34 @@ optimize_agr_copyprop_arg (gimple *defstmt, gcall
> *call,
> call_func(..., SRC, ...);
>
> */
> -static bool
> +static void
> optimize_agr_copyprop (gimple_stmt_iterator *gsip)
> {
> gimple *stmt = gsi_stmt (*gsip);
> if (gimple_has_volatile_ops (stmt))
> - return false;
> + return;
>
> /* Can't prop if the statement could throw. */
> if (stmt_could_throw_p (cfun, stmt))
> - return false;
> + return;
>
> tree dest = gimple_assign_lhs (stmt);
> tree src = gimple_assign_rhs1 (stmt);
> /* If the statement is `src = src;` then ignore it. */
> if (same_for_assignment (dest, src))
> - return false;
> + return;
>
> tree vdef = gimple_vdef (stmt);
> imm_use_iterator iter;
> gimple *use_stmt;
> - bool changed = false;
> FOR_EACH_IMM_USE_STMT (use_stmt, iter, vdef)
> {
> 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;
> + && gimple_store_p (use_stmt))
> + optimize_agr_copyprop_1 (stmt, use_stmt, dest, src);
> + else if (is_gimple_call (use_stmt))
> + optimize_agr_copyprop_arg (stmt, as_a<gcall*>(use_stmt), dest, src);
> }
> - return changed;
> }
>
> /* Optimizes builtin memcmps for small constant sizes.
> @@ -2180,8 +2168,7 @@ simplify_builtin_call (gimple_stmt_iterator *gsi_p,
> tree callee2, bool full_walk
> {
> /* Try to prop the zeroing/value of the memset to memcpy
> if the dest is an address and the value is a constant. */
> - if (optimize_aggr_zeroprop (gsi_p, full_walk))
> - return true;
> + optimize_aggr_zeroprop (gsi_p, full_walk);
> }
> return simplify_builtin_memcpy_memset (gsi_p, as_a<gcall*>(stmt2));
>
> @@ -5323,17 +5310,10 @@ pass_forwprop::execute (function *fun)
> {
> tree rhs1 = gimple_assign_rhs1 (stmt);
> enum tree_code code = gimple_assign_rhs_code (stmt);
> - if (gimple_store_p (stmt) && optimize_aggr_zeroprop
> (&gsi, full_walk))
> - {
> - changed = true;
> - break;
> - }
> - if (gimple_assign_load_p (stmt) && gimple_store_p (stmt)
> - && optimize_agr_copyprop (&gsi))
> - {
> - changed = true;
> - break;
> - }
> + if (gimple_store_p (stmt))
> + optimize_aggr_zeroprop (&gsi, full_walk);
> + if (gimple_assign_load_p (stmt) && gimple_store_p (stmt))
> + optimize_agr_copyprop (&gsi);
It looks to me that we can do
if (gimple_store_p (stmt))
{
optimize_aggr_zeroprop (&gsi, full_walk);
// does this ever leave us with a non-store
'stmt'? need to do stmt = gsi_stmt (gsi)?
if (gimple_assign_load_p (stmt))
optimize_agr_copyprop (&gsi);
}
else if (TREE_CODE_CLASS (code) == tcc_comparison)
...
? We only handle loads (ARRAY_REF) below.
OK with such change.
Richard.
> if (TREE_CODE_CLASS (code) == tcc_comparison)
> changed |= forward_propagate_into_comparison (&gsi);
> --
> 2.43.0
>