tree-optimization/110924 - fix vop liveness for noreturn const CFG parts

Message ID 20230808122353.CF6F713451@imap2.suse-dmz.suse.de
State Unresolved
Headers
Series tree-optimization/110924 - fix vop liveness for noreturn const CFG parts |

Checks

Context Check Description
snail/gcc-patch-check warning Git am fail log

Commit Message

Richard Biener Aug. 8, 2023, 12:23 p.m. UTC
  The virtual operand live problem used by sinking assumes we have
virtual uses at each end point of the CFG but as shown in the PR
this isn't true for parts for example ending in __builtin_unreachable.
The following removes the optimization made possible by this and
now requires marking backedges.

Bootstrapped and tested on x86_64-unknown-linux-gnu, pushed.

	PR tree-optimization/110924
	* tree-ssa-live.h (virtual_operand_live): Update comment.
	* tree-ssa-live.cc (virtual_operand_live::get_live_in): Remove
	optimization, look at each predecessor.
	* tree-ssa-sink.cc (pass_sink_code::execute): Mark backedges.

	* gcc.dg/torture/pr110924.c: New testcase.
---
 gcc/testsuite/gcc.dg/torture/pr110924.c | 23 ++++++++++++++++++
 gcc/tree-ssa-live.cc                    | 32 ++++++++++++++-----------
 gcc/tree-ssa-live.h                     |  3 ++-
 gcc/tree-ssa-sink.cc                    |  1 +
 4 files changed, 44 insertions(+), 15 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/torture/pr110924.c
  

Patch

diff --git a/gcc/testsuite/gcc.dg/torture/pr110924.c b/gcc/testsuite/gcc.dg/torture/pr110924.c
new file mode 100644
index 00000000000..7b395775c09
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/pr110924.c
@@ -0,0 +1,23 @@ 
+/* { dg-do compile } */
+
+int a[1], b, c, d, e, f, g;
+void h(int i, int j) {
+  int *k = 0;
+  if (*k)
+    h(0, 0);
+  g = i && d;
+}
+int main() {
+  if (c)
+    goto l;
+  if (!a)
+    while (1) {
+      f = 1;
+      while (f)
+        h(b && main(), e);
+      while (1)
+        ;
+    l:;
+    }
+  return 0;
+}
diff --git a/gcc/tree-ssa-live.cc b/gcc/tree-ssa-live.cc
index c9c2fdef0e3..61789fae67d 100644
--- a/gcc/tree-ssa-live.cc
+++ b/gcc/tree-ssa-live.cc
@@ -1676,23 +1676,27 @@  virtual_operand_live::get_live_in (basic_block bb)
   if (!liveout)
     init ();
 
-  /* Since we don't have a virtual PHI we can now pick any of the
-     incoming edges liveout value.  All returns from the function have
-     a virtual use forcing generation of virtual PHIs.  */
+  /* Since we don't have a virtual PHI and we don't know whether there's
+     a downstream virtual use (and thus PHIs are inserted where necessary)
+     we now have to check each incoming edge live-out.  */
   edge_iterator ei;
   edge e;
+  tree livein = NULL_TREE;
   FOR_EACH_EDGE (e, ei, bb->preds)
-    if (liveout[e->src->index])
-      {
-	if (EDGE_PRED (bb, 0) != e)
-	  liveout[EDGE_PRED (bb, 0)->src->index] = liveout[e->src->index];
-	return liveout[e->src->index];
-      }
-
-  /* Since virtuals are in SSA form at most the immediate dominator can
-     contain the definition of the live version.  Skipping to that deals
-     with CFG cycles as well.  */
-  return get_live_out (get_immediate_dominator (CDI_DOMINATORS, bb));
+    if (e->flags & EDGE_DFS_BACK)
+      /* We can ignore backedges since if there's a def there it would
+	 have forced a PHI in the source because it also acts as use
+	 downstream.  */
+      continue;
+    else if (!livein)
+      livein = get_live_out (e->src);
+    else if (get_live_out (e->src) != livein)
+      /* When there's no virtual use downstream this indicates a point
+	 where we'd insert a PHI merging the different live virtual
+	 operands.  */
+      return NULL_TREE;
+
+  return livein;
 }
 
 /* Compute live-out of BB.  */
diff --git a/gcc/tree-ssa-live.h b/gcc/tree-ssa-live.h
index a7604448332..d175ad7247e 100644
--- a/gcc/tree-ssa-live.h
+++ b/gcc/tree-ssa-live.h
@@ -332,7 +332,8 @@  make_live_on_entry (tree_live_info_p live, basic_block bb , int p)
 /* On-demand virtual operand global live analysis.  There is at most
    a single virtual operand live at a time, the following computes and
    caches the virtual operand live at the exit of a basic block
-   supporting related live-in and live-on-edge queries.  */
+   supporting related live-in and live-on-edge queries.  It requires
+   up-to-date marked backedges.  */
 
 class virtual_operand_live
 {
diff --git a/gcc/tree-ssa-sink.cc b/gcc/tree-ssa-sink.cc
index 6ad9d21589e..a360c5cdd6e 100644
--- a/gcc/tree-ssa-sink.cc
+++ b/gcc/tree-ssa-sink.cc
@@ -822,6 +822,7 @@  pass_sink_code::execute (function *fun)
   /* Arrange for the critical edge splitting to be undone if requested.  */
   unsigned todo = unsplit_edges ? TODO_cleanup_cfg : 0;
   connect_infinite_loops_to_exit ();
+  mark_dfs_back_edges (fun);
   memset (&sink_stats, 0, sizeof (sink_stats));
   calculate_dominance_info (CDI_DOMINATORS);