]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
re PR tree-optimization/54985 (dom optimization erroneous remove conditional goto.)
authorJeff Law <law@redhat.com>
Tue, 23 Oct 2012 20:33:49 +0000 (14:33 -0600)
committerJeff Law <law@gcc.gnu.org>
Tue, 23 Oct 2012 20:33:49 +0000 (14:33 -0600)
        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.

From-SVN: r192745

gcc/ChangeLog
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.c-torture/execute/pr54985.c [new file with mode: 0644]
gcc/tree-ssa-threadedge.c

index 89578c39be2cac536a25fcb3f1dbcb5c0935727b..f75665e484ce89263e1bd03a246e8cf4761c8fe5 100644 (file)
@@ -1,3 +1,11 @@
+2012-10-23  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.
+
 2012-10-23  Vladimir Makarov  <vmakarov@redhat.com>
 
        * lra-constraints.c (update_ebb_live_info): Process empty blocks.
index 79ccb547bd660b45e2bb657c8d9e8733e23b5e8b..b9bee3f32e490ab53af60ba9166725620ffe3269 100644 (file)
@@ -1,3 +1,7 @@
+2012-10-23  Jeff Law  <law@redhat.com>
+
+       * gcc.c-torture/execute/pr54985.c: New test.
+
 2012-10-23  Paul Koning  <ni1d@arrl.net>
 
        PR debug/54508
diff --git a/gcc/testsuite/gcc.c-torture/execute/pr54985.c b/gcc/testsuite/gcc.c-torture/execute/pr54985.c
new file mode 100644 (file)
index 0000000..678c9f4
--- /dev/null
@@ -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 105e3abdec3122930f21534f400acae0602e49b9..1ffacae7cb09754fdaacfaf16d9a904602ac5cef 100644 (file)
@@ -572,6 +572,44 @@ simplify_control_stmt_condition (edge e,
   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, int n)
+{
+  ssa_op_iter iter;
+  use_operand_p use_p;
+  gimple last = gsi_stmt (gsi_last_bb (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
@@ -705,19 +743,8 @@ thread_across_edge (gimple dummy_cond,
      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, 1))
+       goto fail;
     }
 
   stmt_count = 0;
@@ -758,7 +785,9 @@ thread_across_edge (gimple dummy_cond,
             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, 2)))
            {
              /* We don't want to thread back to a block we have already
                 visited.  This may be overly conservative.  */
@@ -816,11 +845,16 @@ thread_across_edge (gimple dummy_cond,
        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, 3))
+             e2 = thread_around_empty_block (e3,
+                                             dummy_cond,
+                                             handle_dominating_asserts,
+                                             simplify,
+                                             visited);
+           else
+             e2 = NULL;
+
            if (e2)
              {
                e3 = e2;