public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] tree-optimization/106754 - fix compute_control_dep_chain defect
@ 2022-09-06 12:55 Richard Biener
  0 siblings, 0 replies; only message in thread
From: Richard Biener @ 2022-09-06 12:55 UTC (permalink / raw)
  To: gcc-patches

The following handles the situation of a loop exit along the
control path to the PHI def or from there to the use in a different
way, aoviding premature abort of the walks as noticed in the two
cases where the exit is outermost (gcc.dg/uninit-pred-11.c) or
wrapped in a condition that is on the path (gcc.dg/uninit-pred-12.c).
Instead of handling such exits during recursion we now pick them
up in the parent when walking post-dominators.  That requires an
additional post-dominator walk at the outermost level which is
facilitated by splitting out the walk to a helper function and
the existing wrapper added earlier.

The patch also removes the bogus early exit from
uninit_analysis::init_use_preds, fixing a simplified version
of the PR106155 testcase.

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

	PR tree-optimization/106754
	* gimple-predicate-analysis.cc (compute_control_dep_chain_pdom):
	New function, split out from compute_control_dep_chain.  Handle
	loop-exit like conditions here by pushing to the control vector.
	(compute_control_dep_chain): Adjust and streamline dumping.
	In the wrapper perform a post-dominator walk as well.
	(uninit_analysis::init_use_preds): Remove premature early exit.

	* gcc.dg/uninit-pred-12.c: New testcase.
	* gcc.dg/uninit-pr106155-1.c: Likewise.
---
 gcc/gimple-predicate-analysis.cc         | 186 +++++++++++++----------
 gcc/testsuite/gcc.dg/uninit-pr106155-1.c |  40 +++++
 gcc/testsuite/gcc.dg/uninit-pred-12.c    |  34 +++++
 3 files changed, 180 insertions(+), 80 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/uninit-pr106155-1.c
 create mode 100644 gcc/testsuite/gcc.dg/uninit-pred-12.c

diff --git a/gcc/gimple-predicate-analysis.cc b/gcc/gimple-predicate-analysis.cc
index ac34b7007a6..5dade458947 100644
--- a/gcc/gimple-predicate-analysis.cc
+++ b/gcc/gimple-predicate-analysis.cc
@@ -981,6 +981,94 @@ dfs_mark_dominating_region (edge exit, basic_block dom, int flag,
   return true;
 }
 
