]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
forwprop: Fix up "nop" copies after recent changes [PR121962]
authorAndrew Pinski <andrew.pinski@oss.qualcomm.com>
Tue, 16 Sep 2025 17:55:03 +0000 (10:55 -0700)
committerAndrew Pinski <andrew.pinski@oss.qualcomm.com>
Wed, 17 Sep 2025 18:36:42 +0000 (11:36 -0700)
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 <andrew.pinski@oss.qualcomm.com>
gcc/testsuite/gcc.dg/torture/pr121962-1.c [new file with mode: 0644]
gcc/tree-ssa-forwprop.cc

diff --git a/gcc/testsuite/gcc.dg/torture/pr121962-1.c b/gcc/testsuite/gcc.dg/torture/pr121962-1.c
new file mode 100644 (file)
index 0000000..97f88ad
--- /dev/null
@@ -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;
+}
index 9d389e1b9bfcb89dfab9079233721aff93ecb457..8e886d2f705b64c2191ecf7b47a060576858a272 100644 (file)
@@ -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);