OSDN Git Service

PR target/50617
[pf3gnuchains/gcc-fork.git] / gcc / tree-ssa-threadedge.c
index 1fee9bf..707c8df 100644 (file)
@@ -1,5 +1,5 @@
 /* SSA Jump Threading
-   Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010
+   Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011
    Free Software Foundation, Inc.
    Contributed by Jeff Law  <law@redhat.com>
 
@@ -225,24 +225,7 @@ fold_assignment_stmt (gimple stmt)
   switch (get_gimple_rhs_class (subcode))
     {
     case GIMPLE_SINGLE_RHS:
-      {
-        tree rhs = gimple_assign_rhs1 (stmt);
-
-        if (TREE_CODE (rhs) == COND_EXPR)
-          {
-            /* Sadly, we have to handle conditional assignments specially
-               here, because fold expects all the operands of an expression
-               to be folded before the expression itself is folded, but we
-               can't just substitute the folded condition here.  */
-            tree cond = fold (COND_EXPR_COND (rhs));
-            if (cond == boolean_true_node)
-              rhs = COND_EXPR_THEN (rhs);
-            else if (cond == boolean_false_node)
-              rhs = COND_EXPR_ELSE (rhs);
-          }
-
-        return fold (rhs);
-      }
+      return fold (gimple_assign_rhs1 (stmt));
 
     case GIMPLE_UNARY_RHS:
       {
@@ -265,6 +248,14 @@ fold_assignment_stmt (gimple stmt)
         tree op0 = gimple_assign_rhs1 (stmt);
         tree op1 = gimple_assign_rhs2 (stmt);
         tree op2 = gimple_assign_rhs3 (stmt);
+
+       /* Sadly, we have to handle conditional assignments specially
+          here, because fold expects all the operands of an expression
+          to be folded before the expression itself is folded, but we
+          can't just substitute the folded condition here.  */
+        if (gimple_assign_rhs_code (stmt) == COND_EXPR)
+         op0 = fold (op0);
+
         return fold_ternary (subcode, TREE_TYPE (lhs), op0, op1, op2);
       }
 
@@ -652,6 +643,27 @@ thread_around_empty_block (edge taken_edge,
   return NULL;
 }
       
+/* E1 and E2 are edges into the same basic block.  Return TRUE if the
+   PHI arguments associated with those edges are equal or there are no
+   PHI arguments, otherwise return FALSE.  */
+
+static bool
+phi_args_equal_on_edges (edge e1, edge e2)
+{
+  gimple_stmt_iterator gsi;
+  int indx1 = e1->dest_idx;
+  int indx2 = e2->dest_idx;
+
+  for (gsi = gsi_start_phis (e1->dest); !gsi_end_p (gsi); gsi_next (&gsi))
+    {
+      gimple phi = gsi_stmt (gsi);
+
+      if (!operand_equal_p (gimple_phi_arg_def (phi, indx1),
+                           gimple_phi_arg_def (phi, indx2), 0))
+       return false;
+    }
+  return true;
+}
 
 /* We are exiting E->src, see if E->dest ends with a conditional
    jump which has a known value when reached via E.
@@ -770,10 +782,73 @@ thread_across_edge (gimple dummy_cond,
            }
 
          remove_temporary_equivalences (stack);
-         register_jump_thread (e, taken_edge);
+         register_jump_thread (e, taken_edge, NULL);
+         return;
        }
     }
 
+ /* We were unable to determine what out edge from E->dest is taken.  However,
+    we might still be able to thread through successors of E->dest.  This
+    often occurs when E->dest is a joiner block which then fans back out
+    based on redundant tests.
+
+    If so, we'll copy E->dest and redirect the appropriate predecessor to
+    the copy.  Within the copy of E->dest, we'll thread one or more edges
+    to points deeper in the CFG.
+
+    This is a stopgap until we have a more structured approach to path
+    isolation.  */
+  {
+    edge e2, e3, taken_edge;
+    edge_iterator ei;
+    bool found = false;
+    bitmap visited = BITMAP_ALLOC (NULL);
+
+    /* Look at each successor of E->dest to see if we can thread through it.  */
+    FOR_EACH_EDGE (taken_edge, ei, e->dest->succs)
+      {
+       /* Avoid threading to any block we have already visited.  */
+       bitmap_clear (visited);
+       bitmap_set_bit (visited, taken_edge->dest->index);
+       bitmap_set_bit (visited, e->dest->index);
+
+       /* Record whether or not we were able to thread through a successor
+          of E->dest.  */
+       found = false;
+       e3 = taken_edge;
+       do
+         {
+           e2 = thread_around_empty_block (e3,
+                                           dummy_cond,
+                                           handle_dominating_asserts,
+                                           simplify,
+                                           visited);
+           if (e2)
+             {
+               e3 = e2;
+               found = true;
+             }
+         }
+        while (e2);
+
+       /* If we were able to thread through a successor of E->dest, then
+          record the jump threading opportunity.  */
+       if (found)
+         {
+           edge tmp;
+           /* If there is already an edge from the block to be duplicated
+              (E2->src) to the final target (E3->dest), then make sure that
+              the PHI args associated with the edges E2 and E3 are the
+              same.  */
+           tmp = find_edge (taken_edge->src, e3->dest);
+           if (!tmp || phi_args_equal_on_edges (tmp, e3))
+             register_jump_thread (e, taken_edge, e3);
+         }
+
+      }
+    BITMAP_FREE (visited);
+  }
+
  fail:
   remove_temporary_equivalences (stack);
 }