+static bool
+compute_control_dep_chain (basic_block dom_bb, const_basic_block dep_bb,
+			   vec<edge> cd_chains[], unsigned *num_chains,
+			   vec<edge> &cur_cd_chain, unsigned *num_calls,
+			   unsigned in_region, unsigned depth,
+			   bool *complete_p);
+
+/* Helper for compute_control_dep_chain that walks the post-dominator
+   chain from CD_BB up unto TARGET_BB looking for paths to DEP_BB.  */
+
+static bool
+compute_control_dep_chain_pdom (basic_block cd_bb, const_basic_block dep_bb,
+				basic_block target_bb,
+				vec<edge> cd_chains[], unsigned *num_chains,
+				vec<edge> &cur_cd_chain, unsigned *num_calls,
+				unsigned in_region, unsigned depth,
+				bool *complete_p)
+{
+  bool found_cd_chain = false;
+  while (cd_bb != target_bb)
+    {
+      if (cd_bb == dep_bb)
+	{
+	  /* Found a direct control dependence.  */
+	  if (*num_chains < MAX_NUM_CHAINS)
+	    {
+	      if (DEBUG_PREDICATE_ANALYZER && dump_file)
+		fprintf (dump_file, "%*s pushing { %s }\n",
+			 depth, "", format_edge_vec (cur_cd_chain).c_str ());
+	      cd_chains[*num_chains] = cur_cd_chain.copy ();
+	      (*num_chains)++;
+	    }
+	  found_cd_chain = true;
+	  /* Check path from next edge.  */
+	  break;
+	}
+
+      /* If the dominating region has been marked avoid walking outside.  */
+      if (in_region != 0 && !(cd_bb->flags & in_region))
+	break;
+
+      /* Count the number of steps we perform to limit compile-time.
+	 This should cover both recursion and the post-dominator walk.  */
+      if (*num_calls > (unsigned)param_uninit_control_dep_attempts)
+	{
+	  if (dump_file)
+	    fprintf (dump_file, "param_uninit_control_dep_attempts "
+		     "exceeded: %u\n", *num_calls);
+	  *complete_p = false;
+	  break;
+	}
+      ++*num_calls;
+
+      /* Check if DEP_BB is indirectly control-dependent on DOM_BB.  */
+      if (!single_succ_p (cd_bb)
+	  && compute_control_dep_chain (cd_bb, dep_bb, cd_chains,
+					num_chains, cur_cd_chain,
+					num_calls, in_region, depth + 1,
+					complete_p))
+	{
+	  found_cd_chain = true;
+	  break;
+	}
+
+      /* The post-dominator walk will reach a backedge only
+	 from a forwarder, otherwise it should choose to exit
+	 the SCC.  */
+      if (single_succ_p (cd_bb)
+	  && single_succ_edge (cd_bb)->flags & EDGE_DFS_BACK)
+	break;
+      basic_block prev_cd_bb = cd_bb;
+      cd_bb = get_immediate_dominator (CDI_POST_DOMINATORS, cd_bb);
+      if (cd_bb == EXIT_BLOCK_PTR_FOR_FN (cfun))
+	break;
+      /* Pick up conditions toward the post dominator such like
+	 loop exit conditions.  See gcc.dg/uninit-pred-11.c and
+	 gcc.dg/unninit-pred-12.c and PR106754.  */
+      if (single_pred_p (cd_bb))
+	{
+	  edge e2 = find_edge (prev_cd_bb, cd_bb);
+	  gcc_assert (e2);
+	  cur_cd_chain.safe_push (e2);
+	}
+    }
+  return found_cd_chain;
+}
+
+
 /* Recursively compute the control dependence chains (paths of edges)
    from the dependent basic block, DEP_BB, up to the dominating basic
    block, DOM_BB (the head node of a chain should be dominated by it),
@@ -1024,9 +1112,10 @@ compute_control_dep_chain (basic_block dom_bb, const_basic_block dep_bb,
 
   if (DEBUG_PREDICATE_ANALYZER && dump_file)
     fprintf (dump_file,
-	     "%*s%s (dom_bb = %u, dep_bb = %u, cd_chains = { %s }, ...)\n",
+	     "%*s%s (dom_bb = %u, dep_bb = %u, ..., "
+	     "cur_cd_chain = { %s }, ...)\n",
 	     depth, "", __func__, dom_bb->index, dep_bb->index,
-	     format_edge_vecs (cd_chains, *num_chains).c_str ());
+	     format_edge_vec (cur_cd_chain).c_str ());
 
   bool found_cd_chain = false;
 
@@ -1039,75 +1128,17 @@ compute_control_dep_chain (basic_block dom_bb, const_basic_block dep_bb,
 	continue;
 
       basic_block cd_bb = e->dest;
+      unsigned pop_mark = cur_cd_chain.length ();
       cur_cd_chain.safe_push (e);
-      while (!dominated_by_p (CDI_POST_DOMINATORS, dom_bb, cd_bb)
-	     /* We want to stop when the CFG merges back from the
-		branch in dom_bb.  The post-dominance check alone
-		falls foul of the case of a loop exit test branch
-		where the path on the loop exit post-dominates
-		the branch block.
-		The following catches this but will not allow
-		exploring the post-dom path further.  For the
-		outermost recursion this means we will fail to
-		reach dep_bb while for others it means at least
-		dropping the loop exit predicate from the path
-		which is problematic as it increases the domain
-		spanned by the resulting predicate.
-		See gcc.dg/uninit-pred-11.c for the first case
-		and PR106754 for the second.  */
-	     || single_pred_p (cd_bb))
-	{
-	  if (cd_bb == dep_bb)
-	    {
-	      /* Found a direct control dependence.  */
-	      if (*num_chains < MAX_NUM_CHAINS)
-		{
-		  cd_chains[*num_chains] = cur_cd_chain.copy ();
-		  (*num_chains)++;
-		}
-	      found_cd_chain = true;
-	      /* Check path from next edge.  */
-	      break;
-	    }
-
-	  /* If the dominating region has been marked avoid walking outside.  */
-	  if (in_region != 0 && !(cd_bb->flags & in_region))
-	    break;
-
-	  /* Count the number of steps we perform to limit compile-time.
-	     This should cover both recursion and the post-dominator walk.  */
-	  if (*num_calls > (unsigned)param_uninit_control_dep_attempts)
-	    {
-	      if (dump_file)
-		fprintf (dump_file, "param_uninit_control_dep_attempts "
-			 "exceeded: %u\n", *num_calls);
-	      *complete_p = false;
-	      break;
-	    }
-	  ++*num_calls;
-
-	  /* Check if DEP_BB is indirectly control-dependent on DOM_BB.  */
-	  if (!single_succ_p (cd_bb)
-	      && compute_control_dep_chain (cd_bb, dep_bb, cd_chains,
-					    num_chains, cur_cd_chain,
-					    num_calls, in_region, depth + 1,
-					    complete_p))
-	    {
-	      found_cd_chain = true;
-	      break;
-	    }
-
-	  /* The post-dominator walk will reach a backedge only
-	     from a forwarder, otherwise it should choose to exit
-	     the SCC.  */
-	  if (single_succ_p (cd_bb)
-	      && single_succ_edge (cd_bb)->flags & EDGE_DFS_BACK)
-	    break;
-	  cd_bb = get_immediate_dominator (CDI_POST_DOMINATORS, cd_bb);
-	  if (cd_bb == EXIT_BLOCK_PTR_FOR_FN (cfun))
-	    break;
-	}
-      cur_cd_chain.pop ();
+      basic_block target_bb
+	= get_immediate_dominator (CDI_POST_DOMINATORS, dom_bb);
+      /* Walk the post-dominator chain up to the CFG merge.  */
+      found_cd_chain
+	  |= compute_control_dep_chain_pdom (cd_bb, dep_bb, target_bb,
+					     cd_chains, num_chains,
+					     cur_cd_chain, num_calls,
+					     in_region, depth, complete_p);
+      cur_cd_chain.truncate (pop_mark);
       gcc_assert (cur_cd_chain.length () == cur_chain_len);
     }
 
