Patchwork [4.7,branch] Backport fix for 54985

login
register
mail settings
Submitter Jeff Law
Date Nov. 2, 2012, 8:18 p.m.
Message ID <50942AA4.40109@redhat.com>
Download mbox | patch
Permalink /patch/196755/
State New
Headers show

Comments

Jeff Law - Nov. 2, 2012, 8:18 p.m.
Just backporting the fix for 54985 from the trunk to gcc-4_7-branch. 
Bootstrapped and regression tested on x86_64-unknown-linux-gnu.
2012-11-02  Jeff Law  <law@redhat.com>

	PR tree-optimization/54985
	* tree-ssa-threadedge.c (cond_arg_set_in_bb): New function extracted
	from thread_across_edge.
	(thread_across_edge): Use it in all cases where we might thread
	across a back edge.

	* gcc.c-torture/execute/pr54985.c: New test.

Patch

Index: gcc/testsuite/gcc.c-torture/execute/pr54985.c
===================================================================
--- gcc/testsuite/gcc.c-torture/execute/pr54985.c	(revision 0)
+++ gcc/testsuite/gcc.c-torture/execute/pr54985.c	(working copy)
@@ -0,0 +1,36 @@ 
+
+typedef struct st {
+    int a;
+} ST;
+
+int __attribute__((noinline,noclone))
+foo(ST *s, int c)
+{
+  int first = 1;
+  int count = c;
+  ST *item = s;
+  int a = s->a;
+  int x;
+
+  while (count--)
+    {
+      x = item->a;
+      if (first)
+        first = 0;
+      else if (x >= a)
+        return 1;
+      a = x;
+      item++;
+    }
+  return 0;
+}
+
+extern void abort (void);
+
+int main ()
+{
+  ST _1[2] = {{2}, {1}};
+  if (foo(_1, 2) != 0)
+    abort ();
+  return 0;
+}
Index: gcc/tree-ssa-threadedge.c
===================================================================
--- gcc/tree-ssa-threadedge.c	(revision 193086)
+++ gcc/tree-ssa-threadedge.c	(working copy)
@@ -574,6 +574,44 @@ 
   return cached_lhs;
 }
 
+/* Return TRUE if the statement at the end of e->dest depends on
+   the output of any statement in BB.   Otherwise return FALSE.
+
+   This is used when we are threading a backedge and need to ensure
+   that temporary equivalences from BB do not affect the condition
+   in e->dest.  */
+
+static bool
+cond_arg_set_in_bb (edge e, basic_block bb)
+{
+  ssa_op_iter iter;
+  use_operand_p use_p;
+  gimple last = last_stmt (e->dest);
+
+  /* E->dest does not have to end with a control transferring
+     instruction.  This can occurr when we try to extend a jump
+     threading opportunity deeper into the CFG.  In that case
+     it is safe for this check to return false.  */
+  if (!last)
+    return false;
+
+  if (gimple_code (last) != GIMPLE_COND
+      && gimple_code (last) != GIMPLE_GOTO
+      && gimple_code (last) != GIMPLE_SWITCH)
+    return false;
+
+  FOR_EACH_SSA_USE_OPERAND (use_p, last, iter, SSA_OP_USE | SSA_OP_VUSE)
+    {
+      tree use = USE_FROM_PTR (use_p);
+
+      if (TREE_CODE (use) == SSA_NAME
+	  && gimple_code (SSA_NAME_DEF_STMT (use)) != GIMPLE_PHI
+	  && gimple_bb (SSA_NAME_DEF_STMT (use)) == bb)
+	return true;
+    }
+  return false;
+}
+
 /* TAKEN_EDGE represents the an edge taken as a result of jump threading.
    See if we can thread around TAKEN_EDGE->dest as well.  If so, return
    the edge out of TAKEN_EDGE->dest that we can statically compute will be
@@ -707,19 +745,8 @@ 
      safe to thread this edge.  */
   if (e->flags & EDGE_DFS_BACK)
     {
-      ssa_op_iter iter;
-      use_operand_p use_p;
-      gimple last = gsi_stmt (gsi_last_bb (e->dest));
-
-      FOR_EACH_SSA_USE_OPERAND (use_p, last, iter, SSA_OP_USE | SSA_OP_VUSE)
-	{
-	  tree use = USE_FROM_PTR (use_p);
-
-          if (TREE_CODE (use) == SSA_NAME
-	      && gimple_code (SSA_NAME_DEF_STMT (use)) != GIMPLE_PHI
-	      && gimple_bb (SSA_NAME_DEF_STMT (use)) == e->dest)
-	    goto fail;
-	}
+      if (cond_arg_set_in_bb (e, e->dest))
+	goto fail;
     }
 
   stmt_count = 0;
@@ -760,7 +787,9 @@ 
 	     address.  If DEST is not null, then see if we can thread
 	     through it as well, this helps capture secondary effects
 	     of threading without having to re-run DOM or VRP.  */
-	  if (dest)
+	  if (dest
+	      && ((e->flags & EDGE_DFS_BACK) == 0
+		  || ! cond_arg_set_in_bb (taken_edge, e->dest)))
 	    {
 	      /* We don't want to thread back to a block we have already
  		 visited.  This may be overly conservative.  */
@@ -818,11 +847,16 @@ 
 	e3 = taken_edge;
 	do
 	  {
-	    e2 = thread_around_empty_block (e3,
-				            dummy_cond,
-				            handle_dominating_asserts,
-				            simplify,
-				            visited);
+	    if ((e->flags & EDGE_DFS_BACK) == 0
+		|| ! cond_arg_set_in_bb (e3, e->dest))
+	      e2 = thread_around_empty_block (e3,
+					      dummy_cond,
+					      handle_dominating_asserts,
+					      simplify,
+					      visited);
+	    else
+	      e2 = NULL;
+
 	    if (e2)
 	      {
 	        e3 = e2;