OSDN Git Service

PR target/23832
[pf3gnuchains/gcc-fork.git] / gcc / tree-ssa-dom.c
index 1a59e9e..b37df77 100644 (file)
@@ -479,7 +479,11 @@ tree_ssa_dominator_optimize (void)
       if (cfg_altered)
         free_dominance_info (CDI_DOMINATORS);
 
-      cfg_altered = cleanup_tree_cfg ();
+      /* Only iterate if we threaded jumps AND the CFG cleanup did
+        something interesting.  Other cases generate far fewer
+        optimization opportunities and thus are not worth another
+        full DOM iteration.  */
+      cfg_altered &= cleanup_tree_cfg ();
 
       if (rediscover_loops_after_threading)
        {
@@ -662,7 +666,7 @@ thread_across_edge (struct dom_walk_data *walk_data, edge e)
      statements.  This does not prevent threading through E->dest.  */
   for (bsi = bsi_start (e->dest); ! bsi_end_p (bsi); bsi_next (&bsi))
     {
-      tree cached_lhs;
+      tree cached_lhs = NULL;
 
       stmt = bsi_stmt (bsi);
 
@@ -701,7 +705,7 @@ thread_across_edge (struct dom_walk_data *walk_data, edge e)
       else
        {
          /* Copy the operands.  */
-         tree *copy;
+         tree *copy, pre_fold_expr;
          ssa_op_iter iter;
          use_operand_p use_p;
          unsigned int num, i = 0;
@@ -725,12 +729,31 @@ thread_across_edge (struct dom_walk_data *walk_data, edge e)
 
          /* Try to fold/lookup the new expression.  Inserting the
             expression into the hash table is unlikely to help
-            simplify anything later, so just query the hashtable.  */
-         cached_lhs = fold (TREE_OPERAND (stmt, 1));
-         if (TREE_CODE (cached_lhs) != SSA_NAME
-             && !is_gimple_min_invariant (cached_lhs))
-           cached_lhs = lookup_avail_expr (stmt, false);
+            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 (TREE_CODE (TREE_OPERAND (stmt, 1)) == COND_EXPR)
+           {
+             tree cond = COND_EXPR_COND (TREE_OPERAND (stmt, 1));
+             cond = fold (cond);
+             if (cond == boolean_true_node)
+               pre_fold_expr = COND_EXPR_THEN (TREE_OPERAND (stmt, 1));
+             else if (cond == boolean_false_node)
+               pre_fold_expr = COND_EXPR_ELSE (TREE_OPERAND (stmt, 1));
+             else
+               pre_fold_expr = TREE_OPERAND (stmt, 1);
+           }
+         else
+           pre_fold_expr = TREE_OPERAND (stmt, 1);
 
+         if (pre_fold_expr)
+           {
+             cached_lhs = fold (pre_fold_expr);
+             if (TREE_CODE (cached_lhs) != SSA_NAME
+                 && !is_gimple_min_invariant (cached_lhs))
+               cached_lhs = lookup_avail_expr (stmt, false);
+           }
 
          /* Restore the statement's original uses/defs.  */
          i = 0;
@@ -848,8 +871,6 @@ thread_across_edge (struct dom_walk_data *walk_data, edge e)
            {
              struct edge_info *edge_info;
 
-             update_bb_profile_for_threading (e->dest, EDGE_FREQUENCY (e),
-                                              e->count, taken_edge);
              if (e->aux)
                edge_info = e->aux;
              else
@@ -999,14 +1020,14 @@ dom_opt_finalize_block (struct dom_walk_data *walk_data, basic_block bb)
 {
   tree last;
 
-  /* If we are at a leaf node in the dominator tree, see if we can thread
-     the edge from BB through its successor.
-
-     Do this before we remove entries from our equivalence tables.  */
+  /* If we have an outgoing edge to a block with multiple incoming and
+     outgoing edges, then we may be able to thread the edge.  ie, we
+     may be able to statically determine which of the outgoing edges
+     will be traversed when the incoming edge from BB is traversed.  */
   if (single_succ_p (bb)
       && (single_succ_edge (bb)->flags & EDGE_ABNORMAL) == 0
-      && (get_immediate_dominator (CDI_DOMINATORS, single_succ (bb)) != bb
-         || phi_nodes (single_succ (bb))))
+      && !single_pred_p (single_succ (bb))
+      && !single_succ_p (single_succ (bb)))
        
     {
       thread_across_edge (walk_data, single_succ_edge (bb));
@@ -1023,10 +1044,9 @@ dom_opt_finalize_block (struct dom_walk_data *walk_data, basic_block bb)
 
       extract_true_false_edges_from_block (bb, &true_edge, &false_edge);
 
-      /* If the THEN arm is the end of a dominator tree or has PHI nodes,
-        then try to thread through its edge.  */
-      if (get_immediate_dominator (CDI_DOMINATORS, true_edge->dest) != bb
-         || phi_nodes (true_edge->dest))
+      /* Only try to thread the edge if it reaches a target block with
+        more than one predecessor and more than one successor.  */
+      if (!single_pred_p (true_edge->dest) && !single_succ_p (true_edge->dest))
        {
          struct edge_info *edge_info;
          unsigned int i;
@@ -1073,8 +1093,7 @@ dom_opt_finalize_block (struct dom_walk_data *walk_data, basic_block bb)
        }
 
       /* Similarly for the ELSE arm.  */
-      if (get_immediate_dominator (CDI_DOMINATORS, false_edge->dest) != bb
-         || phi_nodes (false_edge->dest))
+      if (!single_pred_p (false_edge->dest) && !single_succ_p (false_edge->dest))
        {
          struct edge_info *edge_info;
          unsigned int i;