OSDN Git Service

PR target/23832
[pf3gnuchains/gcc-fork.git] / gcc / tree-ssa-dom.c
index 7b79c79..b37df77 100644 (file)
@@ -166,6 +166,7 @@ struct opt_stats_d
   long num_re;
   long num_const_prop;
   long num_copy_prop;
+  long num_iterations;
 };
 
 static struct opt_stats_d opt_stats;
@@ -478,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)
        {
@@ -524,6 +529,8 @@ tree_ssa_dominator_optimize (void)
          if (value && !is_gimple_min_invariant (value))
            SSA_NAME_VALUE (name) = NULL;
        }
+
+      opt_stats.num_iterations++;
     }
   while (optimize > 1 && cfg_altered);
 
@@ -659,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);
 
@@ -698,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;
@@ -722,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;
@@ -845,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
@@ -884,7 +908,7 @@ dom_opt_initialize_block (struct dom_walk_data *walk_data ATTRIBUTE_UNUSED,
 }
 
 /* Given an expression EXPR (a relational expression or a statement), 
-   initialize the hash table element pointed by by ELEMENT.  */
+   initialize the hash table element pointed to by ELEMENT.  */
 
 static void
 initialize_hash_element (tree expr, tree lhs, struct expr_hash_elt *element)
@@ -996,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));
@@ -1020,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;
@@ -1070,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;
@@ -1356,6 +1378,9 @@ dump_dominator_optimization_stats (FILE *file)
   fprintf (file, "    Copies propagated:                        %6ld\n",
           opt_stats.num_copy_prop);
 
+  fprintf (file, "\nTotal number of DOM iterations:             %6ld\n",
+          opt_stats.num_iterations);
+
   fprintf (file, "\nHash table statistics:\n");
 
   fprintf (file, "    avail_exprs: ");
@@ -2851,7 +2876,7 @@ cprop_into_stmt (tree stmt)
 }
 
 
-/* Optimize the statement pointed by iterator SI.
+/* Optimize the statement pointed to by iterator SI.
    
    We try to perform some simplistic global redundancy elimination and
    constant propagation:
@@ -3061,7 +3086,7 @@ update_rhs_and_lookup_avail_expr (tree stmt, tree new_rhs, bool insert)
    NULL_TREE.
 
    Also, when an expression is first inserted in the AVAIL_EXPRS table, it
-   is also added to the stack pointed by BLOCK_AVAIL_EXPRS_P, so that they
+   is also added to the stack pointed to by BLOCK_AVAIL_EXPRS_P, so that they
    can be removed when we finish processing this block and its children.
 
    NOTE: This function assumes that STMT is a MODIFY_EXPR node that