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