From: Andrew Pinski Date: Tue, 16 Sep 2025 17:55:03 +0000 (-0700) Subject: forwprop: Fix up "nop" copies after recent changes [PR121962] X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=a7a9f0de4fe01ee96350892066afbe5aca4bc0a6;p=thirdparty%2Fgcc.git forwprop: Fix up "nop" copies after recent changes [PR121962] 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. 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 --- 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..8e886d2f705 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 considered 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);