]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
tree-optimization/107876 - unswitching of switch
authorRichard Biener <rguenther@suse.de>
Mon, 28 Nov 2022 08:19:33 +0000 (09:19 +0100)
committerRichard Biener <rguenther@suse.de>
Mon, 28 Nov 2022 09:04:42 +0000 (10:04 +0100)
The following shows a missed update of dominators when unswitching
removes unreachable edges from switch stmts it unswitches.  Fixed
by wiping dominator info in that case.

PR tree-optimization/107876
* tree-ssa-loop-unswitch.cc (clean_up_after_unswitching): Wipe
dominator info if we removed an edge.

* g++.dg/tree-ssa/pr107876.C: New testcase.

gcc/testsuite/g++.dg/tree-ssa/pr107876.C [new file with mode: 0644]
gcc/tree-ssa-loop-unswitch.cc

diff --git a/gcc/testsuite/g++.dg/tree-ssa/pr107876.C b/gcc/testsuite/g++.dg/tree-ssa/pr107876.C
new file mode 100644 (file)
index 0000000..6cff2f1
--- /dev/null
@@ -0,0 +1,38 @@
+// { dg-do compile }
+// { dg-require-effective-target c++11 }
+// { dg-options "-O2 -funswitch-loops --param max-unswitch-insns=5 -fdump-tree-unswitch-details" }
+
+class X {
+public:
+  X();
+  X(const X&);
+  X(const volatile X &);
+  ~X();
+};
+
+X test17(int i) {
+  if (false) {
+  impossible:
+    if (i == 3)
+      return X();
+  }
+
+  while (true) {
+    X x;
+    if (i == 0)
+      return x;
+    if (i == 1)
+      break;
+    if (i == 2)
+      continue;
+    if (i == 3)
+      goto impossible;
+    if (i == 4)
+      __builtin_exit(1);
+    if (i == 5)
+      return x;
+  }
+  return X();
+}
+
+// { dg-final { scan-tree-dump "unswitching loop 1 on .switch. with condition: i_\[0-9\]+\\(D\\) == 2" "unswitch" } }
index 186ae953f04ec69a5b2e36c6e6057c75def7153b..e8c9bd6812a43d68c022f4f95fb6df79d6cb6dcc 100644 (file)
@@ -1631,6 +1631,7 @@ clean_up_after_unswitching (int ignored_edge_flag)
   basic_block bb;
   edge e;
   edge_iterator ei;
+  bool removed_edge = false;
 
   FOR_EACH_BB_FN (bb, cfun)
     {
@@ -1655,7 +1656,10 @@ clean_up_after_unswitching (int ignored_edge_flag)
                     to preserve its edge.  But we can remove the
                     non-default CASE sharing the edge.  */
                  if (e != default_e)
-                   remove_edge (e);
+                   {
+                     remove_edge (e);
+                     removed_edge = true;
+                   }
                }
              else
                {
@@ -1672,6 +1676,10 @@ clean_up_after_unswitching (int ignored_edge_flag)
       FOR_EACH_EDGE (e, ei, bb->succs)
        e->flags &= ~ignored_edge_flag;
     }
+
+  /* If we removed an edge we possibly have to recompute dominators.  */
+  if (removed_edge)
+    free_dominance_info (CDI_DOMINATORS);
 }
 
 /* Loop unswitching pass.  */