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  <l...@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.

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;

Reply via email to