@@ -1127,9 +1158,10 @@ compute_control_dep_chain (basic_block dom_bb, const_basic_block dep_bb,
   unsigned num_calls = 0;
   unsigned depth = 0;
   bool complete_p = true;
-  compute_control_dep_chain (dom_bb, dep_bb, cd_chains, num_chains,
-			     cur_cd_chain, &num_calls, in_region, depth,
-			     &complete_p);
+  /* Walk the post-dominator chain.  */
+  compute_control_dep_chain_pdom (dom_bb, dep_bb, NULL, cd_chains,
+				  num_chains, cur_cd_chain, &num_calls,
+				  in_region, depth, &complete_p);
   return complete_p;
 }
 
@@ -1935,9 +1967,7 @@ uninit_analysis::init_use_preds (predicate &use_preds, basic_block def_bb,
   unsigned num_chains = 0;
   auto_vec<edge> dep_chains[MAX_NUM_CHAINS];
 
-  if (!compute_control_dep_chain (cd_root, use_bb, dep_chains, &num_chains)
-      /* ???  Workaround PR106754.  */
-      || num_chains == 0)
+  if (!compute_control_dep_chain (cd_root, use_bb, dep_chains, &num_chains))
     {
       /* If the info in dep_chains is not complete we need to use a
 	 conservative approximation for the use predicate.  */
@@ -2099,10 +2129,6 @@ uninit_analysis::is_use_guarded (gimple *use_stmt, basic_block use_bb,
   /* The basic block where the PHI is defined.  */
   basic_block def_bb = gimple_bb (phi);
 
-  if (dominated_by_p (CDI_POST_DOMINATORS, def_bb, use_bb))
-    /* The use is not guarded.  */
-    return false;
-
   /* Try to build the predicate expression under which the PHI flows
      into its use.  This will be empty if the PHI is defined and used
      in the same bb.  */
diff --git a/gcc/testsuite/gcc.dg/uninit-pr106155-1.c b/gcc/testsuite/gcc.dg/uninit-pr106155-1.c
new file mode 100644
index 00000000000..5c4410deec8
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/uninit-pr106155-1.c
@@ -0,0 +1,40 @@
+/* { dg-do compile } */
+/* { dg-options "-O -fno-ivopts -Wuninitialized" } */
+
+int *e;
+int f1 (void);
+void f2 (int);
+long f3 (void *, long, int *);
+void f4 (void *);
+int *fh;
+
+void tst (void)
+{
+  int status;
+  unsigned char badData[3][3] = { { 7 }, { 16 }, { 23 } };
+  int badDataSize[3] = { 1, 1, 1 };
+  int i;
+
+  for (i = 0; i < 3; i++)
+    {
+      int emax;
+      if (i == 2)
+        emax = f1 ();
+      status = f3 (&badData[i][0], badDataSize[i], fh);
+      if (status)
+        {
+          f1 ();
+          f1 ();
+          f1 ();
+        }
+      f4 (fh);
+      *e = 0;
+      f1 ();
+      /* When threading the following out of the loop uninit
+	 analysis needs to pick up the loop exit condition
+	 to match up with this guard.
+	 ???  This doesn't work reliably when IVOPTs is run.  */
+      if (i == 2)
+        f2 (emax);  /* { dg-bogus "uninitialized" } */
+    }
+}
diff --git a/gcc/testsuite/gcc.dg/uninit-pred-12.c b/gcc/testsuite/gcc.dg/uninit-pred-12.c
new file mode 100644
index 00000000000..ebf0288af1f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/uninit-pred-12.c
@@ -0,0 +1,34 @@
+/* { dg-do compile } */
+/* { dg-options "-O -Wmaybe-uninitialized -fdump-tree-uninit1" } */
+
+extern unsigned bar (void);
+extern void quux (void);
+int z;
+unsigned foo (unsigned v, int y, int w)
+{
+  unsigned u;
+  if (v != 1)
+    u = bar ();
+
+  // Prevent the "dom" pass from changing the CFG layout based on the inference
+  // 'if (v != 1) is false then (v != 2) is true'.  (Now it would have to
+  // duplicate the loop in order to do so, which is deemed expensive.)
+  for (int i = 0; i < 10; i++)
+    quux ();
+
+  // This variantion from uninit-pred-11.c caused compute_control_dep_chain
+  // to run into a defect, producing z != 0 && v != 1, omitting !(i<10)
+  // from the path predicate
+  if (w)
+    {
+      if (y)
+	z = 1;
+      if (v != 1)
+	return u;       /* { dg-bogus "may be used uninitialized" } */
+    }
+
+  return 0;
+}
+
+/* Make sure predicate analysis picked up the loop exit condition.  */
+/* { dg-final { scan-tree-dump "AND \\(NOT \\(ivtmp" "uninit1" } } */
-- 
2.35.3

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2022-09-06 12:55 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-09-06 12:55 [PATCH] tree-optimization/106754 - fix compute_control_dep_chain defect Richard Biener

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).