]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
tree-optimization/98845 - ICE with tail-merging and DCE/DSE disabled
authorRichard Biener <rguenther@suse.de>
Mon, 17 Feb 2025 14:53:11 +0000 (15:53 +0100)
committerRichard Biener <rguenth@gcc.gnu.org>
Mon, 26 May 2025 09:44:51 +0000 (11:44 +0200)
The following shows that tail-merging will make dead SSA defs live
in paths where it wasn't before, possibly introducing UB or as
in this case, uses of abnormals that eventually fail coalescing
later.  The fix is to register such defs for stmt comparison.

PR tree-optimization/98845
* tree-ssa-tail-merge.cc (stmt_local_def): Consider a
def with no uses not local.

* gcc.dg/pr98845.c: New testcase.
* gcc.dg/pr81192.c: Adjust.

(cherry picked from commit 6b8a8c9fd68c5dabaec5ddbc25efeade44f37a14)

gcc/testsuite/gcc.dg/pr81192.c
gcc/testsuite/gcc.dg/pr98845.c [new file with mode: 0644]
gcc/tree-ssa-tail-merge.cc

index 6cab605655853ba5ed4e1efeff525b11df81dc5f..87a7a7a19c80ca4c180cc5e9f501fd5b73ac6516 100644 (file)
@@ -1,5 +1,62 @@
-/* { dg-options "-Os -fdump-tree-pre-details -fdisable-tree-evrp -fno-tree-dse" } */
+/* { dg-options "-Os -fgimple -fdump-tree-pre-details -fdisable-tree-evrp -fno-tree-dse" } */
 
+#if __SIZEOF_INT__ == 2
+#define unsigned __UINT32_TYPE__
+#define int __INT32_TYPE__
+#endif
+
+unsigned a;
+int b, c;
+
+void __GIMPLE(ssa, startwith("pre")) fn2   ()
+{
+  int b_lsm6;
+  int j;
+  int c0_1;
+  int iftmp2_8;
+
+  __BB(2):
+  a = _Literal (unsigned)30;
+  c0_1 = c;
+  b_lsm6_9 = b;
+  goto __BB7;
+
+  __BB(3):
+  if (j_6(D) != _Literal (int)2147483647)
+    goto __BB4;
+  else
+    goto __BB9;
+
+  __BB(4):
+  iftmp2_8 = j_6(D) + _Literal (int)1;
+  goto __BB5;
+
+  __BB(9):
+  iftmp2_8 = j_6(D) + _Literal (int)1;
+  goto __BB5;
+
+  __BB(5):
+  b_lsm6_10 = _Literal (int)2147483647;
+  goto __BB6;
+
+  __BB(6):
+  if (c0_1 != _Literal (int) 0)
+    goto __BB3;
+  else
+    goto __BB8;
+
+  __BB(8):
+  goto __BB7;
+
+  __BB(7):
+  goto __BB6;
+
+}
+
+#if 0
+/* This used to be a C based testcase but ccp3 would now would remove
+   the setting of iftmp2_8 (in the above gimple) which would cause PRE
+   not to test what PRE was doing incorrectly. The original code is below. */
 /* Disable tree-evrp because the new version of evrp sees
 <bb 3> :
   if (j_8(D) != 2147483647)
@@ -18,14 +75,6 @@ which causes the situation being tested to dissapear before we get to PRE.  */
 
 /* Likewise disable DSE which also elides the tail merging "opportunity".  */
 
-#if __SIZEOF_INT__ == 2
-#define unsigned __UINT32_TYPE__
-#define int __INT32_TYPE__
-#endif
-
-unsigned a;
-int b, c;
-
 static int
 fn1 (int p1, int p2)
 {
@@ -41,5 +90,6 @@ fn2 (void)
     for (; c; b = fn1 (j, 1))
       ;
 }
+#endif
 
 /* { dg-final { scan-tree-dump-times "(?n)find_duplicates: <bb .*> duplicate of <bb .*>" 1 "pre" } } */
diff --git a/gcc/testsuite/gcc.dg/pr98845.c b/gcc/testsuite/gcc.dg/pr98845.c
new file mode 100644 (file)
index 0000000..074c979
--- /dev/null
@@ -0,0 +1,33 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fno-tree-dce -fno-tree-dse" } */
+
+int n;
+
+__attribute__ ((returns_twice)) void
+foo (void);
+
+void
+bar (void);
+
+void
+quux (int x)
+{
+  if (x)
+    ++x;
+  else
+    {
+      if (n)
+        {
+          x = 1;
+          foo ();
+        }
+      else
+        bar ();
+
+      if (n)
+        {
+          ++x;
+          ++n;
+        }
+    }
+}
index 33acb649d5d68dd0343f01bb1323bff77ccd92dd..a94108da9f485d1b79bc62dfdb67aae8632f576e 100644 (file)
@@ -336,10 +336,13 @@ stmt_local_def (gimple *stmt)
 
   def_bb = gimple_bb (stmt);
 
+  bool any_use = false;
   FOR_EACH_IMM_USE_FAST (use_p, iter, val)
     {
       if (is_gimple_debug (USE_STMT (use_p)))
        continue;
+
+      any_use = true;
       bb = gimple_bb (USE_STMT (use_p));
       if (bb == def_bb)
        continue;
@@ -351,6 +354,11 @@ stmt_local_def (gimple *stmt)
       return false;
     }
 
+  /* When there is no use avoid making the stmt live on other paths.
+     This can happen with DCE disabled or not done as seen in PR98845.  */
+  if (!any_use)
+    return false;
+
   return true;
 }